from __future__ import annotations

import re

from plugin_interface import BasisPlugin
from tmdb import TmdbCastMember

METADATA_MODE_AUTO = 0
METADATA_MODE_SOURCE = 1
METADATA_MODE_TMDB = 2
METADATA_MODE_MIX = 3


def metadata_setting_id(plugin_name: str) -> str:
    safe = re.sub(r"[^a-z0-9]+", "_", (plugin_name or "").strip().casefold()).strip("_")
    return f"{safe}_metadata_source" if safe else "metadata_source"


def plugin_supports_metadata(plugin: BasisPlugin) -> bool:
    try:
        return plugin.__class__.metadata_for is not BasisPlugin.metadata_for
    except Exception:
        return False


def metadata_policy(
    plugin_name: str,
    plugin: BasisPlugin,
    *,
    allow_tmdb: bool,
    get_setting_int=None,
) -> tuple[bool, bool, bool]:
    if not callable(get_setting_int):
        return plugin_supports_metadata(plugin), allow_tmdb, bool(getattr(plugin, "prefer_source_metadata", False))
    mode = get_setting_int(metadata_setting_id(plugin_name), default=METADATA_MODE_AUTO)
    supports_source = plugin_supports_metadata(plugin)
    if mode == METADATA_MODE_SOURCE:
        return supports_source, False, True
    if mode == METADATA_MODE_TMDB:
        return False, allow_tmdb, False
    if mode == METADATA_MODE_MIX:
        return supports_source, allow_tmdb, True
    prefer_source = bool(getattr(plugin, "prefer_source_metadata", False))
    return supports_source, allow_tmdb, prefer_source


def collect_plugin_metadata(
    plugin: BasisPlugin,
    titles: list[str],
) -> dict[str, tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None]]:
    getter = getattr(plugin, "metadata_for", None)
    if not callable(getter):
        return {}
    collected: dict[str, tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None]] = {}
    for title in titles:
        try:
            labels, art, cast = getter(title)
        except Exception:
            continue
        if isinstance(labels, dict) or isinstance(art, dict) or cast:
            label_map = {str(k): str(v) for k, v in dict(labels or {}).items() if v}
            art_map = {str(k): str(v) for k, v in dict(art or {}).items() if v}
            collected[title] = (label_map, art_map, cast if isinstance(cast, list) else None)
    return collected


def needs_tmdb(labels: dict[str, str], art: dict[str, str], *, want_plot: bool, want_art: bool) -> bool:
    if want_plot and not labels.get("plot"):
        return True
    if want_art and not (art.get("thumb") or art.get("poster") or art.get("fanart") or art.get("landscape")):
        return True
    return False


def merge_metadata(
    title: str,
    tmdb_labels: dict[str, str] | None,
    tmdb_art: dict[str, str] | None,
    tmdb_cast: list[TmdbCastMember] | None,
    plugin_meta: tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None] | None,
) -> tuple[dict[str, str], dict[str, str], list[TmdbCastMember] | None]:
    labels = dict(tmdb_labels or {})
    art = dict(tmdb_art or {})
    cast = tmdb_cast
    if plugin_meta is not None:
        meta_labels, meta_art, meta_cast = plugin_meta
        labels.update({k: str(v) for k, v in dict(meta_labels or {}).items() if v})
        art.update({k: str(v) for k, v in dict(meta_art or {}).items() if v})
        if meta_cast is not None:
            cast = meta_cast
    if "title" not in labels:
        labels["title"] = title
    return labels, art, cast
