#!/usr/bin/env python3
"""Audit the fixed ownership and feature boundary for milestone 06."""

from __future__ import annotations

import json
from pathlib import Path
import re
import tomllib


ROOT = Path(__file__).resolve().parents[1]
OWNED_CRATES = (
    ROOT / "crates" / "libremetaverse-imaging",
    ROOT / "crates" / "libremetaverse-imaging-skia",
    ROOT / "crates" / "libremetaverse-prim-mesher",
)
OWNED_FIXTURES = {
    "LibreMetaverse.Tests/ManagedImageTests.cs": 3,
    "LibreMetaverse.Rendering.Tests/PrimMesher/CoordQuatTests.cs": 18,
    "LibreMetaverse.Rendering.Tests/PrimMesher/PrimMeshTests.cs": 27,
}
STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(")


def load_toml(path: Path) -> dict:
    with path.open("rb") as stream:
        return tomllib.load(stream)


def check_owned_rust() -> None:
    offenders: list[str] = []
    for crate in OWNED_CRATES:
        for path in sorted((crate / "src").rglob("*.rs")):
            if STUB_RE.search(path.read_text()):
                offenders.append(path.relative_to(ROOT).as_posix())
    if offenders:
        raise SystemExit("milestone-owned Rust stubs remain: " + ", ".join(offenders))


def check_features() -> None:
    imaging = load_toml(OWNED_CRATES[0] / "Cargo.toml")
    if imaging["features"].get("default") != []:
        raise SystemExit("imaging default features must stay empty")
    if imaging["features"].get("jpeg2000") != ["dep:libremetaverse-openjpeg"]:
        raise SystemExit("JPEG 2000 must stay isolated behind its optional feature")
    if imaging["features"].get("rust-j2k") != ["dep:j2k"]:
        raise SystemExit("pure-Rust JPEG 2000 must stay isolated behind rust-j2k")
    if not imaging["dependencies"]["libremetaverse-openjpeg"].get("optional"):
        raise SystemExit("the OpenJPEG adapter dependency must stay optional")

    skia = load_toml(OWNED_CRATES[1] / "Cargo.toml")
    if skia["features"].get("default") != []:
        raise SystemExit("Skia adapter default features must stay empty")
    if skia["features"].get("skia") != ["dep:skia-safe"]:
        raise SystemExit("Skia must stay isolated behind its optional feature")
    targets = skia.get("target", {}).values()
    skia_dependencies = [
        target.get("dependencies", {}).get("skia-safe") for target in targets
    ]
    if not skia_dependencies or any(
        dependency is None or not dependency.get("optional")
        for dependency in skia_dependencies
    ):
        raise SystemExit("every platform-specific Skia dependency must stay optional")

    workspace = load_toml(ROOT / "Cargo.toml")["workspace"]
    adapter = "crates/libremetaverse-openjpeg"
    if adapter not in workspace.get("members", []):
        raise SystemExit("the native OpenJPEG adapter must remain explicitly packageable")
    if adapter in workspace.get("default-members", workspace.get("members", [])):
        raise SystemExit("the native OpenJPEG adapter must stay outside default workspace builds")


def check_parity() -> None:
    catalog = json.loads((ROOT / "tests" / "upstream-tests.json").read_text())
    grouped: dict[str, list[dict]] = {source: [] for source in OWNED_FIXTURES}
    for case in catalog["tests"]:
        if case["source"] in grouped:
            grouped[case["source"]].append(case)
    for source, expected in OWNED_FIXTURES.items():
        cases = grouped[source]
        if len(cases) != expected:
            raise SystemExit(f"{source}: expected {expected} reviewed cases, found {len(cases)}")
        incomplete = [
            case["id"]
            for case in cases
            if case["status"] != "translated"
            or case.get("semantic_review") != "reviewed"
            or not (ROOT / case["rust_file"]).is_file()
        ]
        if incomplete:
            raise SystemExit(f"{source}: incomplete parity cases: " + ", ".join(incomplete))


def check_benchmarks_and_ci() -> None:
    expected_benches = {
        OWNED_CRATES[0]: "image_pipeline",
        OWNED_CRATES[2]: "meshing",
    }
    for crate, name in expected_benches.items():
        manifest = load_toml(crate / "Cargo.toml")
        benches = {entry["name"]: entry for entry in manifest.get("bench", [])}
        if benches.get(name, {}).get("harness") is not False:
            raise SystemExit(f"missing harness-free {name} benchmark declaration")
        if not (crate / "benches" / f"{name}.rs").is_file():
            raise SystemExit(f"missing {name} benchmark source")

    workflows = {"consolidated": ROOT / ".gitea" / "workflows" / "ci.yml"}
    for name, path in workflows.items():
        if not path.is_file():
            raise SystemExit(f"missing {name} native-feature workflow")
        runners = re.findall(r"(?m)^\s*runs-on:\s*([^\s#]+)", path.read_text().lower())
        if not runners:
            raise SystemExit(f"{name} workflow has no runner")
        unsupported = sorted({runner for runner in runners if runner != "ubuntu-latest"})
        if unsupported:
            raise SystemExit(
                f"{name} workflow must use only ubuntu-latest, found: "
                + ", ".join(unsupported)
            )
        text = path.read_text()
        for marker in ("required-gate", "METACRATE_SKIA_ARCHIVE", "OPENJPEG_PREFIX"):
            if marker not in text:
                raise SystemExit(f"{name} workflow is missing {marker}")


def main() -> None:
    check_owned_rust()
    check_features()
    check_parity()
    check_benchmarks_and_ci()
    print(
        "milestone 06 audit: owned Rust has no stubs; 48 reviewed parity cases, "
        "optional native features, benchmarks, and Linux-only Gitea workflows are complete"
    )


if __name__ == "__main__":
    main()
