import json
from urllib.parse import quote

from lib.api.trakt.trakt_utils import add_trakt_watched_context_menu, is_trakt_auth
from lib.clients.tmdb.utils.utils import (
    add_tmdb_episode_context_menu,
    add_tmdb_show_context_menu,
    tmdb_get,
)
from lib.utils.general.utils import (
    execute_thread_pool_collection,
    get_fanart_details,
    set_content_type,
    set_media_infoTag,
)
from lib.utils.kodi.utils import (
    add_directory_items_batch,
    apply_section_view,
    build_url,
    end_of_directory,
    get_setting,
    kodilog,
    make_list_item,
)


def show_seasons_details(params):
    set_content_type("season")

    ids = json.loads(params.get("ids", "{}"))
    mode = params.get("mode", "")
    media_type = params.get("media_type", "")

    show_season_info(ids, mode, media_type)
    end_of_directory()
    apply_section_view("view.seasons", content_type="seasons")


def show_season_info(ids, mode, media_type):
    tmdb_id = ids.get("tmdb_id")
    tvdb_id = ids.get("tvdb_id")
    imdb_id = ids.get("imdb_id")

    if imdb_id:
        res = tmdb_get("find_by_imdb_id", imdb_id)
        if res and res.get("tv_results"):
            tmdb_id = res["tv_results"][0]["id"]

    ids = {"tmdb_id": tmdb_id, "tvdb_id": tvdb_id, "imdb_id": imdb_id}

    details = tmdb_get("tv_details", tmdb_id)
    name = details.name
    seasons = details.seasons
    fanart_details = get_fanart_details(tvdb_id=tvdb_id, mode=mode)

    results = execute_thread_pool_collection(
        seasons,
        _process_season,
        details,
        name,
        ids,
        mode,
        media_type,
        fanart_details,
    )

    # Sort by season number
    results.sort(key=lambda x: x[0])

    add_directory_items_batch(
        [(url, list_item, True) for _, url, list_item in results if list_item is not None]
    )


def _process_season(season, details, name, ids, mode, media_type, fanart_details):
    season_name = season.name
    overview = season.overview
    if not overview:
        season.update({"overview": getattr(details, "overview", "")})

    if "Miniseries" in season_name:
        season_name = "Season 1"

    season_number = season.season_number
    if season_number == 0 and not get_setting("include_tvshow_specials"):
        return  # skip specials if disabled

    list_item = make_list_item(label=season_name)
    set_media_infoTag(list_item, data=season, fanart_data=fanart_details, mode="season")
    list_item.setProperty("IsPlayable", "false")

    context_menu = add_tmdb_show_context_menu(mode, ids)
    if is_trakt_auth():
        context_menu += add_trakt_watched_context_menu("shows", season=season_number, ids=ids)
    list_item.addContextMenuItems(context_menu)

    url = build_url(
        "show_episodes_details",
        tv_name=name,
        ids=ids,
        mode=mode,
        media_type=media_type,
        season=season_number,
    )

    return (season_number, url, list_item)


def show_episodes_details(params):
    set_content_type("episode")

    tv_name = params.get("tv_name", "")
    season = int(params.get("season", 1))
    ids = json.loads(params.get("ids", "{}"))
    mode = params.get("mode", "")
    media_type = params.get("media_type", "")

    kodilog(
        f"[EPISODES] show_episodes_details: tv_name={tv_name!r}, season={season}, "
        f"mode={mode!r}, media_type={media_type!r}, ids={ids}"
    )
    item_count = show_episode_info(tv_name, season, ids, mode, media_type)
    kodilog(f"[EPISODES] show_episodes_details: added item_count={item_count}")
    end_of_directory()
    kodilog("[EPISODES] show_episodes_details: end_of_directory called")
    apply_section_view("view.episodes", content_type="episodes")


def show_episode_info(tv_name, season, ids, mode, media_type):
    season_details = tmdb_get("season_details", {"id": ids.get("tmdb_id"), "season": season})
    if not season_details:
        kodilog(
            f"[EPISODES] show_episode_info: no season_details for "
            f"tmdb_id={ids.get('tmdb_id')}, season={season}"
        )
        return 0

    episodes = getattr(season_details, "episodes", []) or []
    kodilog(
        f"[EPISODES] show_episode_info: fetched episodes_count={len(episodes)} "
        f"for tmdb_id={ids.get('tmdb_id')}, season={season}"
    )
    fanart_details = get_fanart_details(tvdb_id=ids.get("tvdb_id"), mode=mode)

    results = execute_thread_pool_collection(
        episodes,
        _process_episode,
        tv_name,
        season,
        ids,
        mode,
        media_type,
        fanart_details,
    )

    # Sort by episode number
    results.sort(key=lambda x: x[0])
    item_count = len([list_item for _, _, list_item in results if list_item is not None])
    kodilog(
        f"[EPISODES] show_episode_info: processed results_count={len(results)}, "
        f"item_count={item_count}"
    )

    add_directory_items_batch(
        [(url, list_item, False) for _, url, list_item in results if list_item is not None]
    )
    return item_count


def _process_episode(episode, tv_name, season, ids, mode, media_type, fanart_details):
    ep_name = episode.name
    episode_number = episode.episode_number

    tv_data = {"name": quote(ep_name), "episode": episode_number, "season": season}

    list_item = make_list_item(label=f"{season}x{episode_number}. {ep_name}")
    list_item.setProperty("IsPlayable", "true")
    set_media_infoTag(list_item, data=episode, fanart_data=fanart_details, mode="episode")

    context_menu = add_tmdb_episode_context_menu(mode, tv_name, tv_data, ids)
    if is_trakt_auth():
        context_menu += add_trakt_watched_context_menu(
            "shows", season=season, episode=episode_number, ids=ids
        )
    list_item.addContextMenuItems(context_menu)

    url = build_url(
        "search",
        mode=mode,
        media_type=media_type,
        query=tv_name,
        ids=ids,
        tv_data=tv_data,
    )

    return (episode_number, url, list_item)
