"""Per-user Generation History storage.

Every generate/refine attempt gets a history entry: created as "generating",
then flipped to "done" (with the resulting svg) or "failed" (with the error
message). Entries older than HISTORY_TTL_HOURS are dropped automatically
every time the store is read or written, so history never needs a manual
cleanup job — it just quietly clears itself after 24 hours.

Plain JSON file storage (no database needed), same pattern as users_store.py.
Storage lives at CONFIG_DIR/history.json, next to config.json and users.json.
"""
from __future__ import annotations

import json
import threading
import uuid
from datetime import datetime, timedelta, timezone

import app_config

HISTORY_FILE = app_config.CONFIG_DIR / "history.json"
HISTORY_TTL_HOURS = int(__import__("os").environ.get("HISTORY_TTL_HOURS", "24"))
MAX_ENTRIES_PER_USER = 200  # hard cap so one heavy user can't bloat the file forever

_lock = threading.Lock()


def _now() -> datetime:
    return datetime.now(timezone.utc)


def _now_iso() -> str:
    return _now().isoformat(timespec="seconds")


def _load_all() -> dict:
    if not HISTORY_FILE.exists():
        return {}
    try:
        return json.loads(HISTORY_FILE.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, OSError):
        return {}


def _save_all(data: dict) -> None:
    app_config.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    HISTORY_FILE.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")


def _purge(entries: list[dict]) -> list[dict]:
    cutoff = _now() - timedelta(hours=HISTORY_TTL_HOURS)
    kept = []
    for e in entries:
        try:
            created = datetime.fromisoformat(e.get("created_at", ""))
        except ValueError:
            continue
        if created >= cutoff:
            kept.append(e)
    return kept[:MAX_ENTRIES_PER_USER]


def add_entry(username: str, *, label: str, glass_type: str = "", glass_style: str = "",
              kind: str = "generate", canvas_size: str = "", bg: str = "",
              extra_prompt: str = "", intensity: str = "", tint: str = "") -> str:
    """Creates a new entry with status 'generating' and returns its id. The
    original request params are kept alongside the result so a history item
    can be reopened and refined later, exactly like a freshly-generated one."""
    entry_id = uuid.uuid4().hex
    with _lock:
        data = _load_all()
        entries = _purge(data.get(username, []))
        entries.insert(0, {
            "id": entry_id,
            "kind": kind,  # "generate" | "refine"
            "status": "generating",
            "label": label,
            "glass_type": glass_type,
            "style": glass_style,
            "canvas_size": canvas_size,
            "bg": bg,
            "extra_prompt": extra_prompt,
            "intensity": intensity,
            "tint": tint,
            "svg": None,
            "error": None,
            "created_at": _now_iso(),
            "updated_at": _now_iso(),
        })
        data[username] = entries
        _save_all(data)
    return entry_id


def mark_done(username: str, entry_id: str, svg: str) -> None:
    _update(username, entry_id, status="done", svg=svg, error=None)


def mark_failed(username: str, entry_id: str, error: str) -> None:
    _update(username, entry_id, status="failed", svg=None, error=(error or "")[:300])


def _update(username: str, entry_id: str, **fields) -> None:
    with _lock:
        data = _load_all()
        entries = _purge(data.get(username, []))
        for e in entries:
            if e["id"] == entry_id:
                e.update(fields)
                e["updated_at"] = _now_iso()
                break
        data[username] = entries
        _save_all(data)


def list_entries(username: str) -> list[dict]:
    with _lock:
        data = _load_all()
        entries = _purge(data.get(username, []))
        data[username] = entries
        _save_all(data)
        return entries


def clear_entries(username: str) -> None:
    with _lock:
        data = _load_all()
        data[username] = []
        _save_all(data)
