# ty:ignore[unresolved-import]
"""Service actions for mass_queue."""

from __future__ import annotations

from homeassistant.core import (
    ServiceCall,
    SupportsResponse,
    callback,
)

from .const import (
    ATTR_CONFIG_ENTRY_ID,
    ATTR_PAGE,
    ATTR_PLAYER_ENTITY,
    ATTR_PLAYLIST_ID,
    ATTR_POSITIONS_TO_REMOVE,
    ATTR_QUEUE_ITEM_ID,
    ATTR_URI,
    DOMAIN,
    LOGGER,
    SERVICE_CLEAR_QUEUE_FROM_HERE,
    SERVICE_GET_ALBUM,
    SERVICE_GET_ALBUM_TRACKS,
    SERVICE_GET_ARTIST,
    SERVICE_GET_ARTIST_TRACKS,
    SERVICE_GET_GROUP_VOLUME,
    SERVICE_GET_PLAYLIST,
    SERVICE_GET_PLAYLIST_TRACKS,
    SERVICE_GET_PODCAST,
    SERVICE_GET_PODCAST_EPISODES,
    SERVICE_GET_QUEUE_ITEMS,
    SERVICE_GET_RECOMMENDATIONS,
    SERVICE_MOVE_QUEUE_ITEM_DOWN,
    SERVICE_MOVE_QUEUE_ITEM_NEXT,
    SERVICE_MOVE_QUEUE_ITEM_UP,
    SERVICE_PLAY_QUEUE_ITEM,
    SERVICE_REMOVE_PLAYLIST_TRACKS,
    SERVICE_REMOVE_QUEUE_ITEM,
    SERVICE_SEND_COMMAND,
    SERVICE_SET_GROUP_VOLUME,
    SERVICE_UNFAVORITE_CURRENT_ITEM,
)
from .schemas import (
    CLEAR_QUEUE_FROM_HERE_SERVICE_SCHEMA,
    GET_DATA_SERVICE_SCHEMA,
    GET_GROUP_VOLUME_SERVICE_SCHEMA,
    GET_PODCAST_EPISODES_SERVICE_SCHEMA,
    GET_RECOMMENDATIONS_SERVICE_SCHEMA,
    GET_TRACKS_SERVICE_SCHEMA,
    MOVE_QUEUE_ITEM_DOWN_SERVICE_SCHEMA,
    MOVE_QUEUE_ITEM_NEXT_SERVICE_SCHEMA,
    MOVE_QUEUE_ITEM_UP_SERVICE_SCHEMA,
    PLAY_QUEUE_ITEM_SERVICE_SCHEMA,
    QUEUE_ITEMS_SERVICE_SCHEMA,
    REMOVE_PLAYLIST_TRACKS_SERVICE_SCHEMA,
    REMOVE_QUEUE_ITEM_SERVICE_SCHEMA,
    SEND_COMMAND_SERVICE_SCHEMA,
    SET_GROUP_VOLUME_SERVICE_SCHEMA,
    UNFAVORITE_CURRENT_ITEM_SERVICE_SCHEMA,
)
from .utils import get_entity_actions_controller, process_recommendations


@callback
def register_actions(hass) -> None:
    """Registers actions with Home Assistant."""
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_QUEUE_ITEMS,
        get_queue_items,
        schema=QUEUE_ITEMS_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_MOVE_QUEUE_ITEM_DOWN,
        move_queue_item_down,
        schema=MOVE_QUEUE_ITEM_DOWN_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_MOVE_QUEUE_ITEM_NEXT,
        move_queue_item_next,
        schema=MOVE_QUEUE_ITEM_NEXT_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_MOVE_QUEUE_ITEM_UP,
        move_queue_item_up,
        schema=MOVE_QUEUE_ITEM_UP_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_PLAY_QUEUE_ITEM,
        play_queue_item,
        schema=PLAY_QUEUE_ITEM_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_REMOVE_QUEUE_ITEM,
        remove_queue_item,
        schema=REMOVE_QUEUE_ITEM_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_SEND_COMMAND,
        send_command,
        schema=SEND_COMMAND_SERVICE_SCHEMA,
        supports_response=SupportsResponse.OPTIONAL,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_UNFAVORITE_CURRENT_ITEM,
        unfavorite_current_item,
        schema=UNFAVORITE_CURRENT_ITEM_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_RECOMMENDATIONS,
        get_recommendations,
        schema=GET_RECOMMENDATIONS_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_GROUP_VOLUME,
        get_group_volume,
        schema=GET_GROUP_VOLUME_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_SET_GROUP_VOLUME,
        set_group_volume,
        schema=SET_GROUP_VOLUME_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_CLEAR_QUEUE_FROM_HERE,
        clear_queue_from_here,
        schema=CLEAR_QUEUE_FROM_HERE_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_PLAYLIST_TRACKS,
        get_playlist_tracks,
        schema=GET_TRACKS_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_ALBUM_TRACKS,
        get_album_tracks,
        schema=GET_TRACKS_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_ARTIST_TRACKS,
        get_artist_tracks,
        schema=GET_TRACKS_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_PODCAST_EPISODES,
        get_podcast_episodes,
        schema=GET_PODCAST_EPISODES_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_ALBUM,
        get_album,
        schema=GET_DATA_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_ARTIST,
        get_artist,
        schema=GET_DATA_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_PLAYLIST,
        get_playlist,
        schema=GET_DATA_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_GET_PODCAST,
        get_podcast,
        schema=GET_DATA_SERVICE_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_REMOVE_PLAYLIST_TRACKS,
        remove_playlist_tracks,
        schema=REMOVE_PLAYLIST_TRACKS_SERVICE_SCHEMA,
        supports_response=SupportsResponse.NONE,
    )


