from __future__ import annotations

import json
from typing import Any

from datahub.db import HubDB
from datahub.timeutil import isoformat, now_shanghai


class LastKnownGood:
    def __init__(self, db: HubDB) -> None:
        self.db = db

    def store(self, cache_key: str, payload: Any, source: str) -> None:
        self.db.execute(
            """
            INSERT INTO last_known_good(cache_key, payload, source, stored_at)
            VALUES (?, ?, ?, ?)
            ON CONFLICT(cache_key) DO UPDATE SET
              payload=excluded.payload, source=excluded.source, stored_at=excluded.stored_at
            """,
            (cache_key, json.dumps(payload, ensure_ascii=False), source, isoformat()),
        )

    def load(self, cache_key: str) -> dict[str, Any] | None:
        row = self.db.fetchone("SELECT * FROM last_known_good WHERE cache_key = ?", (cache_key,))
        if not row:
            return None
        return {
            "payload": json.loads(row["payload"]),
            "source": row["source"],
            "stored_at": row["stored_at"],
        }

    def put_rt(self, cache_key: str, payload: Any, source: str, ttl_seconds: int) -> None:
        now = now_shanghai()
        expires = isoformat(now.replace(microsecond=0))
        # expires_at stored as iso; compute by adding ttl via timestamp
        from datetime import timedelta

        self.db.execute(
            """
            INSERT INTO rt_cache(cache_key, payload, source, stored_at, expires_at)
            VALUES (?, ?, ?, ?, ?)
            ON CONFLICT(cache_key) DO UPDATE SET
              payload=excluded.payload, source=excluded.source,
              stored_at=excluded.stored_at, expires_at=excluded.expires_at
            """,
            (
                cache_key,
                json.dumps(payload, ensure_ascii=False),
                source,
                isoformat(now),
                isoformat(now + timedelta(seconds=ttl_seconds)),
            ),
        )
        self.store(cache_key, payload, source)

    def get_rt(self, cache_key: str, max_stale_seconds: int | None = None) -> dict[str, Any] | None:
        row = self.db.fetchone("SELECT * FROM rt_cache WHERE cache_key = ?", (cache_key,))
        if not row:
            lkg = self.load(cache_key)
            if not lkg:
                return None
            return {**lkg, "stale": True}
        stored_at = row["stored_at"]
        expired = row["expires_at"] < isoformat()
        result = {
            "payload": json.loads(row["payload"]),
            "source": row["source"],
            "stored_at": stored_at,
            "stale": expired,
        }
        if expired and max_stale_seconds is not None:
            from datetime import datetime

            try:
                stored = datetime.fromisoformat(stored_at)
                age = (now_shanghai() - stored).total_seconds()
            except ValueError:
                age = max_stale_seconds + 1
            if age > max_stale_seconds:
                return None
        return result
