import bpy
from ...utils_debug import debug_warn
from .animator_utils import string_to_hash
from ...utils import generateRandomStringId



class NEEDLE_UL_AnimatorParametersList(bpy.types.UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
        layout = layout.box()
        item.draw(context, layout)
    


##################################
# Parameter

def typeToNumber(paramType):
    if paramType == "BOOL":
        return 4
    elif paramType == "INT":
        return 3
    elif paramType == "FLOAT":
        return 1
    elif paramType == "TRIGGER":
        return 9
    return -1

parameterTypes = [
    ("FLOAT", "Float", "Float"),
    ("INT", "Int", "Int"),
    ("BOOL", "Bool", "Bool"),
    ("TRIGGER", "Trigger", "Trigger"),
]
def getParameterTypes(self, context):
    global parameterTypes
    return parameterTypes

class Parameter(bpy.types.PropertyGroup):

    def serialize(self, serializer):
        return {
            "name": self.name,
            "type": typeToNumber(self.parameterType),
            "hash": string_to_hash(self.parameterId),
            "value": self.getValue()
        }

    def getValue(self):
        if self.parameterType == "BOOL":
            return self.boolValue
        elif self.parameterType == "FLOAT":
            return self.floatValue
        elif self.parameterType == "INT":
            return self.intValue
        return 0


    parameterId: bpy.props.StringProperty()
    name: bpy.props.StringProperty(name="Name", default="Parameter")
    parameterType: bpy.props.EnumProperty(name="Type", items=getParameterTypes)

    boolValue: bpy.props.BoolProperty(name="Value", default=False)
    floatValue: bpy.props.FloatProperty(name="Value", default=0.0)
    intValue: bpy.props.IntProperty(name="Value", default=0)
    
    def draw(self, context, layout):
        layout = layout.row()
        layout.prop(self, "name", text="")
        layout.prop(self, "parameterType", text="")
        if self.parameterType == "BOOL":
            layout.prop(self, "boolValue", text="") 
        elif self.parameterType == "FLOAT":
            layout.prop(self, "floatValue", text="")
        elif self.parameterType == "INT":
            layout.prop(self, "intValue", text="")
        remove = layout.operator("needle_animator.remove_parameter", text="", icon="X")
        remove.parameterId = self.parameterId


class addParameterOp(bpy.types.Operator):
    bl_idname = "needle_animator.add_parameter"
    bl_label = "Add Parameter"
    bl_description = "Add a new parameter to the animator"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        node = hasattr(context, "node") and context.node or context.active_node
        param = node.parameters.add()
        param.name = "New Parameter"
        param.parameterId = generateRandomStringId(10)
        return {'FINISHED'}


class removeParameterOp(bpy.types.Operator):
    bl_idname = "needle_animator.remove_parameter"
    bl_label = "Remove Parameter"
    bl_description = "Remove a parameter from the animator"
    bl_options = {'REGISTER', 'UNDO'}

    parameterId: bpy.props.StringProperty()

    def execute(self, context):
        node = hasattr(context, "node") and context.node or context.active_node
        for i in range(len(node.parameters)):
            param = node.parameters[i]
            if param.parameterId == self.parameterId:
                node.parameters.remove(i)
                break
        return {'FINISHED'}



##############################
# Conditions
def getParameters(context: bpy.types.Context, transitionId:str = None):
    if not hasattr(context, "active_node"):

        # find animatorcontroller in blend file that this condition belongs to
        # then return its parameters
        if transitionId != None:
            for group in context.blend_data.node_groups:
                if group.bl_idname == "NEEDLE_AnimatorController":
                    foundAnimatorController = False
                    for node in group.nodes:
                        # get transitions and try to find the transitionId
                        if node.bl_idname == "AnimatorState":
                            for transition in node.transitions:
                                if foundAnimatorController:
                                    break;
                                if transition.transitionId == transitionId:
                                    foundAnimatorController = True
                    if not foundAnimatorController:
                        continue
                    for node in group.nodes:
                        if node.bl_idname == "AnimatorProperties":
                            return node.parameters
                    pass
        return None
    
    # this is the old hacky way of getting the parameters for the selected animatorcontroller
    node = context.active_node
    if not hasattr(node, "id_data"):
        return None
    # get tree
    tree = node.id_data
    for node in tree.nodes:
        if node.bl_idname == "AnimatorProperties":
            return node.parameters
    return None

def getConditionTypes(self, context):
    availableConditions = []
    # get tree
    parameters = getParameters(context, self.transitionId)
    if parameters:
        for param in parameters:
            availableConditions.append((param.parameterId, param.name, param.name))
    return availableConditions

def onConditionParameterChanged(self, context):
    parameters = getParameters(context)
    if parameters:
        for param in parameters:
            if param.parameterId == self.parameterEnum:
                self.parameter = param
                break
    pass



conditionTypes = [
    ("IF", "if", "If"),
    ("IFNOT", "if not", "If Not"),
    ("GREATER", "greater", "Greater"),
    ("LESS", "less", "Less"),
    ("EQUAL", "equals", "Equal"),
    ("NOTEQUAL", "not equal", "Not Equal"),
] 

def getConditionTypeValue(conditionType) -> int: 
    if conditionType == "IF":
        return 1
    elif conditionType == "IFNOT":
        return 2
    elif conditionType == "GREATER":
        return 3
    elif conditionType == "LESS":
        return 4
    elif conditionType == "EQUAL":
        return 6
    elif conditionType == "NOTEQUAL":
        return 7
    

class Condition(bpy.types.PropertyGroup):

    def serialize(self, serializer):
        context = serializer.animatorSerializationContext
        if context.parameters:
            for param in context.parameters:
                # if this is the parameter we're looking for?
                if param.parameterId == self.parameterEnum:

                    # handle bool conditions (they just use the mode and not the threshold)
                    mode = self.mode;
                    if param.parameterType == "BOOL":
                        if self.boolValue:
                            mode = "IF"
                        # a bool condition is actually in the "IF NOT" mode
                        else:
                            mode = "IFNOT"
                    
                    res = {
                        "parameter": param.name,
                        "mode" : getConditionTypeValue(mode),
                        "threshold" : self.getThreshold(param.parameterType),
                    }
                    return res

    def getThreshold(self, parameterType) -> float:
        if parameterType == "FLOAT":
            return self.floatValue
        elif parameterType == "INT":
            return self.intValue
        elif parameterType == "BOOL":
            return self.boolValue
        return 1


    transitionId: bpy.props.StringProperty()
    conditionId: bpy.props.StringProperty()

    parameterEnum: bpy.props.EnumProperty(name="Parameter", items=getConditionTypes, update=onConditionParameterChanged)
    # parameter: bpy.props.PointerProperty(type=Parameter)

    boolValue: bpy.props.BoolProperty(name="Value", default=False)
    floatValue: bpy.props.FloatProperty(name="Value", default=0.0)
    intValue: bpy.props.IntProperty(name="Value", default=0)

    mode: bpy.props.EnumProperty(name="Mode", items=conditionTypes)

    def draw(self, context, layout):
        layout = layout.row()
        layout.prop(self, "parameterEnum", text="")
        
        parameters = getParameters(context)
        if parameters:
            for param in parameters:
                if param.parameterId == self.parameterEnum:
                    if param.parameterType == "BOOL":
                        layout.prop(self, "boolValue", text="") 
                    elif param.parameterType == "FLOAT":
                        layout.prop(self, "mode", text="")
                        layout.prop(self, "floatValue", text="")
                    elif param.parameterType == "INT":
                        layout.prop(self, "mode", text="")
                        layout.prop(self, "intValue", text="")
                    break
        
        removeOp = layout.operator("needle_animator.remove_condition", text="", icon="X")
        removeOp.conditionId = self.conditionId
        removeOp.transitionId = self.transitionId


class addConditionOp(bpy.types.Operator):
    bl_idname = "needle_animator.add_condition"
    bl_label = "Add Condition"
    bl_description = "Add a new condition to transition"
    bl_options = {'REGISTER', 'UNDO'}

    transitionId : bpy.props.StringProperty()

    def execute(self, context):
        node = hasattr(context, "node") and context.node or context.active_node
        transition = node.getTransition(self.transitionId)
        condition = transition.conditions.add()
        condition.transitionId = self.transitionId
        condition.conditionId = generateRandomStringId(5)
        return {'FINISHED'}

class removeConditionOp(bpy.types.Operator):
    bl_idname = "needle_animator.remove_condition"
    bl_label = "Remove Condition"
    bl_description = "Remove a condition from transition"
    bl_options = {'REGISTER', 'UNDO'}

    transitionId: bpy.props.StringProperty()
    conditionId: bpy.props.StringProperty()

    def execute(self, context):
        node = hasattr(context, "node") and context.node or context.active_node
        transition = node.getTransition(self.transitionId)
        transition.removeCondition(self.conditionId)
        return {'FINISHED'}


def register():
    bpy.utils.register_class(NEEDLE_UL_AnimatorParametersList)
    bpy.utils.register_class(Parameter)
    bpy.utils.register_class(addParameterOp)
    bpy.utils.register_class(removeParameterOp)
    bpy.utils.register_class(Condition)
    bpy.utils.register_class(addConditionOp)
    bpy.utils.register_class(removeConditionOp)
    pass

def unregister():
    bpy.utils.unregister_class(NEEDLE_UL_AnimatorParametersList)
    bpy.utils.unregister_class(Parameter)
    bpy.utils.unregister_class(addParameterOp)
    bpy.utils.unregister_class(removeParameterOp)
    bpy.utils.unregister_class(Condition)
    bpy.utils.unregister_class(addConditionOp)
    bpy.utils.unregister_class(removeConditionOp)
    pass