async def get_queue_items(call: ServiceCall):
    """Service wrapper to get queue items."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    return await actions.get_queue_items(call)


async def move_queue_item_down(call: ServiceCall):
    """Service wrapper to move queue item down."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    return await actions.move_queue_item_down(call)


async def move_queue_item_next(call: ServiceCall):
    """Service wrapper to move queue item next."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    return await actions.move_queue_item_next(call)


async def move_queue_item_up(call: ServiceCall):
    """Service wrapper to move queue item up."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    return await actions.move_queue_item_up(call)


async def play_queue_item(call: ServiceCall):
    """Service wrapper to play a queue item."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    return await actions.play_queue_item(call)


async def remove_queue_item(call: ServiceCall):
    """Service wrapper to remove a queue item."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    return await actions.remove_queue_item(call)


async def send_command(call: ServiceCall):
    """Service wrapper to send command to Music Assistant."""
    entry_id = call.data[ATTR_CONFIG_ENTRY_ID]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(entry_id)
    actions = entry.runtime_data.actions
    return await actions.send_command(call)


async def unfavorite_current_item(call: ServiceCall):
    """Service wrapper to unfavorite currently playing item."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    await actions.unfavorite_item(call)


async def get_recommendations(call: ServiceCall):
    """Service wrapper to get recommendations from providers."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    result = await actions.get_recommendations(call)
    return {"response": process_recommendations(result)}


async def get_group_volume(call: ServiceCall):
    """Service wrapper to get grouped volume."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    result = await actions.get_group_volume(call)
    return {"volume_level": result}


async def set_group_volume(call: ServiceCall):
    """Service wrapper to set grouped volume."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    await actions.set_group_volume(call)


def filter_queue_after(queue, current_idx):
    """Returns all items after the current active track."""
    if current_idx == len(queue):
        return []
    return queue[current_idx + 1 :]


async def clear_queue_from_here(call: ServiceCall):
    """Service wrapper to clear queue from point."""
    entity_id = call.data[ATTR_PLAYER_ENTITY]
    hass = call.hass
    actions = get_entity_actions_controller(hass, entity_id)
    current_idx = await actions.get_queue_index(entity_id)
    LOGGER.debug(f"Current Index: {current_idx}")
    queue_id = actions.get_queue_id(entity_id)
    LOGGER.debug(f"Queue ID: {queue_id}")
    queue = actions._controller.queues.get(queue_id)
    LOGGER.debug(f"Queue length: {len(queue)}")
    client = actions._client
    if len(queue) == current_idx:
        return
    items = queue[current_idx + 1 :]
    LOGGER.debug(f"Filtered length: {len(items)}")
    LOGGER.debug(f"First item to remove {items[0]}")
    LOGGER.debug(f"Last item to remove {items[-1]}")
    for item in items:
        queue_item_id = item[ATTR_QUEUE_ITEM_ID]
        await client.player_queues.queue_command_delete(queue_id, queue_item_id)


async def get_album_tracks(call: ServiceCall):
    """Gets all tracks in an album."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    page = call.data.get(ATTR_PAGE)
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return {
        "tracks": await actions.get_album_tracks(uri, page),
    }


async def get_artist_tracks(call: ServiceCall):
    """Gets all tracks for an artist."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return {
        "tracks": await actions.get_artist_tracks(uri),
    }


async def get_playlist_tracks(call: ServiceCall):
    """Gets all tracks in a playlist."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    page = call.data.get(ATTR_PAGE)
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return {
        "tracks": await actions.get_playlist_tracks(uri, page),
    }


async def get_podcast_episodes(call: ServiceCall):
    """Gets all episodes for a podcast."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return {
        "episodes": await actions.get_podcast_episodes(uri),
    }


async def get_album(call: ServiceCall):
    """Returns the details about an album from the server."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return (await actions.get_album_details(uri)).to_dict()


async def get_artist(call: ServiceCall):
    """Returns the details about an artist from the server."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return (await actions.get_artist_details(uri)).to_dict()


async def get_playlist(call: ServiceCall):
    """Returns the details about a playlist from the server."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return (await actions.get_playlist_details(uri)).to_dict()


async def get_podcast(call: ServiceCall):
    """Returns the details about a podcast from the server."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    uri = call.data[ATTR_URI]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    return (await actions.get_podcast_details(uri)).to_dict()


async def remove_playlist_tracks(call: ServiceCall):
    """Removes one or more items from a playlist."""
    config_entry = call.data[ATTR_CONFIG_ENTRY_ID]
    playlist = call.data[ATTR_PLAYLIST_ID]
    positions = call.data[ATTR_POSITIONS_TO_REMOVE]
    if isinstance(positions, int):
        positions = [positions]
    positions = [int(position) for position in positions]
    hass = call.hass
    entry = hass.config_entries.async_get_entry(config_entry)
    actions = entry.runtime_data.actions
    await actions.remove_playlist_tracks(playlist, positions)
