"""Snapshots of the library database.

The recordings are on disk and can be re-scanned. What cannot be recovered
is everything the app learned about them: chapters, event timestamps, clip
marks, transcripts, share links. That all lives in one SQLite file, and
until now nothing kept a copy of it.

A snapshot is taken with `VACUUM INTO`, which writes a consistent copy while
the app keeps running — no stopping workers, no half-written file if a
transcription commits mid-copy. One is taken automatically before an update
is applied, because "the update ate my library" is the failure that would
end someone's trust in this app permanently.
"""
import os
import time
from pathlib import Path

from fastapi import APIRouter, HTTPException

from clipshelf import db
from clipshelf.config import DATA

router = APIRouter(tags=["backup"])

BACKUP_DIR = DATA / "backups"
KEEP = 8                    # snapshots are small; a few weeks of them is fine


def snapshot(tag: str = "manual") -> Path:
    """Consistent copy of the database. Returns the path written."""
    BACKUP_DIR.mkdir(parents=True, exist_ok=True)
    safe = "".join(c for c in tag if c.isalnum() or c in "-_")[:30] or "manual"
    out = BACKUP_DIR / f"library-{time.strftime('%Y%m%d-%H%M%S')}-{safe}.db"
    conn = db.connect()
    try:
        # VACUUM INTO takes its own read transaction: safe while workers write
        conn.execute("VACUUM INTO ?", (str(out),))
    finally:
        conn.close()
    prune()
    return out


def prune(keep: int = KEEP):
    files = sorted(BACKUP_DIR.glob("library-*.db"), key=lambda p: p.stat().st_mtime)
    for old in files[:-keep] if len(files) > keep else []:
        try:
            old.unlink()
        except OSError:
            pass


def items() -> list:
    if not BACKUP_DIR.is_dir():
        return []
    out = []
    for p in sorted(BACKUP_DIR.glob("library-*.db"),
                    key=lambda p: p.stat().st_mtime, reverse=True):
        st = p.stat()
        out.append({"file": p.name, "bytes": st.st_size,
                    "ts": int(st.st_mtime),
                    "tag": p.stem.rsplit("-", 1)[-1]})
    return out


@router.get("/api/backups")
def backups_list():
    return {"status": "success", "backups": items(), "dir": str(BACKUP_DIR)}


@router.post("/api/backups")
def backups_create():
    try:
        p = snapshot("manual")
    except Exception as e:
        from clipshelf import problems
        problems.record("backup", e, "the library snapshot could not be written")
        raise HTTPException(500, f"snapshot failed: {e}")
    return {"status": "success", "file": p.name, "bytes": p.stat().st_size,
            "backups": items()}


@router.delete("/api/backups/{name}")
def backups_delete(name: str):
    p = (BACKUP_DIR / os.path.basename(name)).resolve()
    if not str(p).startswith(str(BACKUP_DIR.resolve())) or not p.is_file():
        raise HTTPException(404, "no such snapshot")
    p.unlink()
    return {"status": "success", "backups": items()}
