import bpy
import bmesh
import os


ROOT = "/home/vela/workspace/domain/tn-silver/web/tn-site"
SOURCE = os.path.join(ROOT, "prototype/assets/noble-shield/ring-desktop.glb")
DESKTOP = os.path.join(
    ROOT,
    "prototype/assets/landing-flow/noble-ring-smooth-desktop.glb",
)
MOBILE = os.path.join(
    ROOT,
    "prototype/assets/landing-flow/noble-ring-smooth-mobile.glb",
)


def select_only(obj):
    bpy.ops.object.select_all(action="DESELECT")
    obj.select_set(True)
    bpy.context.view_layer.objects.active = obj


def apply_modifier(obj, name):
    select_only(obj)
    bpy.ops.object.modifier_apply(modifier=name)


def decimate_to(obj, target_faces):
    face_count = max(1, len(obj.data.polygons))
    if face_count <= target_faces:
        return
    modifier = obj.modifiers.new(name="LandingDecimate", type="DECIMATE")
    modifier.decimate_type = "COLLAPSE"
    modifier.ratio = target_faces / face_count
    modifier.use_collapse_triangulate = True
    apply_modifier(obj, modifier.name)


def export_selected(obj, filepath):
    select_only(obj)
    bpy.ops.export_scene.gltf(
        filepath=filepath,
        export_format="GLB",
        use_selection=True,
        export_materials="NONE",
        export_cameras=False,
        export_lights=False,
        export_yup=True,
    )


def mesh_metrics(obj):
    bm = bmesh.new()
    bm.from_mesh(obj.data)
    bm.edges.ensure_lookup_table()
    bm.faces.ensure_lookup_table()
    boundary_edges = sum(1 for edge in bm.edges if len(edge.link_faces) != 2)
    unseen = set(bm.faces)
    component_sizes = []
    while unseen:
        seed = unseen.pop()
        stack = [seed]
        count = 1
        while stack:
            face = stack.pop()
            for edge in face.edges:
                for neighbor in edge.link_faces:
                    if neighbor in unseen:
                        unseen.remove(neighbor)
                        stack.append(neighbor)
                        count += 1
        component_sizes.append(count)
    bm.free()
    return {
        "vertices": len(obj.data.vertices),
        "faces": len(obj.data.polygons),
        "boundary_edges": boundary_edges,
        "components": len(component_sizes),
        "largest_component": max(component_sizes, default=0),
    }


bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
bpy.ops.import_scene.gltf(filepath=SOURCE)

source = next(obj for obj in bpy.context.scene.objects if obj.type == "MESH")
select_only(source)
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

source.data.remesh_voxel_size = 0.0065
source.data.remesh_voxel_adaptivity = 0.0
source.data.use_remesh_fix_poles = True
source.data.use_remesh_preserve_volume = True
bpy.ops.object.voxel_remesh()

smooth = source.modifiers.new(name="LandingSurfaceSmooth", type="SMOOTH")
smooth.factor = 0.22
smooth.iterations = 10
apply_modifier(source, smooth.name)

for polygon in source.data.polygons:
    polygon.use_smooth = True
source.data.update()

master_mesh = source.data.copy()

desktop = source
desktop.name = "TN_Landing_Noble_Ring_Smooth_Desktop"
decimate_to(desktop, 120_000)
for polygon in desktop.data.polygons:
    polygon.use_smooth = True
desktop.data.update()
print("DESKTOP_METRICS", mesh_metrics(desktop))
export_selected(desktop, DESKTOP)

mobile = bpy.data.objects.new(
    "TN_Landing_Noble_Ring_Smooth_Mobile",
    master_mesh.copy(),
)
bpy.context.collection.objects.link(mobile)
mobile.matrix_world = source.matrix_world.copy()
decimate_to(mobile, 48_000)
for polygon in mobile.data.polygons:
    polygon.use_smooth = True
mobile.data.update()
print("MOBILE_METRICS", mesh_metrics(mobile))
export_selected(mobile, MOBILE)
