"""Jellyseerr stats provider — request counts + recent requests.

Jellyseerr is an optional companion of the Jellyfin service (config lives on
the Jellyfin instance as ``jellyseerr_url`` / ``jellyseerr_api_key``). This
provider is registered for ``service_type == "jellyfin"`` and returns the
headline request stats (total / pending / approved / declined / processing /
available) plus a recent-requests list.

To avoid several widgets + the Requests tab each hitting Jellyseerr, one
authenticated client is reused per service (lru_cache) and the stats result is
cached for a short TTL with a lock — the same pattern the qBittorrent client
uses to keep a single-threaded upstream from being hammered.
"""

from __future__ import annotations

import logging
import threading
import time
from functools import lru_cache
from typing import Any

from media_library_viewer_api.clients.jellyseerr import JellyseerrClient
from media_library_viewer_api.widgets.stats_provider import (
    StatsResult,
    StatValue,
    register_stats_provider,
)

logger = logging.getLogger(__name__)

# Short-TTL cache: multiple widgets + the tab collapse onto one Jellyseerr fetch.
JS_STATS_CACHE_TTL = 10.0

# (stat key, display label) — order is the overview/grid order.
_JELLYSEERR_STATS: list[tuple[str, str]] = [
    ("total", "Total"),
    ("pending", "Pending"),
    ("approved", "Approved"),
    ("declined", "Declined"),
    ("processing", "Processing"),
    ("available", "Available"),
]


@lru_cache(maxsize=16)
def _jellyseer_client(cache_key: tuple[str, str, str]) -> JellyseerrClient:
    """Reuse one authenticated client per (service, url, api_key)."""
    _service_id, base_url, api_key = cache_key
    return JellyseerrClient(base_url, api_key)


class JellyseerrStatsProvider:
    """StatsProvider backed by Jellyseerr /api/v1/request/count + /api/v1/request."""

    def __init__(self, ttl: float = JS_STATS_CACHE_TTL) -> None:
        self._ttl = ttl
        self._cache: dict[str, tuple[float, StatsResult]] = {}
        self._lock = threading.Lock()

    def fetch_stats(self, service: Any) -> StatsResult:
        base_url = str(service.config.get("jellyseerr_url") or "")
        # jellyseerr_api_key is migrating config -> secret; accept either during the transition.
        api_key = str(
            (service.secrets or {}).get("jellyseerr_api_key") or service.config.get("jellyseerr_api_key") or ""
        )
        if not base_url or not api_key:
            return StatsResult(
                stats=[],
                detail="Jellyseerr is not configured for this Jellyfin instance "
                "(set jellyseerr_url + jellyseerr_api_key on the Jellyfin service).",
            )

        now = time.time()
        with self._lock:
            hit = self._cache.get(service.id)
            if hit and (now - hit[0]) < self._ttl:
                return hit[1]

        try:
            client = _jellyseer_client((service.id, base_url, api_key))
            counts = client.request_count()
            recent = client.recent_requests(20)
        except Exception as exc:
            logger.warning("Jellyseerr stats fetch failed for %s: %s", service.id, exc)
            # Serve stale if we have it, else surface the error.
            if hit:
                return hit[1]
            return StatsResult(stats=[], detail=f"Jellyseerr fetch failed: {exc}")

        result = StatsResult(
            stats=[StatValue(key=key, label=label, value=int(counts.get(key, 0))) for key, label in _JELLYSEERR_STATS],
            recent=recent,
        )
        with self._lock:
            self._cache[service.id] = (time.time(), result)
        return result


register_stats_provider("jellyfin", JellyseerrStatsProvider())


def fetch_jellyseer_requests(service: Any) -> list[dict[str, Any]]:
    """Return Jellyseerr requests for the Requests tab table.

    Reuses the per-service cached client (shared with the stats widgets) so the
    tab and widgets don't each open a new session.
    """
    base_url = str(service.config.get("jellyseerr_url") or "")
    api_key = str((service.secrets or {}).get("jellyseerr_api_key") or service.config.get("jellyseerr_api_key") or "")
    if not base_url or not api_key:
        return []
    client = _jellyseer_client((service.id, base_url, api_key))
    return client.open_requests()
