#!/usr/bin/env python3
"""Export web/mobile GLBs by decimating an already-denoised source mesh."""

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("--target-triangles", type=int, required=True)
    parser.add_argument("--name", required=True)
    return parser.parse_args(argv)


def material() -> bpy.types.Material:
    result = bpy.data.materials.new("TN Polished Silver")
    result.use_nodes = True
    result.use_backface_culling = True
    result.diffuse_color = (0.972, 0.960, 0.915, 1.0)
    bsdf = result.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 result


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)

    bpy.ops.object.select_all(action="SELECT")
    bpy.ops.object.delete(use_global=False)
    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(material())
    for polygon in mesh.polygons:
        polygon.use_smooth = True

    mesh.calc_loop_triangles()
    source_triangles = len(mesh.loop_triangles)
    if args.target_triangles < source_triangles:
        modifier = obj.modifiers.new("Web silhouette optimization", type="DECIMATE")
        modifier.decimate_type = "COLLAPSE"
        modifier.ratio = args.target_triangles / source_triangles
        modifier.use_collapse_triangulate = True
        bpy.context.view_layer.objects.active = obj
        obj.select_set(True)
        bpy.ops.object.modifier_apply(modifier=modifier.name)
    for polygon in obj.data.polygons:
        polygon.use_smooth = True
    obj.data.calc_loop_triangles()

    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,
    )
    report = {
        "input": str(source),
        "output": str(output),
        "source_vertices": len(vertices),
        "source_triangles": source_triangles,
        "vertices": len(obj.data.vertices),
        "triangles": len(obj.data.loop_triangles),
        "bytes": output.stat().st_size,
        "smoothing_before_decimation": True,
        "material": {"metallic": 1.0, "roughness": 0.045},
    }
    output.with_suffix(".json").write_text(json.dumps(report, indent=2), encoding="utf-8")
    print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
