import bpy
import os, sys, time
import json
from mathutils import Matrix, Quaternion
argv = sys.argv
argv = argv[argv.index("--") + 1:]

incpath = os.path.dirname(__file__)

sys.path.insert(0, incpath)
outdir = argv[0]

basis_change = Matrix((
    (1, 0, 0, 0),
    (0, 0, 1, 0),
    (0, -1, 0, 0),
    (0, 0, 0, 1)
))

def export_root_objects_to_gltf(output_dir):
    # Ensure the output directory exists
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # Deselect all objects
    bpy.ops.object.select_all(action='DESELECT')

    # Iterate through all objects in the scene
    for obj in bpy.context.scene.objects:
        # Check if the object has no parent and has children
        # The original request specifies "objects having no parent with children".
        # This condition captures those that are explicitly root objects of a hierarchy.
        if obj.parent is None:
            # Select the root object and all its children

            print(obj.name)
            if not obj.name.startswith("furniture-"):
                continue
            desc = {}
            desc["name"] = obj.name.replace("furniture-","")
            desc["mesh"] = obj.name + ".glb"
            if "furniture_tags" in obj:
                mtags = obj["furniture_tags"]
                if "," in mtags:
                    atags = [m.strip() for m in mtags.split(",")]
                    desc["tags"] = atags
                else:
                    desc["tags"] = [mtags]
            else:
                desc["tags"] = []
            desc["sensors"] = []
            desc["actions"] = []
            desc["positions"] = []
            for child in obj.children:
                if child.name.startswith("action-"):
                    if not "action" in child:
                        continue
                    if not "height" in child:
                        continue
                    if not "radius" in child:
                        continue
                    local_matrix = child.matrix_local
                    ogre_local_matrix = basis_change @ local_matrix @ basis_change.inverted()
                    local_pos_d = ogre_local_matrix.to_translation()
                    local_rot_d = ogre_local_matrix.to_quaternion()
                    local_pos = [round(x, 4) for x in local_pos_d]
                    local_rot = [round(x, 4) for x in local_rot_d]
                    action = {}
                    action["position_x"] = local_pos[0]
                    action["position_y"] = local_pos[1]
                    action["position_z"] = local_pos[2]
                    action["rotation_w"] = local_rot[0]
                    action["rotation_x"] = local_rot[1]
                    action["rotation_y"] = local_rot[2]
                    action["rotation_z"] = local_rot[3]
                    action["height"] = child["height"]
                    action["radius"] = child["radius"]
                    action["action"] = child["action"]
                    if "action_text" in child:
                        action["action_text"] = child["action_text"]
                    else:
                        action["action_text"] = child["action"].capitalize()
                    if "name" in child:
                        action["name"] = child["name"]
                    else:
                        action["name"] = desc["name"] + "_" + str(len(desc["actions"]))
                    if "tags" in child:
                        atags = child["tags"]
                        if "," in atags:
                            atags = [m.strip() for m in atags.split(",")]
                            action["tags"] = atags
                        else:
                            action["tags"] = [atags]
                    else:
                        action["tags"] = []
                    for k, v in child.items():
                        if k.startswith("goap_prereq_"):
                            action[k] = v
                        elif k.startswith("goap_effect_"):
                            action[k] = v
                    action["furniture"] = {}
                    action["furniture"]["name"] = desc["name"]
                    action["furniture"]["tags"] = desc["tags"]
                    action["positions"] = []
                    for schild in child.children:
                        if schild.name.startswith("position-"):
                            local_matrix = schild.matrix_local
                            ogre_local_matrix = basis_change @ local_matrix @ basis_change.inverted()
                            local_pos_d = ogre_local_matrix.to_translation()
                            local_rot_d = ogre_local_matrix.to_quaternion()
                            local_pos = [round(x, 4) for x in local_pos_d]
                            local_rot = [round(x, 4) for x in local_rot_d]
                            position = {}
                            if "name" in schild:
                                position["name"] = schild["name"]
                            if "type" in schild:
                                position["type"] = schild["type"]
                            position["position_x"] = local_pos[0]
                            position["position_y"] = local_pos[1]
                            position["position_z"] = local_pos[2]
                            position["rotation_w"] = local_rot[0]
                            position["rotation_x"] = local_rot[1]
                            position["rotation_y"] = local_rot[2]
                            position["rotation_z"] = local_rot[3]
                            action["positions"].append(position)
                    desc["actions"].append(action)
                if child.name.startswith("position-"):
                    local_matrix = child.matrix_local
                    ogre_local_matrix = basis_change @ local_matrix @ basis_change.inverted()
                    local_pos_d = ogre_local_matrix.to_translation()
                    local_rot_d = ogre_local_matrix.to_quaternion()
                    local_pos = [round(x, 4) for x in local_pos_d]
                    local_rot = [round(x, 4) for x in local_rot_d]
                    position = {}
                    if "name" in child:
                        position["name"] = child["name"]
                    if "type" in child:
                        position["type"] = child["type"]
                    position["position_x"] = local_pos[0]
                    position["position_y"] = local_pos[1]
                    position["position_z"] = local_pos[2]
                    position["rotation_w"] = local_rot[0]
                    position["rotation_x"] = local_rot[1]
                    position["rotation_y"] = local_rot[2]
                    position["rotation_z"] = local_rot[3]
                    desc["positions"].append(position)

            obj.select_set(True)
            for child in obj.children_recursive:
                child.select_set(True)

            obj.location = (0.0, 0.0, 0.0)
            
            # Set the root object as the active object for the export operator
            bpy.context.view_layer.objects.active = obj

            # Define the output file path
            file_path = os.path.join(output_dir, f"{obj.name}.glb")
            
            # Export the selected objects to a glTF file
            bpy.ops.export_scene.gltf(filepath=file_path,
                    use_selection=True,
                    check_existing=False,
                    export_format='GLB',
                    export_texture_dir='textures', export_texcoords=True,
                    export_normals=True,
                    export_tangents=True,
                    export_materials='EXPORT',
                    export_colors=True,
                    use_mesh_edges=False,
                    use_mesh_vertices=False,
                    export_cameras=False,
                    use_visible=False,
                    use_renderable=False,
                    export_yup=True,
                    export_apply=True,
                    export_animations=True,
                    export_force_sampling=True,
                    export_def_bones=False,
                    export_current_frame=False,
                    export_morph=True,
                    export_morph_animation=False,
                    export_morph_normal=True,
                    export_morph_tangent=True,
                    export_lights=False,
                    export_skins=True)

            # Deselect all objects for the next iteration
            bpy.ops.object.select_all(action='DESELECT')
            
            print(f"Exported {obj.name} and its children to {file_path}")
            with open(file_path + ".json", "w") as json_data:
                json.dump(desc, json_data)

export_root_objects_to_gltf(outdir)

