import bpy
import bmesh
import os
from ..cAPI import SimulationAPI
from .. import utils
from ..utils import create_binding_constraint
from ..utils import getSelectedPoints
import numpy as np

class HI_PHY_OT_CreateBindingConstraint(bpy.types.Operator):
    bl_idname = "hi_phy.create_binding_constraint"
    bl_label = "Hi Phy Create Binding Constraint"
    bl_options = {'REGISTER', 'UNDO_GROUPED'}

    binding_simulation_object_1: bpy.props.StringProperty(name="Binding Simulation Object")
    binding_simulation_object_2: bpy.props.StringProperty(name="Binding Simulation Object")
    binding_distance: bpy.props.FloatProperty(name="Binding Distance")
    zero_length_binding: bpy.props.BoolProperty(name="Zero Length Binding")
    curve_self_binding : bpy.props.BoolProperty(name="Curve Can Bind Itself")

    def invoke(self, context, event):
        for obj in bpy.context.selected_objects:
            if utils.isSimulationObject(obj) and self.binding_simulation_object_1 == "":
                self.binding_simulation_object_1 = obj.name
                # Set object 2 as well, in case only one object is selected
                self.binding_simulation_object_2 = obj.name
            elif utils.isSimulationObject(obj):
                self.binding_simulation_object_2 = obj.name
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        layout = self.layout
        layout.prop(self, "binding_simulation_object_1")
        layout.prop(self, "binding_simulation_object_2")
        layout.prop(self, "binding_distance")
        layout.prop(self, "zero_length_binding")
        layout.prop(self, "curve_self_binding")

    def execute(self, context):
        depsgraph = bpy.context.evaluated_depsgraph_get()
        # evaluate it so we can get the correct topology after modifiers
        sim_obj_1 = bpy.data.objects[self.binding_simulation_object_1].evaluated_get(depsgraph)
        sim_obj_2 = bpy.data.objects[self.binding_simulation_object_2].evaluated_get(depsgraph)
        # we can't get position attributes from mesh unless we are in object mode
        bk_mode = bpy.context.object.mode
        bpy.ops.object.mode_set(mode='OBJECT')
        if sim_obj_1.type == 'MESH' and sim_obj_2.type == 'MESH':
            if not create_binding_constraint.createMeshMesh(sim_obj_1, sim_obj_2, self.binding_distance, sim_obj_1.name + "_to_" + sim_obj_2.name + "_binding_constraint", self.zero_length_binding, self):
                bpy.ops.object.mode_set(mode=bk_mode)
                return {'CANCELLED'}
        elif sim_obj_1.type == 'CURVES' and sim_obj_2.type == 'CURVES':
            if not create_binding_constraint.createCurvesCurves(sim_obj_1, sim_obj_2, self.binding_distance, sim_obj_1.name + "_to_" + sim_obj_2.name + "_binding_constraint", self.zero_length_binding, self.curve_self_binding, self):
                bpy.ops.object.mode_set(mode=bk_mode)
                return {'CANCELLED'}
        elif sim_obj_1.type == 'MESH' and sim_obj_2.type == 'CURVES':
            if not create_binding_constraint.createMeshCurve(sim_obj_1, sim_obj_2, self.binding_distance, sim_obj_1.name + "_to_" + sim_obj_2.name + "_binding_constraint", self.zero_length_binding, self):
                bpy.ops.object.mode_set(mode=bk_mode)
                return {'CANCELLED'}
        elif sim_obj_1.type == 'CURVES' and sim_obj_2.type == 'MESH':
            if not create_binding_constraint.createMeshCurve(sim_obj_2, sim_obj_1, self.binding_distance, sim_obj_1.name + "_to_" + sim_obj_2.name + "_binding_constraint", self.zero_length_binding, self):
                bpy.ops.object.mode_set(mode=bk_mode)
                return {'CANCELLED'}
        else:
            self.report({"ERROR"}, "Unsupported object types for binding constraint")
            return{'CANCELLED'}
        bpy.ops.object.mode_set(mode=bk_mode)
        return {'FINISHED'}

__CLASSES__ = [
    HI_PHY_OT_CreateBindingConstraint
]

# Define the menu draw function
def menu_draw(self, context):
    # TODO: only add to the menu if the edited object is a valid simulation object
    layout = self.layout
    layout.operator_context = 'INVOKE_DEFAULT'
    layout.operator("hi_phy.create_binding_constraint")

def register():
    for class_ in __CLASSES__:
        bpy.utils.register_class(class_)
        bpy.types.VIEW3D_MT_object_context_menu.append(menu_draw)


def unregister():
    for class_ in reversed(__CLASSES__):
        bpy.types.VIEW3D_MT_object_context_menu.remove(menu_draw)
        bpy.utils.unregister_class(class_)
