from unittest.mock import MagicMock, patch
from urllib.parse import parse_qs, urlparse

from lib.clients.tmdb.base import BaseTmdbClient
from lib.clients.tmdb.utils.utils import (
    add_tmdb_movie_context_menu,
    add_tmdb_show_context_menu,
)
from lib.clients.trakt.trakt import BaseTraktClient

TRAILER_LABEL = "Play Trailer"


def _get_trailer_menu_item(menu):
    for label, command in menu:
        if label == TRAILER_LABEL:
            return label, command
    return None


def _parse_playmedia_command(command):
    url = command[len("PlayMedia(") : -1]
    query = parse_qs(urlparse(url).query)
    return {
        "action": query["action"][0],
        "media_type": query["media_type"][0],
        "tmdb_id": query.get("tmdb_id", [None])[0],
        "yt_id": query.get("yt_id", [None])[0],
        "youtube_url": query.get("youtube_url", [None])[0],
        "title": query.get("title", [None])[0],
    }


def _get_menu_item(menu, label):
    for item_label, command in menu:
        if item_label == label:
            return item_label, command
    return None


def _parse_runplugin_command(command):
    url = command[len("RunPlugin(") : -1]
    query = parse_qs(urlparse(url).query)
    return {key: values[0] for key, values in query.items()}


def test_movie_context_menu_contains_play_trailer_when_tmdb_id_exists():
    with patch(
        "lib.clients.tmdb.utils.utils.translation",
        side_effect=lambda value: TRAILER_LABEL if value == 90672 else f"t-{value}",
    ):
        menu = add_tmdb_movie_context_menu(
            mode="movies",
            media_type="movie",
            title="Demo Movie",
            ids={"tmdb_id": 550},
        )

    trailer_item = _get_trailer_menu_item(menu)

    assert trailer_item is not None
    assert _parse_playmedia_command(trailer_item[1]) == {
        "action": "play_trailer",
        "media_type": "movie",
        "tmdb_id": "550",
        "yt_id": None,
        "youtube_url": None,
        "title": "Demo Movie",
    }


def test_movie_context_menu_hides_play_trailer_without_tmdb_or_youtube_metadata():
    with patch(
        "lib.clients.tmdb.utils.utils.translation",
        side_effect=lambda value: TRAILER_LABEL if value == 90672 else f"t-{value}",
    ):
        menu = add_tmdb_movie_context_menu(
            mode="movies",
            media_type="movie",
            title="Demo Movie",
            ids={"imdb_id": "tt00550"},
        )

    assert _get_trailer_menu_item(menu) is None


def test_movie_context_menu_contains_search_modes_entry():
    search_modes_label = "Search modes"

    with patch(
        "lib.clients.tmdb.utils.utils.translation",
        side_effect=lambda value: search_modes_label if value == 90733 else f"t-{value}",
    ):
        menu = add_tmdb_movie_context_menu(
            mode="movies",
            media_type="movie",
            title="Demo Movie",
            ids={"tmdb_id": 550},
        )

    item = _get_menu_item(menu, search_modes_label)

    assert item is not None
    assert _parse_runplugin_command(item[1]) == {
        "action": "tmdb_search_modes",
        "mode": "movies",
        "media_type": "movie",
        "query": "Demo Movie",
        "tmdb_id": "550",
    }


def test_tv_context_menu_contains_play_trailer_when_tmdb_id_exists():
    with patch(
        "lib.clients.tmdb.utils.utils.translation",
        side_effect=lambda value: TRAILER_LABEL if value == 90672 else f"t-{value}",
    ):
        menu = add_tmdb_show_context_menu(
            mode="tv",
            title="Demo Show",
            ids={"tmdb_id": 1399},
        )

    trailer_item = _get_trailer_menu_item(menu)

    assert trailer_item is not None
    assert _parse_playmedia_command(trailer_item[1]) == {
        "action": "play_trailer",
        "media_type": "tv",
        "tmdb_id": "1399",
        "yt_id": None,
        "youtube_url": None,
        "title": "Demo Show",
    }


def test_base_tmdb_client_passes_show_title_to_context_menu_builder():
    list_item = MagicMock()

    with patch(
        "lib.clients.tmdb.base.add_tmdb_show_context_menu",
        return_value=[("tmdb-tv", "cmd")],
    ) as add_context_menu, patch("lib.clients.tmdb.base.is_trakt_auth", return_value=False), patch(
        "lib.clients.tmdb.base.add_kodi_dir_item"
    ):
        BaseTmdbClient.add_media_directory_item(
            list_item=list_item,
            mode="tv",
            title="Demo Show",
            ids={"tmdb_id": 1399},
        )

    add_context_menu.assert_called_once_with("tv", ids={"tmdb_id": 1399}, title="Demo Show")


def test_trakt_movie_context_menu_contains_play_trailer_when_tmdb_id_exists():
    list_item = MagicMock()

    with patch("lib.clients.trakt.trakt.is_trakt_auth", return_value=False), patch(
        "lib.clients.trakt.trakt.add_kodi_dir_item"
    ), patch(
        "lib.clients.tmdb.utils.utils.translation",
        side_effect=lambda value: TRAILER_LABEL if value == 90672 else f"t-{value}",
    ):
        BaseTraktClient._add_media_directory_item(
            list_item=list_item,
            mode="movies",
            title="Demo Movie",
            ids={"tmdb_id": 550},
            media_type="movie",
        )

    context_menu = list_item.addContextMenuItems.call_args[0][0]
    trailer_item = _get_trailer_menu_item(context_menu)

    assert trailer_item is not None
    assert _parse_playmedia_command(trailer_item[1]) == {
        "action": "play_trailer",
        "media_type": "movie",
        "tmdb_id": "550",
        "yt_id": None,
        "youtube_url": None,
        "title": "Demo Movie",
    }


def test_trakt_show_context_menu_contains_play_trailer_when_tmdb_id_exists():
    list_item = MagicMock()

    with patch("lib.clients.trakt.trakt.is_trakt_auth", return_value=True), patch(
        "lib.clients.trakt.trakt.BaseTraktClient._trakt_context_menu",
        return_value=[("watched", "cmd")],
    ), patch("lib.clients.trakt.trakt.add_kodi_dir_item"), patch(
        "lib.clients.tmdb.utils.utils.translation",
        side_effect=lambda value: TRAILER_LABEL if value == 90672 else f"t-{value}",
    ):
        BaseTraktClient._add_media_directory_item(
            list_item=list_item,
            mode="tv",
            title="Demo Show",
            ids={"tmdb_id": 1399},
            media_type="tv",
        )

    context_menu = list_item.addContextMenuItems.call_args[0][0]
    trailer_item = _get_trailer_menu_item(context_menu)

    assert trailer_item is not None
    assert _parse_playmedia_command(trailer_item[1]) == {
        "action": "play_trailer",
        "media_type": "tv",
        "tmdb_id": "1399",
        "yt_id": None,
        "youtube_url": None,
        "title": "Demo Show",
    }
