"""Where the disk went, and how to get some back.

This app writes in a lot of places: playback proxies beside the recordings,
storyboard sprites, saved clips, editor renders, ingest buffers, game art,
thumbnails. Individually each is reasonable. Together, after a few months
of nightly sessions, they are the reason a drive fills — and nothing in the
app has ever said so.

Nothing here deletes anything the user made. Clips, edits and recordings
are theirs. What can be swept is only what the app can rebuild: proxies,
storyboards, thumbnails, and finished renders that were already exported.
"""
import shutil
import time
from pathlib import Path

from fastapi import APIRouter, HTTPException, Request

from clipshelf import config, fileops
from clipshelf.config import (ASSETS, DATA, EXPORTS, HIGHLIGHTS_DIR, INGEST_DIR,
                            RENDERS, THUMBS)

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


def _dir_size(p) -> tuple:
    p = Path(p)
    total, n = 0, 0
    if not p.is_dir():
        return 0, 0
    for f in p.rglob("*"):
        try:
            if f.is_file():
                total += f.stat().st_size
                n += 1
        except OSError:
            continue
    return total, n


def _proxies() -> tuple:
    """Playback proxies live next to the recordings, not in the data dir."""
    from clipshelf import vod_assets
    root = Path(getattr(vod_assets, "proxy_dir", lambda: "")() or "")
    if root.is_dir():
        return _dir_size(root)
    return 0, 0


def survey() -> dict:
    """What is on disk, and which parts are safe to remove."""
    rows = []

    def add(key, label, path, reclaimable, note):
        size, n = (_proxies() if key == "proxies" else _dir_size(path))
        rows.append({"key": key, "label": label, "bytes": size, "files": n,
                     "reclaimable": reclaimable, "note": note})

    add("proxies", "playback proxies", None, True,
        "720p copies used for scrubbing — rebuilt on demand")
    add("thumbs", "thumbnails", THUMBS, True, "rebuilt on demand")
    add("renders", "editor renders", RENDERS, True,
        "raw output of past exports; anything you saved to My Edits has its own copy")
    add("gameart", "game art", DATA / "gameart", True,
        "cover art cache; re-fetched when needed")
    add("ingest", "ingest tray", INGEST_DIR, False,
        "captures you have not trimmed yet — trim or discard them instead")
    add("clips", "saved clips", HIGHLIGHTS_DIR, False, "yours")
    add("edits", "my edits", EXPORTS, False, "yours")
    add("assets", "editor assets", ASSETS, False, "media you imported")
    add("backups", "library snapshots", DATA / "backups", False,
        "copies of the database; delete individually under Updates")

    total = sum(r["bytes"] for r in rows)
    free = None
    try:
        du = shutil.disk_usage(config.VOD_DIR or str(DATA))
        free = {"free_gb": round(du.free / 1e9, 1), "total_gb": round(du.total / 1e9, 1)}
    except Exception:
        pass
    return {"rows": rows, "total_bytes": total,
            "reclaimable_bytes": sum(r["bytes"] for r in rows if r["reclaimable"]),
            "disk": free}


def sweep(keys: list, older_than_days: float = 0) -> dict:
    """Remove rebuildable files. Refuses anything the user authored."""
    from clipshelf import vod_assets
    targets = {
        "proxies": Path(getattr(vod_assets, "proxy_dir", lambda: "")() or ""),
        "thumbs": Path(THUMBS),
        "renders": Path(RENDERS),
        "gameart": Path(DATA / "gameart"),
    }
    cutoff = time.time() - older_than_days * 86400 if older_than_days else None
    freed, removed = 0, 0
    for key in keys:
        root = targets.get(key)
        if root is None:
            raise HTTPException(400, f"{key} is not something this can remove")
        if not root.is_dir():
            continue
        for f in root.rglob("*"):
            try:
                if not f.is_file():
                    continue
                st = f.stat()
                if cutoff and st.st_mtime > cutoff:
                    continue
                size = st.st_size
                if not fileops.remove(f):
                    continue
                freed += size
                removed += 1
            except OSError:
                continue
    if "gameart" in keys:
        (DATA / "gameart" / "index.json").unlink(missing_ok=True)
        from clipshelf import gameart
        gameart._misses.clear()
    return {"freed_bytes": freed, "removed": removed}


@router.get("/api/storage")
def storage_state():
    return {"status": "success", **survey()}


@router.post("/api/storage/sweep")
async def storage_sweep(request: Request):
    body = await request.json()
    keys = [str(k) for k in (body.get("keys") or [])]
    if not keys:
        raise HTTPException(400, "nothing selected")
    days = float(body.get("older_than_days") or 0)
    res = sweep(keys, days)
    return {"status": "success", **res, **survey()}
