from __future__ import annotations

import json
from typing import Any
from urllib.parse import urljoin, urlparse
from urllib.request import Request, urlopen

from jarvis_gateway.adapters.base import BaseAdapter
from jarvis_gateway.adapters.autoshorts_sanitizer import sanitize_autoshorts_status
from jarvis_gateway.contracts import ModuleId, ModuleSnapshot, SourceType, utcnow
from jarvis_gateway.redaction import redact_error_message

ALLOWED_ENDPOINTS = ("/api/dashboard/summary", "/api/health")


class AutoShortsLiveReadonlyAdapter(BaseAdapter):
    module_id = ModuleId.AUTOSHORTS
    title = "AutoShorts"

    def __init__(self, base_url: str | None, timeout_seconds: float = 3) -> None:
        self.base_url = (base_url or "").rstrip("/")
        self.timeout_seconds = timeout_seconds

    def get_snapshot(self) -> ModuleSnapshot:
        now = utcnow()
        if not _safe_local_base_url(self.base_url):
            return sanitize_autoshorts_status({"reachable": False}, source_type=SourceType.HTTP_API, last_attempt_at=now, error="AUTOSHORTS_API_BASE_URL must be localhost for live_readonly")
        try:
            summary = self._get_json("/api/dashboard/summary")
            health = self._get_json("/api/health", required=False)
            raw = self._map_summary(summary, health)
            return sanitize_autoshorts_status(raw, source_type=SourceType.HTTP_API, last_attempt_at=now)
        except Exception as exc:  # noqa: BLE001 - fail closed
            return sanitize_autoshorts_status({"reachable": False}, source_type=SourceType.HTTP_API, last_attempt_at=now, error=redact_error_message(str(exc)))

    def _get_json(self, endpoint: str, *, required: bool = True) -> dict[str, Any]:
        if endpoint not in ALLOWED_ENDPOINTS:
            raise ValueError("endpoint not allowlisted")
        url = urljoin(self.base_url + "/", endpoint.lstrip("/"))
        req = Request(url, method="GET", headers={"Accept": "application/json"})
        try:
            with urlopen(req, timeout=self.timeout_seconds) as response:  # nosec - localhost allowlist enforced
                data = json.loads(response.read().decode("utf-8"))
                return data if isinstance(data, dict) else {}
        except Exception:
            if required:
                raise
            return {}

    def _map_summary(self, summary: dict[str, Any], health: dict[str, Any]) -> dict[str, Any]:
        raw_pipeline = summary.get("current_content_pipeline")
        pipeline: dict[str, Any] = raw_pipeline if isinstance(raw_pipeline, dict) else {}
        in_production = _safe_int(pipeline.get("in_production"))
        produced = _safe_int(pipeline.get("produced"))
        failed = _safe_int(summary.get("failed_actions"))
        if failed:
            last_status = "failed"
        elif in_production:
            last_status = "planning"
        elif produced:
            last_status = "ready"
        else:
            last_status = "review"
        return {
            "reachable": True,
            "pending_review_count": summary.get("ready_for_approval", 0),
            "ready_preview_count": summary.get("needs_metadata", 0),
            "failed_pipeline_count": failed,
            "last_pipeline_status": last_status,
            "pipeline_freshness": "unknown",
            "publishing_status_category": "review_needed" if summary.get("scheduled_private_uploads", 0) or summary.get("ready_for_approval", 0) else "not_ready",
            "last_success_at": utcnow().isoformat(),
        }


def _safe_local_base_url(base_url: str) -> bool:
    parsed = urlparse(base_url)
    return parsed.scheme == "http" and parsed.hostname in {"127.0.0.1", "localhost"}


def _safe_int(value: Any) -> int:
    if isinstance(value, bool):
        return 0
    if isinstance(value, int):
        return max(0, min(value, 999))
    if isinstance(value, str) and value.isdigit():
        return max(0, min(int(value), 999))
    return 0
