#!/usr/bin/env python3
"""Rebuild an unchanged-topology NPZ candidate as a polished-silver GLB."""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

import bpy
import numpy as np


def parse_args() -> argparse.Namespace:
    argv = sys.argv[sys.argv.index("--") + 1 :] if "--" in sys.argv else []
    parser = argparse.ArgumentParser()
    parser.add_argument("--input", required=True)
    parser.add_argument("--output", required=True)
    parser.add_argument("--name", default="TN_Silver_Denoised")
    return parser.parse_args(argv)


def clear_scene() -> None:
    bpy.ops.object.select_all(action="SELECT")
    bpy.ops.object.delete(use_global=False)


def make_material() -> bpy.types.Material:
    material = bpy.data.materials.new("TN Polished Silver")
    material.use_nodes = True
    material.use_backface_culling = True
    material.diffuse_color = (0.972, 0.960, 0.915, 1.0)
    bsdf = material.node_tree.nodes.get("Principled BSDF")
    bsdf.inputs["Base Color"].default_value = (0.972, 0.960, 0.915, 1.0)
    bsdf.inputs["Metallic"].default_value = 1.0
    bsdf.inputs["Roughness"].default_value = 0.045
    return material


def main() -> None:
    args = parse_args()
    source = Path(args.input).resolve()
    output = Path(args.output).resolve()
    output.parent.mkdir(parents=True, exist_ok=True)
    data = np.load(source)
    vertices = np.asarray(data["vertices"], dtype=np.float32)
    faces = np.asarray(data["faces"], dtype=np.int32)
    custom_normals = (
        np.asarray(data["normals"], dtype=np.float32) if "normals" in data.files else None
    )

    clear_scene()
    mesh = bpy.data.meshes.new(f"{args.name}_Mesh")
    mesh.from_pydata(vertices.tolist(), [], faces.tolist())
    mesh.validate(verbose=False, clean_customdata=False)
    mesh.update(calc_edges=True)
    obj = bpy.data.objects.new(args.name, mesh)
    bpy.context.collection.objects.link(obj)
    mesh.materials.append(make_material())
    for polygon in mesh.polygons:
        polygon.use_smooth = True
    if custom_normals is not None:
        if custom_normals.shape != vertices.shape:
            raise ValueError(
                f"Expected normals shaped {vertices.shape}, got {custom_normals.shape}"
            )
        mesh.normals_split_custom_set_from_vertices(custom_normals.tolist())

    bpy.ops.object.select_all(action="DESELECT")
    obj.select_set(True)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.export_scene.gltf(
        filepath=str(output),
        export_format="GLB",
        use_selection=True,
        export_apply=True,
        export_yup=True,
        export_normals=True,
        export_tangents=False,
        export_texcoords=False,
        export_materials="EXPORT",
        export_animations=False,
        export_cameras=False,
        export_lights=False,
        export_draco_mesh_compression_enable=False,
    )

    metadata = {
        "input": str(source),
        "output": str(output),
        "bytes": output.stat().st_size,
        "vertices": len(vertices),
        "triangles": len(faces),
        "custom_normals": custom_normals is not None,
        "material": {
            "metallic": 1.0,
            "roughness": 0.045,
            "base_color": [0.972, 0.960, 0.915, 1.0],
        },
    }
    output.with_suffix(".json").write_text(
        json.dumps(metadata, indent=2), encoding="utf-8"
    )
    print(json.dumps(metadata, indent=2))


if __name__ == "__main__":
    main()
