from __future__ import annotations

import hashlib
import json
import re
from pathlib import Path

ROOT = Path(__file__).resolve().parent
CANONICAL = ROOT / "reference" / "struc_i_v1_0_4_galaxy_profiles.html"
ENGINE = ROOT / "web" / "static" / "struc_i_v1_0_4_engine.js"
FUNCTIONS = [
    "median", "mean", "std", "quantile", "logspace", "stratifiedSample",
    "computeGaps", "gapStats", "computeVulnerabilityRuns", "computeNuFromRuns",
    "computeVulnerability", "countInversions", "runMCStep", "pressureLabel",
    "classifyRegime",
]


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


def extract_function(text: str, name: str) -> str:
    match = re.search(rf"function\s+{re.escape(name)}\s*\(", text)
    if not match:
        raise ValueError(f"Function {name} not found")
    start = match.start()
    brace = text.find("{", match.end())
    depth = 0
    quote = None
    escaped = False
    for index in range(brace, len(text)):
        ch = text[index]
        if quote:
            if escaped:
                escaped = False
            elif ch == "\\":
                escaped = True
            elif ch == quote:
                quote = None
            continue
        if ch in "'\"`":
            quote = ch
        elif ch == "{":
            depth += 1
        elif ch == "}":
            depth -= 1
            if depth == 0:
                return text[start:index + 1]
    raise ValueError(f"Unclosed function {name}")


def normalize(source: str) -> str:
    # Comments are part of the canonical source inside function bodies; only whitespace is normalized.
    return re.sub(r"\s+", "", source)


def main() -> None:
    canonical = CANONICAL.read_text(encoding="utf-8")
    engine = ENGINE.read_text(encoding="utf-8")
    mismatches = []
    function_hashes = {}
    for name in FUNCTIONS:
        a = normalize(extract_function(canonical, name))
        b = normalize(extract_function(engine, name))
        function_hashes[name] = hashlib.sha256(b.encode("utf-8")).hexdigest()
        if a != b:
            mismatches.append(name)
    lock = {
        "canonical_html": str(CANONICAL.relative_to(ROOT)),
        "canonical_html_sha256": sha256(CANONICAL),
        "engine_js": str(ENGINE.relative_to(ROOT)),
        "engine_js_sha256": sha256(ENGINE),
        "verified_core_functions": FUNCTIONS,
        "normalized_function_sha256": function_hashes,
        "mismatches": mismatches,
    }
    (ROOT / "ENGINE_LOCK.json").write_text(json.dumps(lock, indent=2), encoding="utf-8")
    if mismatches:
        raise SystemExit("ENGINE_CORE_MISMATCH " + ",".join(mismatches))
    print(f"ENGINE_CORE_EQUIVALENCE_PASS functions={len(FUNCTIONS)}")
    print(f"canonical_html_sha256={lock['canonical_html_sha256']}")
    print(f"engine_js_sha256={lock['engine_js_sha256']}")


if __name__ == "__main__":
    main()
