import json
from unittest.mock import MagicMock, patch

from lib.clients.tmdb.tmdb import TmdbClient


def test_tmdb_search_modes_runs_title_year_search_for_movies():
    tmdb_obj = {
        "external_ids": {"imdb_id": "tt1375666", "tvdb_id": ""},
    }

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch(
        "lib.clients.tmdb.tmdb.show_keyboard", return_value="Inception Alt"
    ), patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = 0
        dialog_cls.return_value.numeric.return_value = "2010"

        TmdbClient.tmdb_search_modes(
            {
                "mode": "movies",
                "media_type": "movie",
                "tmdb_id": "27205",
                "query": "Inception",
            }
        )

    payload = run_search_entry.call_args[0][0]
    assert payload["query"] == "Inception Alt"
    assert payload["mode"] == "movies"
    assert payload["search_variant"] == "title_year"
    assert payload["year"] == "2010"
    assert payload["rescrape"] is True
    assert payload["force_select"] is True
    assert json.loads(payload["ids"]) == {
        "tmdb_id": "27205",
        "imdb_id": "tt1375666",
        "tvdb_id": "",
    }


def test_tmdb_search_modes_runs_original_title_search_for_movies():
    tmdb_obj = {
        "external_ids": {"imdb_id": "tt0245429", "tvdb_id": ""},
    }

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch(
        "lib.clients.tmdb.tmdb.show_keyboard",
        return_value="Sen to Chihiro no kamikakushi",
    ), patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = 1

        TmdbClient.tmdb_search_modes(
            {
                "mode": "movies",
                "media_type": "movie",
                "tmdb_id": "129",
                "query": "Spirited Away",
            }
        )

    payload = run_search_entry.call_args[0][0]
    assert payload["search_variant"] == "original_title"
    assert payload["query"] == "Sen to Chihiro no kamikakushi"
    assert payload["year"] == ""
    dialog_cls.return_value.numeric.assert_not_called()


def test_tmdb_search_modes_returns_early_when_dialog_cancelled():
    tmdb_obj = {
        "external_ids": {"imdb_id": "tt1375666", "tvdb_id": ""},
    }

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch("lib.clients.tmdb.tmdb.show_keyboard", return_value="Inception"), patch(
        "lib.search.run_search_entry"
    ) as run_search_entry:
        dialog_cls.return_value.select.return_value = -1

        TmdbClient.tmdb_search_modes(
            {
                "mode": "movies",
                "media_type": "movie",
                "tmdb_id": "27205",
                "query": "Inception",
            }
        )

    run_search_entry.assert_not_called()


def test_tmdb_search_modes_returns_early_when_year_input_cancelled():
    tmdb_obj = {
        "external_ids": {"imdb_id": "tt1375666", "tvdb_id": ""},
    }

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch("lib.clients.tmdb.tmdb.show_keyboard", return_value="Inception"), patch(
        "lib.search.run_search_entry"
    ) as run_search_entry:
        dialog_cls.return_value.select.return_value = 0
        dialog_cls.return_value.numeric.return_value = ""

        TmdbClient.tmdb_search_modes(
            {
                "mode": "movies",
                "media_type": "movie",
                "tmdb_id": "27205",
                "query": "Inception",
            }
        )

    run_search_entry.assert_not_called()


def test_tmdb_search_modes_rejects_invalid_manual_year():
    tmdb_obj = {
        "external_ids": {"imdb_id": "tt1375666", "tvdb_id": ""},
    }

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch("lib.clients.tmdb.tmdb.show_keyboard", return_value="Inception"), patch(
        "lib.clients.tmdb.tmdb.notification"
    ) as notification, patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = 2
        dialog_cls.return_value.numeric.return_value = "20ab"

        TmdbClient.tmdb_search_modes(
            {
                "mode": "movies",
                "media_type": "movie",
                "tmdb_id": "27205",
                "query": "Inception",
            }
        )

    notification.assert_called_once()
    run_search_entry.assert_not_called()


