"""Demo implementation of the media player."""
from __future__ import annotations

from datetime import datetime
from typing import Any

from homeassistant.components.media_player import (
    MediaPlayerDeviceClass,
    MediaPlayerEntity,
    MediaPlayerEntityFeature,
    MediaPlayerState,
    MediaType,
    RepeatMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
import homeassistant.util.dt as dt_util


async def async_setup_platform(
    hass: HomeAssistant,
    config: ConfigType,
    async_add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Set up the media player demo platform."""
    async_add_entities(
        [
            DemoYoutubePlayer(
                "Living Room",
                "eyU3bRy2x44",
                "♥♥ The Best Fireplace Video (3 hours)",
                300,
            ),
            DemoYoutubePlayer(
                "Bedroom", "kxopViU98Xo", "Epic sax guy 10 hours", 360000
            ),
            DemoMusicPlayer(),
            DemoMusicPlayer("Kitchen"),
            DemoTVShowPlayer(),
        ]
    )


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the Demo config entry."""
    await async_setup_platform(hass, {}, async_add_entities)


SOUND_MODE_LIST = ["Music", "Movie"]
DEFAULT_SOUND_MODE = "Music"

YOUTUBE_PLAYER_SUPPORT = (
    MediaPlayerEntityFeature.PAUSE
    | MediaPlayerEntityFeature.VOLUME_SET
    | MediaPlayerEntityFeature.VOLUME_MUTE
    | MediaPlayerEntityFeature.TURN_ON
    | MediaPlayerEntityFeature.TURN_OFF
    | MediaPlayerEntityFeature.PLAY_MEDIA
    | MediaPlayerEntityFeature.PLAY
    | MediaPlayerEntityFeature.SHUFFLE_SET
    | MediaPlayerEntityFeature.SELECT_SOUND_MODE
    | MediaPlayerEntityFeature.SEEK
    | MediaPlayerEntityFeature.STOP
)

MUSIC_PLAYER_SUPPORT = (
    MediaPlayerEntityFeature.PAUSE
    | MediaPlayerEntityFeature.VOLUME_SET
    | MediaPlayerEntityFeature.VOLUME_MUTE
    | MediaPlayerEntityFeature.TURN_ON
    | MediaPlayerEntityFeature.TURN_OFF
    | MediaPlayerEntityFeature.CLEAR_PLAYLIST
    | MediaPlayerEntityFeature.GROUPING
    | MediaPlayerEntityFeature.PLAY
    | MediaPlayerEntityFeature.SHUFFLE_SET
    | MediaPlayerEntityFeature.REPEAT_SET
    | MediaPlayerEntityFeature.VOLUME_STEP
    | MediaPlayerEntityFeature.PREVIOUS_TRACK
    | MediaPlayerEntityFeature.NEXT_TRACK
    | MediaPlayerEntityFeature.SELECT_SOUND_MODE
    | MediaPlayerEntityFeature.STOP
)

NETFLIX_PLAYER_SUPPORT = (
    MediaPlayerEntityFeature.PAUSE
    | MediaPlayerEntityFeature.TURN_ON
    | MediaPlayerEntityFeature.TURN_OFF
    | MediaPlayerEntityFeature.SELECT_SOURCE
    | MediaPlayerEntityFeature.PLAY
    | MediaPlayerEntityFeature.SHUFFLE_SET
    | MediaPlayerEntityFeature.PREVIOUS_TRACK
    | MediaPlayerEntityFeature.NEXT_TRACK
    | MediaPlayerEntityFeature.SELECT_SOUND_MODE
    | MediaPlayerEntityFeature.STOP
)


class AbstractDemoPlayer(MediaPlayerEntity):
    """A demo media players."""

    _attr_sound_mode_list = SOUND_MODE_LIST
    _attr_should_poll = False

    # We only implement the methods that we support

    def __init__(
        self, name: str, device_class: MediaPlayerDeviceClass | None = None
    ) -> None:
        """Initialize the demo device."""
        self._attr_name = name
        self._attr_state = MediaPlayerState.PLAYING
        self._attr_volume_level = 1.0
        self._attr_is_volume_muted = False
        self._attr_shuffle = False
        self._attr_sound_mode = DEFAULT_SOUND_MODE
        self._attr_device_class = device_class

    def turn_on(self) -> None:
        """Turn the media player on."""
        self._attr_state = MediaPlayerState.PLAYING
        self.schedule_update_ha_state()

    def turn_off(self) -> None:
        """Turn the media player off."""
        self._attr_state = MediaPlayerState.OFF
        self.schedule_update_ha_state()

    def mute_volume(self, mute: bool) -> None:
        """Mute the volume."""
        self._attr_is_volume_muted = mute
        self.schedule_update_ha_state()

    def volume_up(self) -> None:
        """Increase volume."""
        assert self.volume_level is not None
        self._attr_volume_level = min(1.0, self.volume_level + 0.1)
        self.schedule_update_ha_state()

    def volume_down(self) -> None:
        """Decrease volume."""
        assert self.volume_level is not None
        self._attr_volume_level = max(0.0, self.volume_level - 0.1)
        self.schedule_update_ha_state()

    def set_volume_level(self, volume: float) -> None:
        """Set the volume level, range 0..1."""
        self._attr_volume_level = volume
        self.schedule_update_ha_state()

    def media_play(self) -> None:
        """Send play command."""
        self._attr_state = MediaPlayerState.PLAYING
        self.schedule_update_ha_state()

    def media_pause(self) -> None:
        """Send pause command."""
        self._attr_state = MediaPlayerState.PAUSED
        self.schedule_update_ha_state()

    def media_stop(self) -> None:
        """Send stop command."""
        self._attr_state = MediaPlayerState.OFF
        self.schedule_update_ha_state()

    def set_shuffle(self, shuffle: bool) -> None:
        """Enable/disable shuffle mode."""
        self._attr_shuffle = shuffle
        self.schedule_update_ha_state()

    def select_sound_mode(self, sound_mode: str) -> None:
        """Select sound mode."""
        self._attr_sound_mode = sound_mode
        self.schedule_update_ha_state()


class DemoYoutubePlayer(AbstractDemoPlayer):
    """A Demo media player that only supports YouTube."""

    # We only implement the methods that we support

    _attr_media_content_type = MediaType.MOVIE

    def __init__(
        self, name: str, youtube_id: str, media_title: str, duration: int
    ) -> None:
        """Initialize the demo device."""
        super().__init__(name)
        self.youtube_id = youtube_id
        self._media_title = media_title
        self._duration = duration
        self._progress: int | None = int(duration * 0.15)
        self._progress_updated_at = dt_util.utcnow()

    @property
    def media_content_id(self) -> str:
        """Return the content ID of current playing media."""
        return self.youtube_id

    @property
    def media_duration(self) -> int:
        """Return the duration of current playing media in seconds."""
        return self._duration

    @property
    def media_image_url(self) -> str:
        """Return the image url of current playing media."""
        return f"https://img.youtube.com/vi/{self.youtube_id}/hqdefault.jpg"

    @property
    def media_title(self) -> str:
        """Return the title of current playing media."""
        return self._media_title

    @property
    def app_name(self) -> str:
        """Return the current running application."""
        return "YouTube"

    @property
    def supported_features(self) -> int:
        """Flag media player features that are supported."""
        return YOUTUBE_PLAYER_SUPPORT

    @property
    def media_position(self) -> int | None:
        """Position of current playing media in seconds."""
        if self._progress is None:
            return None

        position = self._progress

        if self.state == MediaPlayerState.PLAYING:
            position += int(
                (dt_util.utcnow() - self._progress_updated_at).total_seconds()
            )

        return position

    @property
    def media_position_updated_at(self) -> datetime | None:
        """When was the position of the current playing media valid.

        Returns value from homeassistant.util.dt.utcnow().
        """
        if self.state == MediaPlayerState.PLAYING:
            return self._progress_updated_at
        return None

    def play_media(self, media_type: str, media_id: str, **kwargs: Any) -> None:
        """Play a piece of media."""
        self.youtube_id = media_id
        self.schedule_update_ha_state()

    def media_pause(self) -> None:
        """Send pause command."""
        self._progress = self.media_position
        self._progress_updated_at = dt_util.utcnow()
        super().media_pause()


class DemoMusicPlayer(AbstractDemoPlayer):
    """A Demo media player."""

    # We only implement the methods that we support

    _attr_media_content_type = MediaType.MUSIC

    tracks = [
        ("Technohead", "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)"),
        ("Paul Elstak", "Luv U More"),
        ("Dune", "Hardcore Vibes"),
        ("Nakatomi", "Children Of The Night"),
        ("Party Animals", "Have You Ever Been Mellow? (Flamman & Abraxas Radio Mix)"),
        ("Rob G.*", "Ecstasy, You Got What I Need"),
        ("Lipstick", "I'm A Raver"),
        ("4 Tune Fairytales", "My Little Fantasy (Radio Edit)"),
        ("Prophet", "The Big Boys Don't Cry"),
        ("Lovechild", "All Out Of Love (DJ Weirdo & Sim Remix)"),
        ("Stingray & Sonic Driver", "Cold As Ice (El Bruto Remix)"),
        ("Highlander", "Hold Me Now (Bass-D & King Matthew Remix)"),
        ("Juggernaut", 'Ruffneck Rules Da Artcore Scene (12" Edit)'),
        ("Diss Reaction", "Jiiieehaaaa "),
        ("Flamman And Abraxas", "Good To Go (Radio Mix)"),
        ("Critical Mass", "Dancing Together"),
        (
            "Charly Lownoise & Mental Theo",
            "Ultimate Sex Track (Bass-D & King Matthew Remix)",
        ),
    ]

    def __init__(self, name: str = "Walkman") -> None:
        """Initialize the demo device."""
        super().__init__(name)
        self._cur_track = 0
        self._group_members: list[str] = []
        self._repeat = RepeatMode.OFF

    @property
    def group_members(self) -> list[str]:
        """List of players which are currently grouped together."""
        return self._group_members

    @property
    def media_content_id(self) -> str:
        """Return the content ID of current playing media."""
        return "bounzz-1"

    @property
    def media_duration(self) -> int:
        """Return the duration of current playing media in seconds."""
        return 213

    @property
    def media_image_url(self) -> str:
        """Return the image url of current playing media."""
        return "https://graph.facebook.com/v2.5/107771475912710/picture?type=large"

    @property
    def media_title(self) -> str:
        """Return the title of current playing media."""
        return self.tracks[self._cur_track][1] if self.tracks else ""

    @property
    def media_artist(self) -> str:
        """Return the artist of current playing media (Music track only)."""
        return self.tracks[self._cur_track][0] if self.tracks else ""

    @property
    def media_album_name(self) -> str:
        """Return the album of current playing media (Music track only)."""
        return "Bounzz"

    @property
    def media_track(self) -> int:
        """Return the track number of current media (Music track only)."""
        return self._cur_track + 1

    @property
    def repeat(self) -> RepeatMode:
        """Return current repeat mode."""
        return self._repeat

    @property
    def supported_features(self) -> int:
        """Flag media player features that are supported."""
        return MUSIC_PLAYER_SUPPORT

    def media_previous_track(self) -> None:
        """Send previous track command."""
        if self._cur_track > 0:
            self._cur_track -= 1
            self.schedule_update_ha_state()

    def media_next_track(self) -> None:
        """Send next track command."""
        if self._cur_track < len(self.tracks) - 1:
            self._cur_track += 1
            self.schedule_update_ha_state()

    def clear_playlist(self) -> None:
        """Clear players playlist."""
        self.tracks = []
        self._cur_track = 0
        self._attr_state = MediaPlayerState.OFF
        self.schedule_update_ha_state()

    def set_repeat(self, repeat: RepeatMode) -> None:
        """Enable/disable repeat mode."""
        self._repeat = repeat
        self.schedule_update_ha_state()

    def join_players(self, group_members: list[str]) -> None:
        """Join `group_members` as a player group with the current player."""
        self._group_members = [
            self.entity_id,
        ] + group_members
        self.schedule_update_ha_state()

    def unjoin_player(self) -> None:
        """Remove this player from any group."""
        self._group_members = []
        self.schedule_update_ha_state()


class DemoTVShowPlayer(AbstractDemoPlayer):
    """A Demo media player that only supports YouTube."""

    # We only implement the methods that we support

    _attr_media_content_type = MediaType.TVSHOW

    def __init__(self) -> None:
        """Initialize the demo device."""
        super().__init__("Lounge room", MediaPlayerDeviceClass.TV)
        self._cur_episode = 1
        self._episode_count = 13
        self._source = "dvd"
        self._source_list = ["dvd", "youtube"]

    @property
    def media_content_id(self) -> str:
        """Return the content ID of current playing media."""
        return "house-of-cards-1"

    @property
    def media_duration(self) -> int:
        """Return the duration of current playing media in seconds."""
        return 3600

    @property
    def media_image_url(self) -> str:
        """Return the image url of current playing media."""
        return "https://graph.facebook.com/v2.5/HouseofCards/picture?width=400"

    @property
    def media_title(self) -> str:
        """Return the title of current playing media."""
        return f"Chapter {self._cur_episode}"

    @property
    def media_series_title(self) -> str:
        """Return the series title of current playing media (TV Show only)."""
        return "House of Cards"

    @property
    def media_season(self) -> str:
        """Return the season of current playing media (TV Show only)."""
        return "1"

    @property
    def media_episode(self) -> str:
        """Return the episode of current playing media (TV Show only)."""
        return str(self._cur_episode)

    @property
    def app_name(self) -> str:
        """Return the current running application."""
        return "Netflix"

    @property
    def source(self) -> str:
        """Return the current input source."""
        return self._source

    @property
    def source_list(self) -> list[str]:
        """List of available sources."""
        return self._source_list

    @property
    def supported_features(self) -> int:
        """Flag media player features that are supported."""
        return NETFLIX_PLAYER_SUPPORT

    def media_previous_track(self) -> None:
        """Send previous track command."""
        if self._cur_episode > 1:
            self._cur_episode -= 1
            self.schedule_update_ha_state()

    def media_next_track(self) -> None:
        """Send next track command."""
        if self._cur_episode < self._episode_count:
            self._cur_episode += 1
            self.schedule_update_ha_state()

    def select_source(self, source: str) -> None:
        """Set the input source."""
        self._source = source
        self.schedule_update_ha_state()