"""Home Assistant Cast platform."""

from __future__ import annotations

from pychromecast import Chromecast
from pychromecast.const import CAST_TYPE_CHROMECAST

from homeassistant.components.cast import DOMAIN as CAST_DOMAIN
from homeassistant.components.cast.home_assistant_cast import (
    ATTR_URL_PATH,
    ATTR_VIEW_PATH,
    NO_URL_AVAILABLE_ERROR,
    SERVICE_SHOW_VIEW,
)
from homeassistant.components.media_player import (
    BrowseError,
    BrowseMedia,
    MediaClass,
    MediaType,
)
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.network import NoURLAvailableError, get_url

from .const import DOMAIN, ConfigNotFound
from .dashboard import LovelaceConfig

DEFAULT_DASHBOARD = "_default_"


async def async_get_media_browser_root_object(
    hass: HomeAssistant, cast_type: str
) -> list[BrowseMedia]:
    """Create a root object for media browsing."""
    if cast_type != CAST_TYPE_CHROMECAST:
        return []
    return [
        BrowseMedia(
            title="Dashboards",
            media_class=MediaClass.APP,
            media_content_id="",
            media_content_type=DOMAIN,
            thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png",
            can_play=False,
            can_expand=True,
        )
    ]


async def async_browse_media(
    hass: HomeAssistant,
    media_content_type: MediaType | str,
    media_content_id: str,
    cast_type: str,
) -> BrowseMedia | None:
    """Browse media."""
    if media_content_type != DOMAIN:
        return None

    try:
        get_url(hass, require_ssl=True, prefer_external=True)
    except NoURLAvailableError as err:
        raise BrowseError(NO_URL_AVAILABLE_ERROR) from err

    # List dashboards.
    if not media_content_id:
        children = [
            BrowseMedia(
                title="Default",
                media_class=MediaClass.APP,
                media_content_id=DEFAULT_DASHBOARD,
                media_content_type=DOMAIN,
                thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png",
                can_play=True,
                can_expand=False,
            )
        ]
        for url_path in hass.data[DOMAIN]["dashboards"]:
            if url_path is None:
                continue

            info = await _get_dashboard_info(hass, url_path)
            children.append(_item_from_info(info))

        root = (await async_get_media_browser_root_object(hass, CAST_TYPE_CHROMECAST))[
            0
        ]
        root.children = children
        return root

    try:
        info = await _get_dashboard_info(hass, media_content_id)
    except ValueError as err:
        raise BrowseError(f"Dashboard {media_content_id} not found") from err

    children = []

    for view in info["views"]:
        children.append(
            BrowseMedia(
                title=view["title"],
                media_class=MediaClass.APP,
                media_content_id=f'{info["url_path"]}/{view["path"]}',
                media_content_type=DOMAIN,
                thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png",
                can_play=True,
                can_expand=False,
            )
        )

    root = _item_from_info(info)
    root.children = children
    return root


async def async_play_media(
    hass: HomeAssistant,
    cast_entity_id: str,
    chromecast: Chromecast,
    media_type: MediaType | str,
    media_id: str,
) -> bool:
    """Play media."""
    if media_type != DOMAIN:
        return False

    if "/" in media_id:
        url_path, view_path = media_id.split("/", 1)
    else:
        url_path = media_id
        try:
            info = await _get_dashboard_info(hass, media_id)
        except ValueError as err:
            raise HomeAssistantError(f"Invalid dashboard {media_id} specified") from err
        view_path = info["views"][0]["path"] if info["views"] else "0"

    data = {
        ATTR_ENTITY_ID: cast_entity_id,
        ATTR_VIEW_PATH: view_path,
    }
    if url_path != DEFAULT_DASHBOARD:
        data[ATTR_URL_PATH] = url_path

    await hass.services.async_call(
        CAST_DOMAIN,
        SERVICE_SHOW_VIEW,
        data,
        blocking=True,
    )
    return True


async def _get_dashboard_info(hass, url_path):
    """Load a dashboard and return info on views."""
    if url_path == DEFAULT_DASHBOARD:
        url_path = None
    dashboard: LovelaceConfig | None = hass.data[DOMAIN]["dashboards"].get(url_path)

    if dashboard is None:
        raise ValueError("Invalid dashboard specified")

    try:
        config = await dashboard.async_load(False)
    except ConfigNotFound:
        config = None

    if dashboard.url_path is None:
        url_path = DEFAULT_DASHBOARD
        title = "Default"
    else:
        url_path = dashboard.url_path
        title = config.get("title", url_path) if config else url_path

    views = []
    data = {
        "title": title,
        "url_path": url_path,
        "views": views,
    }

    if config is None:
        return data

    for idx, view in enumerate(config["views"]):
        path = view.get("path", f"{idx}")
        views.append(
            {
                "title": view.get("title", path),
                "path": path,
            }
        )

    return data


@callback
def _item_from_info(info: dict) -> BrowseMedia:
    """Convert dashboard info to browse item."""
    return BrowseMedia(
        title=info["title"],
        media_class=MediaClass.APP,
        media_content_id=info["url_path"],
        media_content_type=DOMAIN,
        thumbnail="https://brands.home-assistant.io/_/lovelace/logo.png",
        can_play=True,
        can_expand=len(info["views"]) > 1,
    )