"""mutation_generator.py — Generate mutated Lean files from manifest.json.

Each mutation takes a theorem, applies a text-based transformation
(flip = → ≠, swap mul → add, etc.), and writes the mutated .lean file.
The runner then attempts to build it and expects failure.
"""
import json, re, shutil
from pathlib import Path
from typing import Any

REPO = Path(__file__).resolve().parents[2]
MUTATIONS = REPO / "scripts" / "qc_flag" / "mutations"
MANIFEST = REPO / "scripts" / "qc_flag" / "manifest.json"

def load_manifest() -> dict[str, Any]:
    return json.loads(MANIFEST.read_text())

def apply_mutation(text: str, diff: str) -> str:
    if "\u2192" in diff:
        parts = diff.split("\u2192")
        return text.replace(parts[0].strip(), parts[1].strip())
    return text

def generate_all(manifest: dict[str, Any] | None = None) -> dict[str, list[Path]]:
    if manifest is None:
        manifest = load_manifest()
    MUTATIONS.mkdir(parents=True, exist_ok=True)
    result: dict[str, list[Path]] = {}
    for src_rel, cfg in manifest["sources"].items():
        src = REPO / src_rel
        if not src.exists():
            continue
        orig = src.read_text()
        paths: list[Path] = []
        for tname, tcfg in cfg["theorems"].items():
            for m in tcfg["mutations"]:
                mutated = apply_mutation(orig, m["diff"])
                p = MUTATIONS / f"{m['id']}_{src.stem}.lean"
                p.write_text(mutated)
                paths.append(p)
        result[str(src)] = paths
    return result

if __name__ == "__main__":
    gen = generate_all()
    total = sum(len(v) for v in gen.values())
    print(f"Generated {total} mutations")
