"""DB-first unlock-calendar loader (with JSON fallback). Single source of truth for how every consumer
(the unlock sleeve + the Bybit edges/book evals) reads the cliff calendar.

The calendar moved off `unlock_calendar.json` on the single-node surfer-data PVC into the operational
`unlock_events` table (networked, node-agnostic). The loader reads from the DB when a repo is supplied and
its table is non-empty; otherwise it falls back to the JSON file (back-compat — so an un-migrated cluster,
or a fresh DB before the one-time import, still works). The events returned are byte-identical regardless
of source, so the unlock sleeve's results are identical whether it read the JSON or the DB. No network."""
from __future__ import annotations

import json
import logging
from pathlib import Path
from typing import Any

log = logging.getLogger(__name__)


def load_unlock_events(repo: Any | None, json_path: str | None) -> list[dict[str, Any]]:
    """Return the cliff calendar as [{"sym","cliff_day","n","cat"}].

    DB-first: if `repo` is supplied and its `unlock_events` table is non-empty, return those rows. Else fall
    back to `json_path` if it exists. Returns [] if neither source yields events (the unlock edge then
    reports N/A / is omitted by its caller, never fabricated)."""
    if repo is not None:
        try:
            if not repo.is_empty():
                return repo.read_events()
        except Exception as exc:  # noqa: BLE001 — a DB hiccup must fall back to the json, not crash the sleeve
            log.warning("unlock-calendar: DB read failed, falling back to json: %s", exc)
    if json_path:
        p = Path(json_path)
        if p.exists():
            try:
                return json.loads(p.read_text())
            except Exception as exc:  # noqa: BLE001 — a corrupt/absent json => empty calendar, not a crash
                log.warning("unlock-calendar: json read failed (%s): %s", json_path, exc)
    return []


def operational_unlock_repo(settings: Any) -> Any | None:
    """Build an UnlockCalendarRepo over the operational DSN, migrated (create-if-not-exists). Returns None
    if construction fails (e.g. DB unreachable) so callers degrade to the JSON fallback."""
    try:
        from fxhnt.adapters.persistence.unlock_calendar_repo import UnlockCalendarRepo
        repo = UnlockCalendarRepo(settings.operational_dsn)
        repo.migrate()
        return repo
    except Exception as exc:  # noqa: BLE001 — no DB => JSON fallback, never a crash on import
        log.warning("unlock-calendar: could not open operational repo, using json: %s", exc)
        return None
