"""URL helpers and programme label formatting."""
from __future__ import annotations

import datetime as _dt
import os
import re
import sys
import urllib.parse
from typing import Any

from xbmcaddon import Addon

from .constants import ADDON_ID, CHANNEL_LOGO_WIDTH

# Package display names from VodPackages → artwork filenames (Antik+ TV app drawables).
_VOD_PACKAGE_ART: dict[str, str] = {
    "NG Now": "package_vod_national_now.jpg",
    "O Košiciach": "package_vod_about_kosice.jpg",
    "NOVINKY": "package_vod_novinky.jpg",
    "Pre deti": "package_vod_for_kids.jpg",
    "ANTIK Film": "package_vod_antik_film.jpg",
    "PLAY tv Deti": "package_vod_play_tv_kids.jpg",
    "PLAY tv Doku": "package_vod_play_tv_doku.jpg",
    "PLAY tv Film": "package_vod_play_tv_film.jpg",
    "BBC": "package_vod_bbc.jpg",
    "AXN Now": "package_vod_axn_now.jpg",
    "Koncerty": "package_vod_concerts.jpg",
    "Filmy ENG": "package_vod_movies_eng.jpg",
    "Dokumenty": "package_vod_documents.jpg",
    "Viasat World": "package_vod_viasat_world.jpg",
    "FilmBox ON": "package_vod_filmbox.jpg",
    "Fitnes": "package_vod_fitness.jpg",
}

_TIMEZONE_RE = re.compile(r"([+-]\d{2}:?\d{2}|Z)$")
_TZ_SUFFIX_RE = re.compile(r"([+-]\d{4}|Z)$")


def parse_plugin_params() -> dict[str, str]:
    if len(sys.argv) < 3:
        return {}
    raw = (sys.argv[2] or "").strip()
    if not raw or raw in ("?", "/"):
        return {}
    if raw.startswith("plugin://"):
        parsed = urllib.parse.urlparse(raw)
        query = parsed.query
    elif raw.startswith("?"):
        query = raw[1:]
    elif raw.startswith("/"):
        query = raw[1:]
    else:
        query = raw
    return {
        k: v
        for k, v in urllib.parse.parse_qsl(query, keep_blank_values=False)
    }


def upgrade_channel_logo_url(url: str, width: int = CHANNEL_LOGO_WIDTH) -> str:
    """Request higher-resolution Antik channel logos (?w=50 -> ?w=512)."""
    text = (url or "").strip()
    if not text:
        return text
    if "w=" in text:
        return re.sub(r"w=\d+", f"w={width}", text, count=1)
    sep = "&" if "?" in text else "?"
    return f"{text}{sep}w={width}"


def archive_days_from_channel(channel: dict[str, Any]) -> int:
    """Per-channel archive retention in days from middleware/Antik API."""
    for key in ("archive_days", "archiveDays"):
        try:
            days = int(channel.get(key) or 0)
        except (TypeError, ValueError):
            continue
        if days > 0:
            return min(days, 90)
    return 0


def build_url(**kwargs: Any) -> str:
    params = {k: str(v) for k, v in kwargs.items() if v is not None and v != ""}
    query = urllib.parse.urlencode(params, quote_via=urllib.parse.quote)
    return f"plugin://{ADDON_ID}/?{query}"


def build_play_url(channel: str, start: str, stop: str) -> str:
    """Canonical play URL used as Kodi bookmark key across all entry points."""
    return build_url(action="play", channel=channel, start=start, stop=stop)


def build_vod_play_url(movie_id: int, title: str = "") -> str:
    """Canonical VOD play URL used as Kodi bookmark key."""
    return build_url(action="vod_play", movie_id=movie_id, title=title or "")


def vod_item_art(
    item: dict[str, Any],
    data: dict[str, Any] | None = None,
    middleware_base: str = "",
    api: Any | None = None,
) -> dict[str, str]:
    """Poster/thumb from middleware proxy path or img_url template."""
    image = str(item.get("image") or "").strip()
    movie_id = item.get("id")
    if image.startswith("/") and api is not None:
        image = api.authenticated_url(image)
    elif image.startswith("/") and middleware_base:
        image = f"{middleware_base.rstrip('/')}{image}"
    elif not image and movie_id is not None and api is not None:
        image = api.authenticated_url(f"/api/v1/vod/poster/{movie_id}")
    elif not image and movie_id is not None and middleware_base:
        image = f"{middleware_base.rstrip('/')}/api/v1/vod/poster/{movie_id}"
    elif not image:
        tpl = str((data or {}).get("img_url") or "").strip()
        if tpl and movie_id is not None:
            if "%d" in tpl:
                image = tpl.replace("%d", str(movie_id))
            elif "{id}" in tpl:
                image = tpl.replace("{id}", str(movie_id))
    return {"thumb": image, "poster": image, "icon": image}


def vod_package_art(package_name: str) -> dict[str, str] | None:
    """Bundled provider logos matching the Antik+ TV VOD dashboard."""
    filename = _VOD_PACKAGE_ART.get(package_name.strip(), "package_default.png")
    addon = Addon(ADDON_ID)
    path = os.path.join(addon.getAddonInfo("path"), "resources", "media", "packages", filename)
    if not os.path.isfile(path):
        path = os.path.join(addon.getAddonInfo("path"), "resources", "media", "packages", "package_default.png")
    if os.path.isfile(path):
        return {"thumb": path, "icon": path, "poster": path}
    return None


