#!/usr/bin/env python3
"""Create a non-secret capsule from a SQLite-to-Postgres restore proof."""

from __future__ import annotations

import argparse
import hashlib
import json
import sys
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

PRIVATE_FIELDS = ("source_sqlite_backup", "private_artifacts")


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


def validate_restore_proof(proof: dict[str, Any]) -> list[str]:
    problems = []
    mismatches = proof.get("mismatched_tables") or []
    if proof.get("artifact") != "sqlite_postgres_restore_canary":
        problems.append(f"artifact={proof.get('artifact')}")
    if proof.get("status") != "pass":
        problems.append(f"status={proof.get('status')}")
    if proof.get("source_integrity_check") != "ok":
        problems.append(f"source_integrity_check={proof.get('source_integrity_check')}")
    if mismatches:
        problems.append(f"mismatched_tables={len(mismatches)}")
    if proof.get("source_table_count") != proof.get("target_table_count"):
        problems.append(
            f"table_count source={proof.get('source_table_count')} target={proof.get('target_table_count')}"
        )
    if proof.get("source_total_rows") != proof.get("target_total_rows"):
        problems.append(f"total_rows source={proof.get('source_total_rows')} target={proof.get('target_total_rows')}")
    if not proof.get("generated_at_utc"):
        problems.append("missing_generated_at_utc")
    return problems


def build_capsule(proof_path: Path) -> dict[str, Any]:
    proof = json.loads(proof_path.read_text())
    problems = validate_restore_proof(proof)
    capsule = {
        "artifact": "sqlite_postgres_restore_canary_capsule",
        "capsule_generated_at_utc": datetime.now(UTC).isoformat(),
        "source_proof_generated_at_utc": proof.get("generated_at_utc"),
        "source_proof_sha256": sha256(proof_path),
        "status": "pass" if not problems else "fail",
        "source_integrity_check": proof.get("source_integrity_check"),
        "source_sqlite_backup_sha256": proof.get("source_sqlite_backup_sha256"),
        "postgres_image": proof.get("postgres_image"),
        "postgres_schema": proof.get("postgres_schema"),
        "source_table_count": proof.get("source_table_count"),
        "target_table_count": proof.get("target_table_count"),
        "source_total_rows": proof.get("source_total_rows"),
        "target_total_rows": proof.get("target_total_rows"),
        "mismatched_table_count": len(proof.get("mismatched_tables") or []),
        "conversion_notes": proof.get("conversion_notes", {}),
        "conversion_stats": proof.get("conversion_stats", {}),
        "redacted_fields": list(PRIVATE_FIELDS),
        "problems": problems,
        "not_proven_by_this_artifact": [
            "private backup file availability",
            "private generated SQL contents",
            "GCP Cloud SQL import execution",
            "GCP Cloud SQL target-count readback",
        ],
    }
    return capsule


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--proof", required=True, type=Path, help="Full sqlite-postgres restore canary proof JSON")
    parser.add_argument("--output", required=True, type=Path, help="Redacted capsule JSON output path")
    return parser.parse_args()


def main() -> int:
    args = parse_args()
    capsule = build_capsule(args.proof)
    rendered = json.dumps(capsule, indent=2, sort_keys=True) + "\n"
    for private_field in PRIVATE_FIELDS:
        if private_field in rendered and private_field not in json.dumps(capsule.get("redacted_fields", [])):
            print(f"private field leaked into capsule: {private_field}", file=sys.stderr)
            return 1
    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(rendered)
    print(rendered, end="")
    return 0 if capsule["status"] == "pass" else 1


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