# Blender (3.2) batch: SKCombat FBX → glTF (separate) with the right Unity texture, 1 unit = 1 board cell.
# Run: blender -b --factory-startup --python convert.py -- <jobs.json> <out dir> <textures dir>
# jobs.json: [{"src": fbx path, "pack": "nature-props", "name": "bonfire-lit", "tex": "nature", "kind": "opaque|alpha|glow"}]
import bpy, bmesh, sys, os, json, mathutils
jobs_path, out_dir, tex_dir = sys.argv[sys.argv.index('--') + 1:]
jobs = json.load(open(jobs_path))
CELL = 0.015  # one SKCombat floor tile in Blender units after the FBX's own 0.01 scale
done = []
for j in jobs:
    bpy.ops.wm.read_factory_settings(use_empty=True)
    try:
        for src in j.get('srcs') or [j['src']]:
            bpy.ops.import_scene.fbx(filepath=src)
    except Exception as e:
        print('SKIP', j['src'], e); continue
    meshes = [o for o in bpy.data.objects if o.type == 'MESH']
    if not meshes:
        print('EMPTY', j['src']); continue
    # flatten: one plain mesh in world space (no empties / bone-like nodes), sized in board cells
    for o in bpy.data.objects:
        o.animation_data_clear()  # some files carry a take that would re-pose them on export
    for a in list(bpy.data.actions):
        bpy.data.actions.remove(a)
    for o in meshes:
        o.data = o.data.copy()
        o.data.transform(o.matrix_world)
        o.parent = None
        o.location = (0, 0, 0); o.rotation_euler = (0, 0, 0); o.scale = (1, 1, 1)
        o.matrix_world = mathutils.Matrix.Identity(4)
    for o in [o for o in bpy.data.objects if o.type != 'MESH']:
        bpy.data.objects.remove(o, do_unlink=True)
    bpy.ops.object.select_all(action='DESELECT')
    for o in meshes: o.select_set(True)
    bpy.context.view_layer.objects.active = meshes[0]
    if len(meshes) > 1: bpy.ops.object.join()
    obj = bpy.context.view_layer.objects.active
    me = obj.data
    me.transform(mathutils.Matrix.Scale(1 / CELL, 4))
    bm = bmesh.new(); bm.from_mesh(me)
    # floor tiles are columns sunk into the ground: keep only what is above `cut` (cells below their top, z = 0)
    if j.get('cut') is not None:
        geom = bm.verts[:] + bm.edges[:] + bm.faces[:]
        bmesh.ops.bisect_plane(bm, geom=geom, plane_co=(0, 0, j['cut']), plane_no=(0, 0, 1), clear_inner=True)
    # origin: the middle of the model's base (x, y); its height stays (props stand at 0, tiles have their top at 0)
    zs = [v.co.z for v in bm.verts]
    if not zs:
        print('EMPTY', j['src']); bm.free(); continue
    zmin, zmax = min(zs), max(zs)
    lim = zmin + max(0.02, (zmax - zmin) * 0.15)
    foot = [v.co for v in bm.verts if v.co.z <= lim]
    cx = (min(c.x for c in foot) + max(c.x for c in foot)) / 2
    cy = (min(c.y for c in foot) + max(c.y for c in foot)) / 2
    bmesh.ops.translate(bm, verts=bm.verts, vec=(-cx, -cy, 0 if j.get('cut') is not None else -zmin))
    bm.to_mesh(me); bm.free(); me.update()
    meshes = [obj]
    # one material for every slot: the atlas this model was painted on
    img = bpy.data.images.load(os.path.join(tex_dir, j['tex'] + ('.png' if j['kind'] == 'alpha' or j['tex'] == 'basic' else '.jpg')))
    img.name = j['tex']
    mat = bpy.data.materials.new('sk-' + j['tex'])
    mat.use_nodes = True
    nt = mat.node_tree
    bsdf = nt.nodes.get('Principled BSDF')
    tn = nt.nodes.new('ShaderNodeTexImage')
    tn.image = img
    nt.links.new(tn.outputs['Color'], bsdf.inputs['Base Color'])
    bsdf.inputs['Roughness'].default_value = 0.85
    bsdf.inputs['Specular'].default_value = 0.2
    if j['kind'] == 'alpha':
        nt.links.new(tn.outputs['Alpha'], bsdf.inputs['Alpha'])
        mat.blend_method = 'CLIP'
        mat.alpha_threshold = 0.4
        mat.use_backface_culling = False
    if j['kind'] == 'glow':
        nt.links.new(tn.outputs['Color'], bsdf.inputs['Emission'])
    for o in meshes:
        o.data.materials.clear()
        o.data.materials.append(mat)
    pack_dir = os.path.join(out_dir, j['pack'])
    os.makedirs(pack_dir, exist_ok=True)
    bpy.ops.export_scene.gltf(filepath=os.path.join(pack_dir, j['name'] + '.gltf'), export_format='GLTF_SEPARATE',
                              export_texture_dir='tex', export_materials='EXPORT', export_yup=True, export_apply=True,
                              export_cameras=False, export_lights=False, export_animations=False)
    done.append(j['name'])
print('CONVERTED', len(done))
