Make it complex import bpy
from bpy.props import EnumProperty, FloatProperty, IntProperty
import math

class FanClearAnimationOperator(bpy.types.Operator):
    """Clear animation data of selected objects and reset values"""
    bl_idname = "object.clear_animation"
    bl_label = "Clear Animation"

    def execute(self, context):
        for obj in context.selected_objects:
            obj.animation_data_clear()
            obj.rotation_euler = (0, 0, 0)  # Reset rotation to zero
        return {'FINISHED'}

class FanAnimationOperator(bpy.types.Operator):
    """Animate the rotation of selected objects as if they are fans"""
    bl_idname = "object.fan_animation"
    bl_label = "Fan Animation"

    def apply_curve_rotation(self, start_rotation, end_rotation, frame, total_frames, ease):
        progress = (frame / total_frames)
        if ease == 'LINEAR':
            return start_rotation + (end_rotation - start_rotation) * progress
        elif ease == 'EASE_IN':
            return start_rotation + (end_rotation - start_rotation) * (progress ** 3)
        elif ease == 'EASE_OUT':
            return start_rotation + (end_rotation - start_rotation) * (1 - (1 - progress) ** 3)
        elif ease == 'EASE_IN_OUT':
            if progress < 0.5:
                return start_rotation + (end_rotation - start_rotation) * (4 * progress ** 3)
            else:
                return start_rotation + (end_rotation - start_rotation) * (1 - (-2 * progress + 2)**3 / 2)

    def execute(self, context):
        rotation_x = math.radians(context.scene.fan_rotation_x)
        rotation_y = math.radians(context.scene.fan_rotation_y)
        rotation_z = math.radians(context.scene.fan_rotation_z)
        end_rotation_x = math.radians(context.scene.fan_end_rotation_x)
        end_rotation_y = math.radians(context.scene.fan_end_rotation_y)
        end_rotation_z = math.radians(context.scene.fan_end_rotation_z)
        start_frame_x = context.scene.fan_start_frame_x
        end_frame_x = context.scene.fan_end_frame_x
        start_frame_y = context.scene.fan_start_frame_y
        end_frame_y = context.scene.fan_end_frame_y
        start_frame_z = context.scene.fan_start_frame_z
        end_frame_z = context.scene.fan_end_frame_z
        wobble_amplitude = math.radians(context.scene.fan_wobble_amplitude)
        wobble_frequency = context.scene.fan_wobble_frequency
        wobble_start_frame = context.scene.fan_wobble_start_frame
        wobble_end_frame = context.scene.fan_wobble_end_frame
        ease_x = context.scene.fan_easing_x
        ease_y = context.scene.fan_easing_y
        ease_z = context.scene.fan_easing_z
        ease_wobble = context.scene.fan_easing_wobble

        for obj in context.selected_objects:
            obj.rotation_mode = 'XYZ'

            # Set initial rotation to zero at frame 1
            obj.rotation_euler = (0, 0, 0)
            obj.keyframe_insert(data_path="rotation_euler", index=0, frame=1)
            obj.keyframe_insert(data_path="rotation_euler", index=1, frame=1)
            obj.keyframe_insert(data_path="rotation_euler", index=2, frame=1)

            def apply_wobble(angle, frame, axis):
                if wobble_start_frame <= frame <= wobble_end_frame:
                    wobble_progress = (frame - wobble_start_frame) / (wobble_end_frame - wobble_start_frame)
                    if ease_wobble == 'LINEAR':
                        wobble_factor = wobble_progress
                    elif ease_wobble == 'EASE_IN':
                        wobble_factor = wobble_progress ** 3
                    elif ease_wobble == 'EASE_OUT':
                        wobble_factor = 1 - (1 - wobble_progress) ** 3
                    elif ease_wobble == 'EASE_IN_OUT':
                        if wobble_progress < 0.5:
                            wobble_factor = 4 * wobble_progress ** 3
                        else:
                            wobble_factor = 1 - (-2 * wobble_progress + 2)**3 / 2
                    wobble = wobble_amplitude * math.sin(wobble_frequency * frame) * wobble_factor
                    return angle + wobble if axis == 'X' else (angle + wobble if axis == 'Y' else angle + wobble)
                else:
                    return angle
            
            total_frames_x = end_frame_x - start_frame_x if end_frame_x != start_frame_x else 1
            total_frames_y = end_frame_y - start_frame_y if end_frame_y != start_frame_y else 1
            total_frames_z = end_frame_z - start_frame_z if end_frame_z != start_frame_z else 1

            for frame in range(start_frame_x, end_frame_x + 1):
                current_rotation = self.apply_curve_rotation(rotation_x, end_rotation_x, frame - start_frame_x, total_frames_x, ease_x)
                obj.rotation_euler[0] = apply_wobble(current_rotation, frame, 'X')
                obj.keyframe_insert(data_path="rotation_euler", index=0, frame=frame)
            
            for frame in range(start_frame_y, end_frame_y + 1):
                current_rotation = self.apply_curve_rotation(rotation_y, end_rotation_y, frame - start_frame_y, total_frames_y, ease_y)
                obj.rotation_euler[1] = apply_wobble(current_rotation, frame, 'Y')
                obj.keyframe_insert(data_path="rotation_euler", index=1, frame=frame)
            
            for frame in range(start_frame_z, end_frame_z + 1):
                current_rotation = self.apply_curve_rotation(rotation_z, end_rotation_z, frame - start_frame_z, total_frames_z, ease_z)
                obj.rotation_euler[2] = apply_wobble(current_rotation, frame, 'Z')
                obj.keyframe_insert(data_path="rotation_euler", index=2, frame=frame)

        return {'FINISHED'}

