from __future__ import annotations

import hashlib
import json
import shutil
import tempfile
import zipfile
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
OUTPUT = ROOT.parent / "PolicyFaultBench_v0.6.1_COMPLETE_EVIDENCE.zip"

INCLUDE = (
    "src",
    "policies",
    "scenarios",
    "schemas",
    "config",
    "manifests",
    "external_sources",
    "tests",
    "scripts",
    "analysis",
    "results",
    "study",
    "reports",
    "README.md",
    "SAFETY.md",
    "SECURITY.md",
    "INSTALL_AR.md",
    "VALIDATION_REPORT.md",
    "pyproject.toml",
)

EXCLUDED_NAMES = {
    ".env",
    ".env.local",
    ".git",
    "__pycache__",
    ".pytest_cache",
}

SECRET_MARKERS = (
    b"sk-proj-",
    b"sk-ant-",
    b"aiza",
)

EVIDENCE_SUFFIXES = {
    ".json",
    ".jsonl",
    ".csv",
    ".md",
    ".txt",
}


def sha256(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


def copy_selected(staging_root: Path) -> Path:
    project = staging_root / "PolicyFaultBench"
    project.mkdir(parents=True)
    for relative in INCLUDE:
        source = ROOT / relative
        if not source.exists():
            continue
        target = project / relative
        if source.is_dir():
            shutil.copytree(
                source,
                target,
                ignore=shutil.ignore_patterns(
                    *EXCLUDED_NAMES,
                    "*.pyc",
                    ".env*",
                ),
            )
        else:
            target.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(source, target)
    return project


def scan_for_secrets(project: Path) -> None:
    for path in project.rglob("*"):
        if not path.is_file():
            continue
        if (
            path.name in EXCLUDED_NAMES
            or path.name.startswith(".env")
        ):
            raise RuntimeError(f"Prohibited secret path: {path}")
        if path.suffix.lower() not in EVIDENCE_SUFFIXES:
            continue
        data = path.read_bytes().lower()
        if any(marker in data for marker in SECRET_MARKERS):
            raise RuntimeError(f"Credential-like marker in evidence: {path}")


def write_manifest(project: Path) -> Path:
    files = sorted(
        path
        for path in project.rglob("*")
        if path.is_file() and path.name != "PACKAGE_MANIFEST.json"
    )
    manifest = {
        "schema_version": "1.0",
        "package": "PolicyFaultBench v0.6.1 complete evidence",
        "protocol_id": "pfb-policy-generalization-v1",
        "file_count_excluding_manifest": len(files),
        "files": {
            str(path.relative_to(project)): sha256(path)
            for path in files
        },
        "api_keys_included": False,
        "primary_extension_result": {
            "scheduled_trials": 800,
            "strict_successes": 791,
            "strict_failures": 9,
            "overall_acceptance_rule_passed": False,
            "containment_failures": 0,
        },
    }
    path = project / "PACKAGE_MANIFEST.json"
    path.write_text(
        json.dumps(manifest, indent=2, sort_keys=True) + "\n",
        encoding="utf-8",
    )
    return path


def main() -> None:
    with tempfile.TemporaryDirectory(
        prefix="pfb-complete-evidence-"
    ) as raw:
        staging = Path(raw)
        project = copy_selected(staging)
        scan_for_secrets(project)
        manifest = write_manifest(project)
        manifest_hash = sha256(manifest)
        with zipfile.ZipFile(OUTPUT, "w", zipfile.ZIP_DEFLATED) as archive:
            for path in sorted(staging.rglob("*")):
                if path.is_file():
                    archive.write(
                        path,
                        arcname=str(path.relative_to(staging)),
                    )

    with zipfile.ZipFile(OUTPUT) as archive:
        bad = archive.testzip()
        if bad is not None:
            raise RuntimeError(f"Archive CRC failure: {bad}")
        names = archive.namelist()
        if any(
            Path(name).name in EXCLUDED_NAMES
            or Path(name).name.startswith(".env")
            for name in names
        ):
            raise RuntimeError("Archive contains a prohibited path")

    print(
        json.dumps(
            {
                "archive": str(OUTPUT),
                "sha256": sha256(OUTPUT),
                "size_bytes": OUTPUT.stat().st_size,
                "manifest_sha256": manifest_hash,
                "api_keys_included": False,
            },
            indent=2,
            sort_keys=True,
        )
    )


if __name__ == "__main__":
    main()