def test_tmdb_search_modes_returns_early_when_title_edit_cancelled():
    tmdb_obj = {
        "external_ids": {"imdb_id": "tt1375666", "tvdb_id": ""},
    }

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch("lib.clients.tmdb.tmdb.show_keyboard", return_value=""), patch(
        "lib.search.run_search_entry"
    ) as run_search_entry:
        dialog_cls.return_value.select.return_value = 0

        TmdbClient.tmdb_search_modes(
            {
                "mode": "movies",
                "media_type": "movie",
                "tmdb_id": "27205",
                "query": "Inception",
            }
        )

    dialog_cls.return_value.numeric.assert_not_called()
    run_search_entry.assert_not_called()


def test_tmdb_episode_search_modes_runs_search_with_edited_title_season_episode():
    tmdb_obj = MagicMock()
    tmdb_obj.original_name = "Breaking Bad"

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch(
        "lib.clients.tmdb.tmdb.show_keyboard", return_value="Breaking Bad Alt"
    ), patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = 0
        dialog_cls.return_value.numeric.side_effect = ["2", "5"]

        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "tv",
                "media_type": "tv",
                "query": "Breaking Bad",
                "ids": json.dumps({"tmdb_id": "1396", "imdb_id": "tt0903747", "tvdb_id": "81189"}),
                "tv_data": json.dumps({"name": "Episode 5", "season": 1, "episode": 5}),
            }
        )

    payload = run_search_entry.call_args[0][0]
    assert payload["query"] == "Breaking Bad Alt"
    assert payload["mode"] == "tv"
    assert payload["rescrape"] is True
    assert payload["force_select"] is True
    tv_data = json.loads(payload["tv_data"])
    assert tv_data["season"] == 2
    assert tv_data["episode"] == 5
    assert json.loads(payload["ids"]) == {
        "tmdb_id": "1396",
        "imdb_id": "tt0903747",
        "tvdb_id": "81189",
    }


def test_tmdb_episode_search_modes_runs_search_with_original_title():
    tmdb_obj = MagicMock()
    tmdb_obj.original_name = "Breaking Bad Original"

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch(
        "lib.clients.tmdb.tmdb.show_keyboard", return_value="Breaking Bad Original"
    ), patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = 1
        dialog_cls.return_value.numeric.side_effect = ["3", "8"]

        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "tv",
                "media_type": "tv",
                "query": "Breaking Bad",
                "ids": json.dumps({"tmdb_id": "1396"}),
                "tv_data": json.dumps({"name": "Episode 5", "season": 1, "episode": 5}),
            }
        )

    payload = run_search_entry.call_args[0][0]
    assert payload["query"] == "Breaking Bad Original"
    tv_data = json.loads(payload["tv_data"])
    assert tv_data["season"] == 3
    assert tv_data["episode"] == 8


def test_tmdb_episode_search_modes_runs_full_show_title_year_without_tv_data():
    tmdb_obj = MagicMock()
    tmdb_obj.original_name = "Breaking Bad"

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch(
        "lib.clients.tmdb.tmdb.show_keyboard", return_value="Breaking Bad Alt"
    ), patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = 2
        dialog_cls.return_value.numeric.return_value = "2008"

        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "tv",
                "media_type": "tv",
                "query": "Breaking Bad",
                "ids": json.dumps({"tmdb_id": "1396", "imdb_id": "tt0903747", "tvdb_id": "81189"}),
                "tv_data": json.dumps({"name": "Episode 5", "season": 1, "episode": 5}),
            }
        )

    payload = run_search_entry.call_args[0][0]
    assert payload["query"] == "Breaking Bad Alt"
    assert payload["mode"] == "tv"
    assert payload["search_variant"] == "title_year"
    assert payload["year"] == "2008"
    assert payload["rescrape"] is True
    assert payload["force_select"] is True
    assert "tv_data" not in payload
    assert json.loads(payload["ids"]) == {
        "tmdb_id": "1396",
        "imdb_id": "tt0903747",
        "tvdb_id": "81189",
    }
    assert dialog_cls.return_value.numeric.call_count == 1


