"""Media Source models."""
from __future__ import annotations

from abc import ABC
from dataclasses import dataclass
from typing import Any, cast

from homeassistant.components.media_player import BrowseMedia
from homeassistant.components.media_player.const import (
    MEDIA_CLASS_CHANNEL,
    MEDIA_CLASS_DIRECTORY,
    MEDIA_TYPE_CHANNEL,
    MEDIA_TYPE_CHANNELS,
)
from homeassistant.core import HomeAssistant, callback

from .const import DOMAIN, URI_SCHEME, URI_SCHEME_REGEX


@dataclass
class PlayMedia:
    """Represents a playable media."""

    url: str
    mime_type: str


class BrowseMediaSource(BrowseMedia):
    """Represent a browsable media file."""

    children: list[BrowseMediaSource | BrowseMedia] | None

    def __init__(
        self, *, domain: str | None, identifier: str | None, **kwargs: Any
    ) -> None:
        """Initialize media source browse media."""
        media_content_id = f"{URI_SCHEME}{domain or ''}"
        if identifier:
            media_content_id += f"/{identifier}"

        super().__init__(media_content_id=media_content_id, **kwargs)

        self.domain = domain
        self.identifier = identifier


@dataclass
class MediaSourceItem:
    """A parsed media item."""

    hass: HomeAssistant
    domain: str | None
    identifier: str

    async def async_browse(self) -> BrowseMediaSource:
        """Browse this item."""
        if self.domain is None:
            base = BrowseMediaSource(
                domain=None,
                identifier=None,
                media_class=MEDIA_CLASS_DIRECTORY,
                media_content_type=MEDIA_TYPE_CHANNELS,
                title="Media Sources",
                can_play=False,
                can_expand=True,
                children_media_class=MEDIA_CLASS_CHANNEL,
            )
            base.children = [
                BrowseMediaSource(
                    domain=source.domain,
                    identifier=None,
                    media_class=MEDIA_CLASS_CHANNEL,
                    media_content_type=MEDIA_TYPE_CHANNEL,
                    title=source.name,
                    can_play=False,
                    can_expand=True,
                )
                for source in self.hass.data[DOMAIN].values()
            ]
            return base

        return await self.async_media_source().async_browse_media(self)

    async def async_resolve(self) -> PlayMedia:
        """Resolve to playable item."""
        return await self.async_media_source().async_resolve_media(self)

    @callback
    def async_media_source(self) -> MediaSource:
        """Return media source that owns this item."""
        return cast(MediaSource, self.hass.data[DOMAIN][self.domain])

    @classmethod
    def from_uri(cls, hass: HomeAssistant, uri: str) -> MediaSourceItem:
        """Create an item from a uri."""
        if not (match := URI_SCHEME_REGEX.match(uri)):
            raise ValueError("Invalid media source URI")

        domain = match.group("domain")
        identifier = match.group("identifier")

        return cls(hass, domain, identifier)


class MediaSource(ABC):
    """Represents a source of media files."""

    name: str | None = None

    def __init__(self, domain: str) -> None:
        """Initialize a media source."""
        self.domain = domain
        if not self.name:
            self.name = domain

    async def async_resolve_media(self, item: MediaSourceItem) -> PlayMedia:
        """Resolve a media item to a playable item."""
        raise NotImplementedError

    async def async_browse_media(self, item: MediaSourceItem) -> BrowseMediaSource:
        """Browse media."""
        raise NotImplementedError