#!/usr/bin/env python3
"""Aggressively fair only the regular body while preserving the front ornament."""

from __future__ import annotations

import json
import math
import sys
from pathlib import Path

import bpy


CANDIDATES = {
    "medium": (0.34, 70),
    "clean": (0.42, 120),
    "max": (0.48, 180),
}


def angular_distance(a: float, b: float) -> float:
    return abs((a - b + math.pi) % (2 * math.pi) - math.pi)


def main() -> None:
    args = sys.argv[sys.argv.index("--") + 1 :]
    source = Path(args[0]).resolve()
    output = Path(args[1]).resolve()
    output.mkdir(parents=True, exist_ok=True)
    result = {}
    for name, (strength, iterations) in CANDIDATES.items():
        bpy.ops.object.select_all(action="SELECT")
        bpy.ops.object.delete(use_global=False)
        bpy.ops.import_scene.gltf(filepath=str(source))
        obj = max((candidate for candidate in bpy.context.scene.objects if candidate.type == "MESH"), key=lambda item: len(item.data.vertices))
        bpy.context.view_layer.objects.active = obj
        group = obj.vertex_groups.new(name="Protected ornament blend")
        for vertex in obj.data.vertices:
            coordinate = obj.matrix_world @ vertex.co
            distance = angular_distance(math.atan2(coordinate.y, coordinate.x), -math.pi / 2)
            start, end = math.radians(38), math.radians(82)
            t = min(1.0, max(0.0, (distance - start) / (end - start)))
            weight = t * t * (3.0 - 2.0 * t)
            group.add([vertex.index], weight, "REPLACE")
        modifier = obj.modifiers.new(name="Curvature fairing", type="LAPLACIANSMOOTH")
        modifier.vertex_group = group.name
        modifier.lambda_factor = strength
        modifier.lambda_border = strength * 0.08
        modifier.iterations = iterations
        modifier.use_volume_preserve = False
        modifier.use_normalized = True
        bpy.ops.object.modifier_apply(modifier=modifier.name)
        for polygon in obj.data.polygons:
            polygon.use_smooth = True
        path = output / f"reconstructed-faired-{name}.glb"
        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(path), 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,
        )
        obj.data.calc_loop_triangles()
        result[name] = {
            "strength": strength, "iterations": iterations, "path": str(path),
            "vertices": len(obj.data.vertices), "triangles": len(obj.data.loop_triangles),
            "bytes": path.stat().st_size, "dimensions": list(obj.dimensions),
        }
    (output / "faired-candidates.json").write_text(json.dumps(result, indent=2), encoding="utf-8")
    print("TN_FAIRED_CANDIDATES", json.dumps(result))


if __name__ == "__main__":
    main()
