#!/usr/bin/env python3
"""Floor-games JSON cache for EtherGold HTTP (OHD Win11 startup fetch)."""
from __future__ import annotations

import json
import os
from datetime import datetime, timezone
from typing import Any, Dict, Optional, Sequence, Tuple

from pathlib import Path

from p3_gamestats import (
    BLACK_GOLD_21_GAME_ID,
    MAX_FLOOR_PROGRESSIVE_GAMES,
    MAX_FLOOR_PROGRESSIVE_GAMES_WITH_BG21,
)

FLOOR_GAMES_JSON = "floor-games.json"
SOURCE_P3 = "p3_gamestats"
SOURCE_CONFIG = "config"
SOURCE_CACHE = "cache"


def _read_eg_version() -> str:
    """Track tip VERSION.txt (same stamp as EG_VERSION). Avoid importing pog422_core
    here — that pulls fcntl and breaks Windows unit tests."""
    path = Path(__file__).resolve().parent / "VERSION.txt"
    try:
        text = path.read_text(encoding="utf-8").strip().splitlines()[0].strip()
    except OSError:
        return "unknown"
    return text or "unknown"


# Alias only — HTTP is not a separately shipped product. Never hardcode.
HTTP_BUILD = _read_eg_version()


def _utc_now_iso() -> str:
    return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def default_floor_games_path(ethergold_root: str | None = None) -> str:
    root = ethergold_root or os.environ.get("ETHERGOLD_ROOT", "/home/topbox/EtherGold")
    return os.path.join(root, FLOOR_GAMES_JSON)


def _progressive_capable_game_ids() -> Tuple[int, ...]:
    return tuple(g for g in range(1, 17) if g != BLACK_GOLD_21_GAME_ID)


def parse_progressive_floor_games(
    raw: str,
    *,
    black_gold_21_enabled: bool,
) -> Tuple[int, ...]:
    """Parse an explicit floor list. Empty input → empty tuple (never invent 1–12)."""
    max_count = (
        MAX_FLOOR_PROGRESSIVE_GAMES_WITH_BG21
        if black_gold_21_enabled
        else MAX_FLOOR_PROGRESSIVE_GAMES
    )
    capable = set(_progressive_capable_game_ids())

    if not raw.strip():
        return ()

    parsed: list[int] = []
    for part in raw.split(","):
        text = part.strip()
        if not text:
            continue
        game_id = int(text)
        if game_id == BLACK_GOLD_21_GAME_ID:
            continue
        if game_id not in capable:
            continue
        if game_id not in parsed:
            parsed.append(game_id)
    games = tuple(parsed)
    if len(games) > max_count:
        games = games[:max_count]
    return games


def _config_from_env() -> Tuple[Tuple[int, ...], bool]:
    bg21 = os.environ.get("PROGRESSIVE_BLACK_GOLD_21", "").strip().lower() in (
        "1",
        "true",
        "yes",
        "on",
    )
    raw = os.environ.get("PROGRESSIVE_FLOOR_GAMES", "").strip()
    return parse_progressive_floor_games(raw, black_gold_21_enabled=bg21), bg21


def build_floor_games_payload(
    *,
    progressive_floor_games: Sequence[int],
    black_gold_21_enabled: bool,
    source: str,
    version: str = HTTP_BUILD,
) -> Dict[str, Any]:
    return {
        "version": version,
        "progressive_floor_games": [int(g) for g in progressive_floor_games],
        "black_gold_21_enabled": bool(black_gold_21_enabled),
        "source": source,
        "updated_utc": _utc_now_iso(),
    }


def build_payload_from_p3(
    progressive_floor_games: Sequence[int],
    *,
    black_gold_21_enabled: bool,
) -> Dict[str, Any]:
    return build_floor_games_payload(
        progressive_floor_games=progressive_floor_games,
        black_gold_21_enabled=black_gold_21_enabled,
        source=SOURCE_P3,
    )


def build_payload_from_config() -> Dict[str, Any]:
    floor_games, bg21 = _config_from_env()
    return build_floor_games_payload(
        progressive_floor_games=floor_games,
        black_gold_21_enabled=bg21,
        source=SOURCE_CONFIG,
    )


def load_cached_payload(path: str | None = None) -> Optional[Dict[str, Any]]:
    cache_path = path or default_floor_games_path()
    if not os.path.isfile(cache_path):
        return None
    try:
        with open(cache_path, encoding="utf-8") as handle:
            payload = json.load(handle)
        if isinstance(payload, dict) and payload.get("progressive_floor_games"):
            return payload
    except (OSError, ValueError, json.JSONDecodeError):
        pass
    return None


def save_cached_payload(payload: Dict[str, Any], path: str | None = None) -> str:
    cache_path = path or default_floor_games_path()
    directory = os.path.dirname(cache_path) or "."
    os.makedirs(directory, exist_ok=True)
    tmp_path = f"{cache_path}.tmp"
    with open(tmp_path, "w", encoding="utf-8") as handle:
        json.dump(payload, handle, indent=2)
        handle.write("\n")
    os.replace(tmp_path, cache_path)
    return cache_path


def resolve_serve_payload(path: str | None = None) -> Dict[str, Any]:
    cached = load_cached_payload(path)
    if cached is not None:
        cached = dict(cached)
        cached.setdefault("source", SOURCE_CACHE)
        cached.setdefault("version", HTTP_BUILD)
        return cached
    return build_payload_from_config()
