#!/usr/bin/env python3
"""Generate release-manifest.json from built component tarballs.

Scans the dist/ directory for component tarballs, reads their
COMPONENT_VERSION metadata, computes SHA256 checksums, and writes
a release-manifest.json suitable for upload as a GitHub Release asset.

Usage:
    python3 ci/generate-manifest.py [dist_dir] [--version VERSION]
"""
import hashlib
import json
import os
import sys
import tarfile
from pathlib import Path


def sha256_file(path: Path) -> str:
    """Compute SHA256 checksum of a file."""
    h = hashlib.sha256()
    with open(path, "rb") as f:
        while chunk := f.read(65536):
            h.update(chunk)
    return h.hexdigest()


def read_component_version(tarball_path: Path) -> dict:
    """Read COMPONENT_VERSION JSON from inside a tarball."""
    with tarfile.open(tarball_path, "r:gz") as tf:
        for member in tf.getmembers():
            if member.name.endswith("COMPONENT_VERSION"):
                f = tf.extractfile(member)
                if f:
                    return json.loads(f.read().decode())
    return {}


def main():
    dist_dir = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("dist")
    version = None
    if "--version" in sys.argv:
        idx = sys.argv.index("--version")
        version = sys.argv[idx + 1]

    if not dist_dir.exists():
        print(f"Error: {dist_dir} does not exist")
        sys.exit(1)

    # Read VERSION file if version not specified
    if not version:
        version_file = Path("VERSION")
        version = version_file.read_text().strip() if version_file.exists() else "0.1.0"

    manifest = {
        "schema_version": 1,
        "release_version": version,
        "components": {},
    }

    tarballs = sorted(dist_dir.glob("*.tar.gz"))
    if not tarballs:
        print(f"Warning: no tarballs found in {dist_dir}")

    for tarball in tarballs:
        filename = tarball.name
        checksum = sha256_file(tarball)
        size = tarball.stat().st_size
        comp_version = read_component_version(tarball)
        comp_id = comp_version.get("component_id", "")

        if not comp_id:
            # Try to infer from filename
            for known in ("pm3", "frontend", "backend", "theme"):
                if filename.startswith(known):
                    comp_id = known
                    break

        if not comp_id:
            print(f"  Skipping {filename} (unknown component)")
            continue

        comp_ver = comp_version.get("version", version)

        # Build asset key (platform-specific for pm3)
        platform_str = comp_version.get("platform")
        python_abi = comp_version.get("python_abi")
        if platform_str and python_abi:
            asset_key = f"{platform_str}-{python_abi}"
        else:
            asset_key = "default"

        asset_info = {
            "filename": filename,
            "checksum_sha256": checksum,
            "size": size,
        }
        if comp_version.get("python_version"):
            asset_info["python_version"] = comp_version["python_version"]
        if platform_str:
            asset_info["platform"] = platform_str

        # Initialize component entry if needed
        if comp_id not in manifest["components"]:
            manifest["components"][comp_id] = {
                "version": comp_ver,
                "assets": {},
                "changelog": "",
            }

        manifest["components"][comp_id]["assets"][asset_key] = asset_info
        print(f"  {comp_id}/{asset_key}: {filename} ({size} bytes)")

    # Write manifest
    manifest_path = dist_dir / "release-manifest.json"
    with open(manifest_path, "w") as f:
        json.dump(manifest, f, indent=2)

    print(f"\n✅ Wrote {manifest_path}")
    print(f"   Components: {list(manifest['components'].keys())}")


if __name__ == "__main__":
    main()
