from __future__ import annotations

"""HTTP floor-games sync — Pi serves JSON; OHD Win11 fetches at startup."""

import json
import urllib.error
import urllib.request
from datetime import datetime, timezone
from typing import Any, Dict, Optional, Sequence, Tuple

from ohd_progressive_modes import (
    parse_progressive_floor_games,
    sanitize_progressive_floor_games,
)

FLOOR_GAMES_JSON = "floor-games.json"
HTTP_FETCH_TIMEOUT_S = 5.0
SOURCE_P3 = "p3_gamestats"
SOURCE_CONFIG = "config"


def _utc_now_iso() -> str:
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def floor_games_url_from_progressives_source(progressives_source: str) -> str:
    """Derive floor-games.json URL from progressives.csv URL."""
    source = progressives_source.strip()
    if source.lower().endswith("progressives.csv"):
        return source[: -len("progressives.csv")] + FLOOR_GAMES_JSON
    if source.rstrip("/").lower().endswith("/ethergold"):
        return source.rstrip("/") + "/" + FLOOR_GAMES_JSON
    base = source.rsplit("/", 1)[0]
    return f"{base}/EtherGold/{FLOOR_GAMES_JSON}"


def build_floor_games_payload(
    *,
    version: str,
    config,
    p3_floor_games: Optional[Sequence[int]] = None,
    p3_loaded: bool = False,
    p3_black_gold_21: Optional[bool] = None,
) -> Dict[str, Any]:
    """Build JSON body for GET /EtherGold/floor-games.json on the Pi."""
    if p3_loaded and p3_floor_games is not None:
        bg21 = bool(p3_black_gold_21) if p3_black_gold_21 is not None else False
        floor_games = sanitize_progressive_floor_games(
            p3_floor_games,
            black_gold_21_enabled=bg21,
        )
        source = SOURCE_P3
    else:
        bg21 = (
            config.getboolean("TOPBOX", "BLACK_GOLD_21_ENABLED")
            if config.has_option("TOPBOX", "BLACK_GOLD_21_ENABLED")
            else False
        )
        floor_raw = (
            config.get("TOPBOX", "PROGRESSIVE_FLOOR_GAMES")
            if config.has_option("TOPBOX", "PROGRESSIVE_FLOOR_GAMES")
            else ""
        )
        floor_games = parse_progressive_floor_games(
            floor_raw,
            black_gold_21_enabled=bg21,
        )
        source = SOURCE_CONFIG

    return {
        "version": version,
        "progressive_floor_games": list(floor_games),
        "black_gold_21_enabled": bg21,
        "source": source,
        "updated_utc": _utc_now_iso(),
    }


def fetch_remote_floor_games(
    url: str,
    *,
    timeout_s: float = HTTP_FETCH_TIMEOUT_S,
) -> Tuple[
    Optional[Tuple[int, ...]],
    Optional[bool],
    Optional[str],
    Optional[str],
    Optional[str],
]:
    """
    Fetch floor-games.json from the office Pi / Master.

    Returns (floor_games, black_gold_21_enabled, remote_version, source, error_message).
    """
    request = urllib.request.Request(
        url,
        headers={"Accept": "application/json"},
    )
    try:
        with urllib.request.urlopen(request, timeout=timeout_s) as response:
            body = response.read().decode("utf-8")
    except urllib.error.HTTPError as exc:
        return None, None, None, None, f"HTTP {exc.code} for {url}"
    except (OSError, urllib.error.URLError, TimeoutError) as exc:
        return None, None, None, None, f"fetch failed for {url}: {exc}"

    try:
        data = json.loads(body)
    except json.JSONDecodeError as exc:
        return None, None, None, None, f"invalid JSON from {url}: {exc}"

    if not isinstance(data, dict):
        return None, None, None, None, f"invalid payload from {url}: expected object"

    raw_games = data.get("progressive_floor_games")
    if not isinstance(raw_games, list):
        return None, None, None, None, f"missing progressive_floor_games in {url}"

    bg21 = bool(data.get("black_gold_21_enabled", False))
    source = str(data.get("source") or SOURCE_CONFIG)
    floor_games = sanitize_progressive_floor_games(
        [int(g) for g in raw_games],
        black_gold_21_enabled=bg21,
    )
    remote_version = data.get("version")
    if remote_version is not None:
        remote_version = str(remote_version)
    return floor_games, bg21, remote_version, source, None
