#!/usr/bin/env python3
"""Regenerate the distributable manifest while excluding secrets and caches.

Also reports the shape of the package — how many fonts, presets, transitions and
sounds are actually present — so a truncated copy is visible immediately instead of
failing at render time.
"""
from __future__ import annotations

import hashlib
import json
from datetime import date
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
VERSION = "4.0.0"
EXCLUDED_PARTS = {".git", ".venv", "__pycache__", "cache", "node_modules"}
EXCLUDED_FILES = {".env", "MANIFEST.json"}
# Downloaded font sources are reproducible from font_catalog.json and add megabytes
# of hashes to the manifest without telling anyone anything useful.
SOURCE_FONT_DIRS = {"assets/fonts"}


def is_font_source(relative: Path) -> bool:
    parts = relative.parts
    if len(parts) < 3 or parts[0] != "assets" or parts[1] != "fonts":
        return False
    # Keep the catalog, the manifest and the flat pack; skip per-family downloads.
    return parts[2] not in ("all", "font_catalog.json", "font_manifest.json", "README.md")


def main() -> None:
    files = []
    skipped_font_sources = 0
    for path in sorted(ROOT.rglob("*")):
        if not path.is_file():
            continue
        relative = path.relative_to(ROOT)
        if relative.name in EXCLUDED_FILES or any(
            part in EXCLUDED_PARTS for part in relative.parts
        ):
            continue
        if is_font_source(relative):
            skipped_font_sources += 1
            continue
        content = path.read_bytes()
        files.append({
            "path": relative.as_posix(),
            "bytes": len(content),
            "sha256": hashlib.sha256(content).hexdigest(),
        })

    def count(pattern: str) -> int:
        return len(list(ROOT.glob(pattern)))

    catalog = ROOT / "assets" / "fonts" / "font_catalog.json"
    library = ROOT / "assets" / "transitions" / "transition_library.json"
    inventory = {
        "scripts": count("scripts/*.py"),
        "caption_presets": count("assets/caption_styles/*.json"),
        "font_families_in_catalog": (
            len(json.loads(catalog.read_text(encoding="utf-8"))["families"])
            if catalog.exists() else 0
        ),
        "font_faces_installed": count("assets/fonts/all/*.ttf"),
        "transitions": (
            len(json.loads(library.read_text(encoding="utf-8"))["transitions"])
            if library.exists() else 0
        ),
        "sfx_files": count("assets/sfx/*.wav"),
        "grades": (
            len(json.loads((ROOT / "assets" / "grades" / "grade_presets.json")
                           .read_text(encoding="utf-8"))["grades"])
            if (ROOT / "assets" / "grades" / "grade_presets.json").exists() else 0
        ),
        "references": count("references/*.md"),
    }

    manifest = {
        "package": "ai_pro_video_skill",
        "version": VERSION,
        "generated_at": date.today().isoformat(),
        "secrets_included": False,
        "inventory": inventory,
        "notes": {
            "font_sources_excluded": (
                f"{skipped_font_sources} загруженных исходных файлов шрифтов не "
                f"включены в манифест: они воспроизводятся из assets/fonts/"
                f"font_catalog.json командой scripts/install_fonts.py."
            ),
            "regenerate_pack": "python scripts/install_fonts.py --tier all",
            "regenerate_sfx": "python scripts/generate_sfx.py",
        },
        "files": files,
    }
    output = ROOT / "MANIFEST.json"
    output.write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n",
                      encoding="utf-8")
    print(json.dumps({
        "output": str(output), "files": len(files),
        "secrets_included": False, "inventory": inventory,
        "font_sources_excluded": skipped_font_sources,
    }, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
