"""Local disk cache for API responses — avoids re-fetching during fit/transform cycles."""

from __future__ import annotations

import hashlib
import json
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

# Cache entries older than this for recent data are considered stale.
# Historical data (>30 days old) is cached indefinitely.
DEFAULT_TTL_HOURS = 1


def _cache_dir() -> Path:
    """Return the default cache directory, creating it if needed."""
    d = Path.home() / ".cache" / "therminal"
    d.mkdir(parents=True, exist_ok=True)
    return d


def _cache_key(station: str, endpoint: str, params: dict[str, Any]) -> str:
    """Generate a deterministic cache key from request parameters."""
    blob = json.dumps({"station": station, "endpoint": endpoint, **params}, sort_keys=True)
    return hashlib.sha256(blob.encode()).hexdigest()[:16]


def get_cached(
    station: str,
    endpoint: str,
    params: dict[str, Any],
    ttl_hours: int = DEFAULT_TTL_HOURS,
) -> list[dict[str, Any]] | None:
    """Return cached response or None if not cached / stale."""
    key = _cache_key(station, endpoint, params)
    path = _cache_dir() / f"{key}.json"
    if not path.exists():
        return None

    envelope = json.loads(path.read_text())

    # Check TTL for freshness
    fetched_at_str = envelope.get("fetched_at")
    if fetched_at_str is not None:
        fetched_at = datetime.fromisoformat(fetched_at_str)
        age_hours = (datetime.now(UTC) - fetched_at).total_seconds() / 3600
        if age_hours > ttl_hours:
            return None

    return envelope.get("data")  # type: ignore[no-any-return]


def set_cached(
    station: str, endpoint: str, params: dict[str, Any], data: list[dict[str, Any]]
) -> None:
    """Write response to cache with timestamp."""
    key = _cache_key(station, endpoint, params)
    path = _cache_dir() / f"{key}.json"
    envelope = {
        "fetched_at": datetime.now(UTC).isoformat(),
        "data": data,
    }
    path.write_text(json.dumps(envelope))


def clear_cache() -> int:
    """Remove all cached files. Returns count of files removed."""
    d = _cache_dir()
    count = 0
    for f in d.glob("*.json"):
        f.unlink()
        count += 1
    return count