class FanAnimationPanel(bpy.types.Panel):
    """Panel for Fan Animation"""
    bl_label = "Fan Animation"
    bl_idname = "OBJECT_PT_fan_animation"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Fan Animation'

    def draw(self, context):
        layout = self.layout

        # Rotation Settings Subpanel
        layout.label(text="X Rotation:")
        layout.prop(context.scene, "fan_rotation_x", text="Start Rotation")
        layout.prop(context.scene, "fan_end_rotation_x", text="End Rotation")
        layout.prop(context.scene, "fan_easing_x", text="Easing Type X")
        
        layout.label(text="Y Rotation:")
        layout.prop(context.scene, "fan_rotation_y", text="Start Rotation")
        layout.prop(context.scene, "fan_end_rotation_y", text="End Rotation")
        layout.prop(context.scene, "fan_easing_y", text="Easing Type Y")
        
        layout.label(text="Z Rotation:")
        layout.prop(context.scene, "fan_rotation_z", text="Start Rotation")
        layout.prop(context.scene, "fan_end_rotation_z", text="End Rotation")
        layout.prop(context.scene, "fan_easing_z", text="Easing Type Z")

        # Animation Settings Subpanel
        layout.label(text="Animation Settings:")
        layout.prop(context.scene, "fan_start_frame_x", text="Start Frame X")
        layout.prop(context.scene, "fan_end_frame_x", text="End Frame X")
        layout.prop(context.scene, "fan_start_frame_y", text="Start Frame Y")
        layout.prop(context.scene, "fan_end_frame_y", text="End Frame Y")
        layout.prop(context.scene, "fan_start_frame_z", text="Start Frame Z")
        layout.prop(context.scene, "fan_end_frame_z", text="End Frame Z")

        # Wobble Settings Subpanel
        layout.label(text="Wobble Settings:")
        layout.prop(context.scene, "fan_wobble_amplitude", text="Wobble Amplitude")
        layout.prop(context.scene, "fan_wobble_frequency", text="Wobble Frequency")
        layout.prop(context.scene, "fan_wobble_start_frame", text="Wobble Start Frame")
        layout.prop(context.scene, "fan_wobble_end_frame", text="Wobble End Frame")
        layout.prop(context.scene, "fan_easing_wobble", text="Easing Type Wobble")

        # Buttons
        layout.operator("object.fan_animation", text="Animate Fans")
        layout.operator("object.clear_animation", text="Clear Animation Data")