def vod_item_label(item: dict[str, Any]) -> str:
    title = str(item.get("display_title") or item.get("title") or "Item").strip()
    meta = str(item.get("meta") or "").strip()
    if meta:
        return f"{title} [{meta}]"
    return title


def _date_part(start: str) -> str:
    if not start:
        return ""
    if "T" in start:
        return start.split("T", 1)[0]
    if " " in start:
        return start.split(" ", 1)[0]
    return start[:10]


def format_epg_date(start: str) -> str:
    date_part = _date_part(start)
    parts = date_part.split("-")
    if len(parts) >= 3:
        try:
            return f"{int(parts[2]):02d}. {int(parts[1]):02d}. {parts[0]}"
        except ValueError:
            pass
    return date_part


def format_epg_time(start: str) -> str:
    if not start:
        return ""
    value = start.strip()
    if "T" in value:
        time_part = value.split("T", 1)[1]
    elif " " in value:
        time_part = value.split(" ", 1)[1]
    else:
        return ""

    time_part = _TIMEZONE_RE.sub("", time_part)
    parts = time_part.split(":")
    if len(parts) >= 2:
        try:
            return f"{int(parts[0]):02d}:{int(parts[1]):02d}"
        except ValueError:
            return f"{parts[0]}:{parts[1]}"
    return ""


def format_duration(seconds: float) -> str:
    total = max(0, int(seconds))
    hours, rem = divmod(total, 3600)
    minutes, secs = divmod(rem, 60)
    if hours:
        return f"{hours}:{minutes:02d}:{secs:02d}"
    return f"{minutes}:{secs:02d}"


def _parse_timezone(tz_text: str) -> _dt.tzinfo | None:
    if tz_text == "Z":
        return _dt.timezone.utc
    try:
        sign = 1 if tz_text[0] == "+" else -1
        hours = int(tz_text[1:3])
        minutes = int(tz_text[3:5])
        return _dt.timezone(sign * _dt.timedelta(hours=hours, minutes=minutes))
    except (ValueError, IndexError):
        return None


def _parse_antik_datetime(value: Any) -> Any:
    """Parse Antik ISO timestamps without strptime (Kodi may break datetime.strptime)."""
    if not isinstance(value, str):
        return None
    text = value.strip()
    if not text:
        return None

    text = re.sub(r"([+-]\d{2}):(\d{2})$", r"\1\2", text)
    if "T" in text:
        date_part, rest = text.split("T", 1)
    elif " " in text:
        date_part, rest = text.split(" ", 1)
    else:
        return None

    try:
        year, month, day = (int(part) for part in date_part.split("-", 2))
    except (ValueError, TypeError):
        return None

    tzinfo = None
    tz_match = _TZ_SUFFIX_RE.search(rest)
    if tz_match:
        tzinfo = _parse_timezone(tz_match.group(1))
        time_part = rest[: tz_match.start()]
    else:
        time_part = rest

    try:
        time_bits = time_part.split(":")
        hour = int(time_bits[0])
        minute = int(time_bits[1]) if len(time_bits) > 1 else 0
        second = int(float(time_bits[2])) if len(time_bits) > 2 else 0
    except (ValueError, TypeError, IndexError):
        return None

    try:
        return _dt.datetime(year, month, day, hour, minute, second, tzinfo=tzinfo)
    except ValueError:
        return None


def programme_duration_seconds(start: Any, stop: Any) -> int:
    start_dt = _parse_antik_datetime(start)
    stop_dt = _parse_antik_datetime(stop)
    if not start_dt or not stop_dt:
        return 0
    return max(0, int((stop_dt - start_dt).total_seconds()))


def show_label(start: str, title: str) -> str:
    """Stations flow: '05:10 football'."""
    clock = format_epg_time(start)
    return f"{clock} {title}" if clock else title


def archive_list_label(title: str, station_name: str, start: str) -> str:
    """Genres/Search playable: 'Gladiator (HBO, 22. 05. 2026 22:30)'."""
    station = station_name.strip()
    date_s = format_epg_date(start)
    time_s = format_epg_time(start)
    return f"{title} ({station}, {date_s} {time_s})"


def history_list_label(
    title: str,
    station_name: str,
    start: str,
    series_title: str = "",
) -> str:
    """History: movie or episode with optional series title."""
    station = station_name.strip()
    date_s = format_epg_date(start)
    time_s = format_epg_time(start)
    show = (series_title or "").strip()
    if show:
        return f"{title} ({show}, {station}, {date_s} {time_s})"
    return f"{title} ({station} {date_s} {time_s})"


def vod_history_list_label(
    title: str,
    series_title: str = "",
    meta: str = "",
    year: str = "",
) -> str:
    """VOD history: movie or episode with optional series and meta."""
    show = (series_title or "").strip()
    suffix = (meta or "").strip()
    year_s = (year or "").strip()
    if show:
        base = f"{title} ({show})"
    else:
        base = title
    if suffix:
        base = f"{base} [{suffix}]"
    if year_s:
        base = f"{base} ({year_s})"
    return base
