#!/usr/bin/env python3
"""Audit issue 77's native MeshFoundry ownership and evidence boundary."""

from __future__ import annotations

from pathlib import Path
import re

import generate_api_shims


ROOT = Path(__file__).resolve().parents[1]
SOURCE = ROOT / "crates" / "libremetaverse-rendering-mesh-foundry" / "src" / "mesh_foundry.rs"
GENERATED = ROOT / "crates" / "libremetaverse-rendering-mesh-foundry" / "src" / "generated.rs"
MANIFEST = ROOT / "crates" / "libremetaverse-rendering-mesh-foundry" / "Cargo.toml"
ASSET_TESTS = ROOT / "crates" / "libremetaverse-rendering-mesh-foundry" / "tests" / "mesh_assets.rs"
COMPAT = ROOT / "tests" / "compat" / "tests" / "imaging_meshing_semantics.rs"
BENCH = ROOT / "crates" / "libremetaverse-rendering-mesh-foundry" / "benches" / "mesh_decode.rs"
WORKSPACE = ROOT / "Cargo.toml"
DOC = ROOT / "crates" / "libremetaverse-rendering-mesh-foundry" / "README.md"
STRUCTURED = ROOT / "crates" / "libremetaverse-structured-data" / "src" / "lib.rs"
WORKFLOW = ROOT / ".gitea" / "workflows" / "ci.yml"
STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(")

TYPE = "T:LibreMetaverse.Rendering.MeshFoundry"
MEMBERS = {
    "M:LibreMetaverse.Rendering.MeshFoundry.#ctor",
    "M:LibreMetaverse.Rendering.MeshFoundry.GenerateFacetedMesh(LibreMetaverse.Primitive,LibreMetaverse.Rendering.DetailLevel)",
    "M:LibreMetaverse.Rendering.MeshFoundry.GenerateFacetedMeshMesh(LibreMetaverse.Primitive,System.Byte[])",
    "M:LibreMetaverse.Rendering.MeshFoundry.GenerateFacetedMeshMesh(LibreMetaverse.Primitive,System.Byte[],LibreMetaverse.Rendering.DetailLevel)",
    "M:LibreMetaverse.Rendering.MeshFoundry.GenerateFacetedSculptMesh(LibreMetaverse.Primitive,LibreMetaverse.Imaging.ManagedImage,LibreMetaverse.Rendering.DetailLevel)",
    "M:LibreMetaverse.Rendering.MeshFoundry.GenerateSimpleMesh(LibreMetaverse.Primitive,LibreMetaverse.Rendering.DetailLevel)",
    "M:LibreMetaverse.Rendering.MeshFoundry.GenerateSimpleMeshWithNormals(LibreMetaverse.Primitive,LibreMetaverse.Rendering.DetailLevel)",
    "M:LibreMetaverse.Rendering.MeshFoundry.GenerateSimpleSculptMesh(LibreMetaverse.Primitive,LibreMetaverse.Imaging.ManagedImage,LibreMetaverse.Rendering.DetailLevel)",
    "M:LibreMetaverse.Rendering.MeshFoundry.MeshSubMeshAsConvexHulls(LibreMetaverse.Primitive,System.Byte[])",
    "M:LibreMetaverse.Rendering.MeshFoundry.MeshSubMeshAsConvexHulls(LibreMetaverse.Primitive,System.Byte[],System.Collections.Generic.List{LibreMetaverse.Vector3}@)",
    "M:LibreMetaverse.Rendering.MeshFoundry.MeshSubMeshAsSimpleMesh(LibreMetaverse.Primitive,System.Byte[])",
    "M:LibreMetaverse.Rendering.MeshFoundry.TerrainMesh(System.Single[0:,0:],System.Single,System.Single,System.Single,System.Single)",
    "M:LibreMetaverse.Rendering.MeshFoundry.TransformTexCoords(System.Collections.Generic.List{LibreMetaverse.Rendering.Vertex},LibreMetaverse.Vector3,LibreMetaverse.Primitive.TextureEntryFace,LibreMetaverse.Vector3)",
    "M:LibreMetaverse.Rendering.MeshFoundry.UnpackMesh(System.Byte[])",
}


def require_markers(path: Path, markers: tuple[str, ...]) -> None:
    text = path.read_text()
    missing = [marker for marker in markers if marker not in text]
    if missing:
        raise SystemExit(f"{path.name}: audit evidence missing: " + ", ".join(missing))


def main() -> None:
    if generate_api_shims.NATIVE_DECLARATIONS.get(TYPE) != "crate::mesh_foundry::MeshFoundry":
        raise SystemExit("issue 77 MeshFoundry native declaration is missing")
    missing = sorted(MEMBERS - set(generate_api_shims.NATIVE_MEMBER_BODIES))
    if missing:
        raise SystemExit("issue 77 native members missing: " + ", ".join(missing))
    for source in (SOURCE, GENERATED):
        if STUB_RE.search(source.read_text()):
            raise SystemExit(f"issue 77 owned Rust stubs remain in {source.name}")

    require_markers(SOURCE, (
        "impl IRendering for MeshFoundry", "SimpleRenderer", "SculptMesh::from_height_rows",
        "deserialize_llsd_binary_prefix", "ZlibDecoder", "select_lod", "decode_submesh",
        "TexCoord1", "Tangent", "generate_normals", "generate_tangents", "MeshFaceAux",
        "decode_skin", "decode_weights", "apply_sculpt_modifiers", "texture_for_face",
        "MAX_ASSET_BYTES", "MAX_TOTAL_VERTICES", "MAX_JOINTS", "checked_add",
        "mesh triangle index is out of range", "Error::Rendering",
    ))
    manifest = MANIFEST.read_text()
    required_deps = (
        "flate2", "libremetaverse-prim-mesher", "libremetaverse-rendering-simple",
        "libremetaverse-structured-data", "stats_alloc",
    )
    missing_deps = [dependency for dependency in required_deps if dependency not in manifest]
    if missing_deps:
        raise SystemExit("issue 77 dependencies/evidence missing: " + ", ".join(missing_deps))

    require_markers(ASSET_TESTS, (
        "model_workflow_asset_round_trips_and_falls_back_deterministically",
        "rigged_mesh_preserves_skin_uv_tangent_material_and_ordering_domains",
        "RiggedSkinMath::build_inv_bind_matrices", "compressed_submesh_decode_has_stable_golden_output",
        "0xcb32_07be_6dea_73c8", "rebases_indices_in_face_order",
        "convex_hulls_decode_bounding_and_decomposed_domains",
        "malformed_offsets_indices_and_weights_return_source_context",
        "mirror_and_invert_update_coordinates_normals_and_tangents",
    ))
    require_markers(COMPAT, (
        "reviewed_meshfoundrytests_generatesimplemesh_box_returnsnonnull",
        "reviewed_meshfoundrytests_generatefacetedmesh_box_has6faces",
        "reviewed_meshfoundrytests_transformtexcoords_identitytransform_preservesuvs",
        "reviewed_meshfoundrytests_terrainmesh_allindicesinrange",
    ))
    require_markers(BENCH, ("fixture(240)", "57_600", "342_726", "Region::new"))
    require_markers(WORKSPACE, ("[profile.benchmark]", 'opt-level = 1', "incremental = false"))
    require_markers(STRUCTURED, ("pub fn deserialize_llsd_binary_prefix", "binary::deserialize_prefix"))
    require_markers(DOC, (
        "prim-local coordinates", "MeshFaceAux", "bitangent", "UV1", "RiggedSkinMath",
        "exactly-four-influence", "XOR winding", "64 MiB", "65,536", "6,000,000",
        "source primitive UUID", "57,600-vertex",
    ))
    require_markers(WORKFLOW, ("required-gate",))
    print(
        "issue 77 audit: native prim/sculpt/terrain and packed mesh pipelines, bounded LLSD/zlib, "
        "LOD, normals/tangents/UVs, materials, rigging, convex data, tests, benchmark, and docs are present"
    )


if __name__ == "__main__":
    main()
