"""草稿预览：未发布蓝图的内部可访问快照（供 /#/preview/{id} 与真页面截图）。"""
from __future__ import annotations

import json
import threading
import time
import uuid
from pathlib import Path
from typing import Any

_lock = threading.Lock()
_store: dict[str, dict[str, Any]] = {}
_TTL_SEC = 3600
_disk = (Path(__file__).resolve().parent / ".runtime" / "preview").resolve()
_alt_disk = (Path(__file__).resolve().parents[1] / ".runtime" / "preview").resolve()


def _preview_dirs() -> list[Path]:
    dirs = [_disk]
    if _alt_disk != _disk:
        dirs.append(_alt_disk)
    return dirs


def _purge() -> None:
    now = time.time()
    dead = [k for k, v in _store.items() if now - float(v.get("ts") or 0) > _TTL_SEC]
    for k in dead:
        _store.pop(k, None)
        for d in _preview_dirs():
            p = d / f"{k}.json"
            if p.is_file():
                try:
                    p.unlink()
                except OSError:
                    pass


def create_preview(
    blueprint: dict[str, Any],
    *,
    rows: list[dict[str, Any]] | None = None,
    resource: str = "",
) -> str:
    """写入预览包，返回 preview_id。"""
    pid = uuid.uuid4().hex[:12]
    res = resource
    if not res:
        apis = (blueprint.get("apis") or {}).get("resources") or []
        if apis and isinstance(apis[0], dict):
            res = str(apis[0].get("path") or "records").lstrip("/")
        else:
            res = "records"
    pack = {
        "id": pid,
        "ts": time.time(),
        "blueprint": blueprint,
        "rows": list(rows or [])[:800],
        "resource": res,
    }
    with _lock:
        _purge()
        _store[pid] = pack
        for d in _preview_dirs():
            try:
                d.mkdir(parents=True, exist_ok=True)
                (d / f"{pid}.json").write_text(
                    json.dumps(pack, ensure_ascii=False),
                    encoding="utf-8",
                )
            except OSError:
                continue
    return pid


def get_preview(preview_id: str) -> dict[str, Any] | None:
    pid = (preview_id or "").strip()
    if not pid:
        return None
    with _lock:
        _purge()
        pack = _store.get(pid)
        if pack:
            return pack
    for d in _preview_dirs():
        p = d / f"{pid}.json"
        if not p.is_file():
            continue
        try:
            pack = json.loads(p.read_text(encoding="utf-8"))
            if isinstance(pack, dict):
                with _lock:
                    _store[pid] = pack
                return pack
        except (OSError, json.JSONDecodeError):
            continue
    return None
