#!/usr/bin/env python3
"""Copy loose rootfs assets with viewer-friendly extensions.

This preserves target files unchanged and writes renamed copies under assets/.
"""

from __future__ import annotations

import argparse
import hashlib
import json
import re
import shutil
import struct
from pathlib import Path


def sha256_file(path: Path) -> str:
    h = hashlib.sha256()
    with path.open("rb") as f:
        for chunk in iter(lambda: f.read(1024 * 1024), b""):
            h.update(chunk)
    return h.hexdigest()


def safe_parts(path: Path) -> list[str]:
    parts: list[str] = []
    for part in path.parts:
        if part in ("", ".", ".."):
            continue
        clean = re.sub(r"[^A-Za-z0-9._' -]+", "_", part).strip()
        parts.append(clean or "_")
    return parts


def detect_extension(data: bytes) -> str | None:
    if data.startswith(b"\x89PNG\r\n\x1a\n"):
        return ".png"
    if data.startswith((b"\x00\x01\x00\x00", b"OTTO", b"ttcf")):
        return ".ttf"
    if len(data) >= 12 and data[4:8] == b"ftyp":
        major = data[8:12]
        return ".mov" if major == b"qt  " else ".mp4"
    return None


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--source", type=Path, default=Path("games/pokemon_pro/assets"))
    parser.add_argument("--output", type=Path, default=Path("assets/openable/loose"))
    parser.add_argument("--manifest", type=Path, default=Path("assets/loose_manifest.json"))
    args = parser.parse_args()

    copied = []
    skipped = 0
    for src in sorted(args.source.rglob("*")):
        if not src.is_file() or src.name == "main.pck":
            continue
        with src.open("rb") as f:
            head = f.read(64)
        ext = detect_extension(head)
        if ext is None:
            skipped += 1
            continue
        rel = src.relative_to(args.source)
        rel_parts = safe_parts(rel)
        out = args.output.joinpath(*rel_parts)
        if out.suffix.lower() != ext:
            out = out.with_name(out.name + ext)
        out.parent.mkdir(parents=True, exist_ok=True)
        shutil.copyfile(src, out)
        copied.append(
            {
                "source": str(src),
                "source_target_path": "/games/pokemon_pro/assets/" + str(rel),
                "output": str(out),
                "size": src.stat().st_size,
                "sha256": sha256_file(src),
                "detected_extension": ext,
            }
        )

    args.manifest.parent.mkdir(parents=True, exist_ok=True)
    args.manifest.write_text(
        json.dumps(
            {
                "source_root": str(args.source),
                "output_root": str(args.output),
                "copied": len(copied),
                "skipped_non_openable": skipped,
                "entries": copied,
            },
            indent=2,
        ),
        encoding="utf-8",
    )
    print(json.dumps({"copied": len(copied), "skipped_non_openable": skipped}, indent=2))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