def test_tmdb_episode_search_modes_returns_early_when_selector_cancelled():
    tmdb_obj = MagicMock()
    tmdb_obj.original_name = "Breaking Bad"

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = -1

        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "tv",
                "media_type": "tv",
                "query": "Breaking Bad",
                "ids": json.dumps({"tmdb_id": "1396"}),
                "tv_data": json.dumps({"name": "Episode 5", "season": 1, "episode": 5}),
            }
        )

    dialog_cls.return_value.numeric.assert_not_called()
    run_search_entry.assert_not_called()


def test_tmdb_episode_search_modes_returns_early_when_title_cancelled():
    tmdb_obj = MagicMock()
    tmdb_obj.original_name = "Breaking Bad"

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch("lib.clients.tmdb.tmdb.show_keyboard", return_value=""), patch(
        "lib.search.run_search_entry"
    ) as run_search_entry:
        dialog_cls.return_value.select.return_value = 0

        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "tv",
                "media_type": "tv",
                "query": "Breaking Bad",
                "ids": json.dumps({"tmdb_id": "1396"}),
                "tv_data": json.dumps({"name": "Episode 5", "season": 1, "episode": 5}),
            }
        )

    dialog_cls.return_value.numeric.assert_not_called()
    run_search_entry.assert_not_called()


def test_tmdb_episode_search_modes_returns_early_when_season_cancelled():
    tmdb_obj = MagicMock()
    tmdb_obj.original_name = "Breaking Bad"

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch(
        "lib.clients.tmdb.tmdb.show_keyboard", return_value="Breaking Bad"
    ), patch("lib.search.run_search_entry") as run_search_entry:
        dialog_cls.return_value.select.return_value = 0
        dialog_cls.return_value.numeric.return_value = ""

        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "tv",
                "media_type": "tv",
                "query": "Breaking Bad",
                "ids": json.dumps({"tmdb_id": "1396"}),
                "tv_data": json.dumps({"name": "Episode 5", "season": 1, "episode": 5}),
            }
        )

    run_search_entry.assert_not_called()


def test_tmdb_episode_search_modes_rejects_invalid_season():
    tmdb_obj = MagicMock()
    tmdb_obj.original_name = "Breaking Bad"

    with patch.object(TmdbClient, "_get_tmdb_metadata", return_value=tmdb_obj), patch(
        "lib.clients.tmdb.tmdb.xbmcgui.Dialog"
    ) as dialog_cls, patch(
        "lib.clients.tmdb.tmdb.show_keyboard", return_value="Breaking Bad"
    ), patch("lib.clients.tmdb.tmdb.notification") as notification, patch(
        "lib.search.run_search_entry"
    ) as run_search_entry:
        dialog_cls.return_value.select.return_value = 0
        dialog_cls.return_value.numeric.return_value = "abc"

        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "tv",
                "media_type": "tv",
                "query": "Breaking Bad",
                "ids": json.dumps({"tmdb_id": "1396"}),
                "tv_data": json.dumps({"name": "Episode 5", "season": 1, "episode": 5}),
            }
        )

    notification.assert_called_once()
    run_search_entry.assert_not_called()


def test_tmdb_episode_search_modes_returns_early_for_non_tv_mode():
    with patch("lib.search.run_search_entry") as run_search_entry:
        TmdbClient.tmdb_episode_search_modes(
            {
                "mode": "movies",
                "media_type": "movie",
                "query": "Inception",
                "ids": json.dumps({"tmdb_id": "27205"}),
                "tv_data": json.dumps({}),
            }
        )

    run_search_entry.assert_not_called()
