"""Support for media browsing."""
import logging

from afsapi import AFSAPI, FSApiException, OutOfRangeException, Preset

from homeassistant.components.media_player import (
    BrowseError,
    BrowseMedia,
    MediaClass,
    MediaType,
)

from .const import MEDIA_CONTENT_ID_CHANNELS, MEDIA_CONTENT_ID_PRESET

TOP_LEVEL_DIRECTORIES = {
    MEDIA_CONTENT_ID_CHANNELS: "Channels",
    MEDIA_CONTENT_ID_PRESET: "Presets",
}

FSAPI_ITEM_TYPE_TO_MEDIA_CLASS = {
    0: MediaClass.DIRECTORY,
    1: MediaClass.CHANNEL,
    2: MediaClass.CHANNEL,
}

_LOGGER = logging.getLogger(__name__)


def _item_preset_payload(preset: Preset, player_mode: str) -> BrowseMedia:
    """
    Create response payload for a single media item.

    Used by async_browse_media.
    """
    return BrowseMedia(
        title=preset.name,
        media_class=MediaClass.CHANNEL,
        media_content_type=MediaType.CHANNEL,
        # We add 1 to the preset key to keep it in sync with the numbering shown
        # on the interface of the device
        media_content_id=f"{player_mode}/{MEDIA_CONTENT_ID_PRESET}/{int(preset.key)+1}",
        can_play=True,
        can_expand=False,
    )


def _item_payload(
    key, item: dict[str, str], player_mode: str, parent_keys: list[str]
) -> BrowseMedia:
    """
    Create response payload for a single media item.

    Used by async_browse_media.
    """
    assert "label" in item or "name" in item
    assert "type" in item

    title = item.get("label") or item.get("name") or "Unknown"
    title = title.strip()

    media_content_id = "/".join(
        [player_mode, MEDIA_CONTENT_ID_CHANNELS, *parent_keys, key]
    )
    media_class = (
        FSAPI_ITEM_TYPE_TO_MEDIA_CLASS.get(int(item["type"])) or MediaClass.CHANNEL
    )

    return BrowseMedia(
        title=title,
        media_class=media_class,
        media_content_type=MediaClass.CHANNEL,
        media_content_id=media_content_id,
        can_play=(media_class != MediaClass.DIRECTORY),
        can_expand=(media_class == MediaClass.DIRECTORY),
    )


async def browse_top_level(current_mode, afsapi: AFSAPI):
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """

    children = [
        BrowseMedia(
            title=name,
            media_class=MediaClass.DIRECTORY,
            media_content_type=MediaType.CHANNELS,
            media_content_id=(
                f"{current_mode or 'unknown'}/{top_level_media_content_id}"
            ),
            can_play=False,
            can_expand=True,
        )
        for top_level_media_content_id, name in TOP_LEVEL_DIRECTORIES.items()
    ]

    library_info = BrowseMedia(
        media_class=MediaClass.DIRECTORY,
        media_content_id="library",
        media_content_type=MediaType.CHANNELS,
        title="Media Library",
        can_play=False,
        can_expand=True,
        children=children,
        children_media_class=MediaClass.DIRECTORY,
    )

    return library_info


async def browse_node(
    afsapi: AFSAPI,
    media_content_type,
    media_content_id,
):
    """List the contents of a navigation directory (or preset list)."""

    player_mode, browse_type, *parent_keys = media_content_id.split("/")

    title = TOP_LEVEL_DIRECTORIES.get(browse_type, "Unknown")

    children = []
    try:
        if browse_type == MEDIA_CONTENT_ID_PRESET:
            # Return the presets

            children = [
                _item_preset_payload(preset, player_mode=player_mode)
                for preset in await afsapi.get_presets()
            ]

        else:
            # Browse to correct folder
            await afsapi.nav_select_folder_via_path(parent_keys)

            # Return items in this folder
            children = [
                _item_payload(key, item, player_mode, parent_keys=parent_keys)
                async for key, item in await afsapi.nav_list()
            ]
    except OutOfRangeException as err:
        raise BrowseError("The requested item is out of range") from err
    except FSApiException as err:
        raise BrowseError(str(err)) from err

    return BrowseMedia(
        title=title,
        media_content_id=media_content_id,
        media_content_type=MediaType.CHANNELS,
        media_class=MediaClass.DIRECTORY,
        can_play=False,
        can_expand=True,
        children=children,
        children_media_class=MediaType.CHANNEL,
    )
