from __future__ import annotations

import argparse
import json
import shutil
from datetime import datetime, timezone
from pathlib import Path
from typing import Any


def main() -> int:
    parser = argparse.ArgumentParser(description="Approve a generated memorial pet package for desktop use.")
    parser.add_argument("--build-dir", required=True, type=Path, help="Generated build directory containing package/pet.json.")
    parser.add_argument(
        "--output-root",
        type=Path,
        default=Path("outputs") / "approved_pet_packages",
        help="Directory where approved desktop packages are installed.",
    )
    parser.add_argument(
        "--approval-note",
        default="User approved likeness, comfort, and action suitability for desktop use.",
        help="Short non-sensitive approval note.",
    )
    args = parser.parse_args()

    approved_dir = approve_pet_package(
        build_dir=args.build_dir,
        output_root=args.output_root,
        approval_note=args.approval_note,
    )
    print(json.dumps({"ok": True, "approved_package_dir": str(approved_dir)}, ensure_ascii=False, indent=2))
    return 0


def approve_pet_package(*, build_dir: Path, output_root: Path, approval_note: str) -> Path:
    build_dir = build_dir.resolve()
    package_dir = build_dir / "package"
    package_manifest_path = package_dir / "pet.json"
    spritesheet_path = package_dir / "spritesheet.png"
    validation_path = build_dir / "validation.json"
    build_manifest_path = build_dir / "manifest.json"

    if not package_manifest_path.exists():
        raise FileNotFoundError(f"package manifest not found: {package_manifest_path}")
    if not spritesheet_path.exists():
        raise FileNotFoundError(f"package spritesheet not found: {spritesheet_path}")
    if not validation_path.exists():
        raise FileNotFoundError(f"validation not found: {validation_path}")

    validation = _read_json(validation_path)
    if validation.get("ok") is not True:
        raise ValueError("cannot approve a package whose validation.json is not ok")

    package = _read_json(package_manifest_path)
    pet_id = _safe_package_dir_name(str(package.get("id") or package.get("displayName") or "pet"))
    approved_dir = (output_root / pet_id).resolve()
    approved_dir.mkdir(parents=True, exist_ok=True)

    shutil.copy2(spritesheet_path, approved_dir / "spritesheet.png")
    approved_at = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
    package["userApproved"] = True
    package.setdefault("source", {})
    package["source"].update(
        {
            "fixtureKind": "private_generated_approved",
            "sensitiveContentStored": False,
            "approvedAt": approved_at,
            "approvalNote": " ".join(approval_note.strip().split())[:160],
        }
    )
    if build_manifest_path.exists():
        build_manifest = _read_json(build_manifest_path)
        package["source"]["sourceBuildId"] = str(build_manifest.get("build_id", ""))
        package["source"]["sourcePackageId"] = str(build_manifest.get("package_id", ""))
        package["source"]["imageGenerationProvider"] = str(
            build_manifest.get("source", {}).get("image_generation_provider", "")
        )
        package["source"]["imageModel"] = str(build_manifest.get("source", {}).get("image_model", ""))

    _write_json(approved_dir / "pet.json", package)
    _write_json(
        approved_dir / "approval.json",
        {
            "ok": True,
            "approvedAt": approved_at,
            "petId": package.get("id"),
            "displayName": package.get("displayName"),
            "sourceBuildDirName": build_dir.name,
            "validation": str(validation_path.relative_to(build_dir)),
            "note": package["source"]["approvalNote"],
        },
    )
    return approved_dir


def _read_json(path: Path) -> dict[str, Any]:
    return json.loads(path.read_text(encoding="utf-8"))


def _write_json(path: Path, payload: dict[str, Any]) -> None:
    path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def _safe_package_dir_name(value: str) -> str:
    cleaned = "".join(char for char in value.strip() if char not in {"/", "\\", ":", "\0"})
    return cleaned or "pet"


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