def register():
    bpy.utils.register_class(FanAnimationOperator)
    bpy.utils.register_class(FanAnimationPanel)
    bpy.utils.register_class(FanClearAnimationOperator)
    bpy.types.Scene.fan_rotation_type = EnumProperty(
        name="Rotation Type",
        items=[('CONSTANT', "Constant Speed", "Constant speed rotation")],
        default='CONSTANT'
    )
    bpy.types.Scene.fan_rotation_x = FloatProperty(name="Rotation X", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_rotation_y = FloatProperty(name="Rotation Y", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_rotation_z = FloatProperty(name="Rotation Z", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_end_rotation_x = FloatProperty(name="End Rotation X", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_end_rotation_y = FloatProperty(name="End Rotation Y", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_end_rotation_z = FloatProperty(name="End Rotation Z", default=0.0, min=-360.0, max=360.0)
    bpy.types.Scene.fan_start_frame_x = IntProperty(name="Start Frame X", default=1, min=1)
    bpy.types.Scene.fan_end_frame_x = IntProperty(name="End Frame X", default=250, min=1)
    bpy.types.Scene.fan_start_frame_y = IntProperty(name="Start Frame Y", default=1, min=1)
    bpy.types.Scene.fan_end_frame_y = IntProperty(name="End Frame Y", default=250, min=1)
    bpy.types.Scene.fan_start_frame_z = IntProperty(name="Start Frame Z", default=1, min=1)
    bpy.types.Scene.fan_end_frame_z = IntProperty(name="End Frame Z", default=250, min=1)
    bpy.types.Scene.fan_wobble_amplitude = FloatProperty(name="Wobble Amplitude", default=10.0, min=0.0, max=360.0)
    bpy.types.Scene.fan_wobble_frequency = FloatProperty(name="Wobble Frequency", default=1.0, min=0.0, max=10.0)
    bpy.types.Scene.fan_wobble_start_frame = IntProperty(name="Wobble Start Frame", default=1, min=1)
    bpy.types.Scene.fan_wobble_end_frame = IntProperty(name="Wobble End Frame", default=250, min=1)
    bpy.types.Scene.fan_easing_x = EnumProperty(
        name="Easing Type X",
        items=[
            ('LINEAR', "Linear", "Linear progression"),
            ('EASE_IN', "Ease In", "Ease In progression"),
            ('EASE_OUT', "Ease Out", "Ease Out progression"),
            ('EASE_IN_OUT', "Ease In-Out", "Ease In-Out progression")
        ],
        default='LINEAR'
    )
    bpy.types.Scene.fan_easing_y = EnumProperty(
        name="Easing Type Y",
        items=[
            ('LINEAR', "Linear", "Linear progression"),
            ('EASE_IN', "Ease In", "Ease In progression"),
            ('EASE_OUT', "Ease Out", "Ease Out progression"),
            ('EASE_IN_OUT', "Ease In-Out", "Ease In-Out progression")
        ],
        default='LINEAR'
    )
    bpy.types.Scene.fan_easing_z = EnumProperty(
        name="Easing Type Z",
        items=[
            ('LINEAR', "Linear", "Linear progression"),
            ('EASE_IN', "Ease In", "Ease In progression"),
            ('EASE_OUT', "Ease Out", "Ease Out progression"),
            ('EASE_IN_OUT', "Ease In-Out", "Ease In-Out progression")
        ],
        default='LINEAR'
    )
    bpy.types.Scene.fan_easing_wobble = EnumProperty(
        name="Easing Type Wobble",
        items=[
            ('LINEAR', "Linear", "Linear progression"),
            ('EASE_IN', "Ease In", "Ease In progression"),
            ('EASE_OUT', "Ease Out", "Ease Out progression"),
            ('EASE_IN_OUT', "Ease In-Out", "Ease In-Out progression")
        ],
        default='LINEAR'
    )

def unregister():
    bpy.utils.unregister_class(FanAnimationOperator)
    bpy.utils.unregister_class(FanAnimationPanel)
    bpy.utils.unregister_class(FanClearAnimationOperator)
    del bpy.types.Scene.fan_rotation_type
    del bpy.types.Scene.fan_rotation_x
    del bpy.types.Scene.fan_rotation_y
    del bpy.types.Scene.fan_rotation_z
    del bpy.types.Scene.fan_end_rotation_x
    del bpy.types.Scene.fan_end_rotation_y
    del bpy.types.Scene.fan_end_rotation_z
    del bpy.types.Scene.fan_start_frame_x
    del bpy.types.Scene.fan_end_frame_x
    del bpy.types.Scene.fan_start_frame_y
    del bpy.types.Scene.fan_end_frame_y
    del bpy.types.Scene.fan_start_frame_z
    del bpy.types.Scene.fan_end_frame_z
    del bpy.types.Scene.fan_wobble_amplitude
    del bpy.types.Scene.fan_wobble_frequency
    del bpy.types.Scene.fan_wobble_start_frame
    del bpy.types.Scene.fan_wobble_end_frame
    del bpy.types.Scene.fan_easing_x
    del bpy.types.Scene.fan_easing_y
    del bpy.types.Scene.fan_easing_z
    del bpy.types.Scene.fan_easing_wobble

if __name__ == "__main__":
    register()