using System;
using System.Collections.Generic;
using AlicizaX.UI.Extension.Editor;
using UnityEditor;
using UnityEditorInternal;
using UnityEditor.UI;
using UnityEngine;
using UnityEngine.UI;
using AnimatorControllerParameterType = UnityEngine.AnimatorControllerParameterType;

[CanEditMultipleObjects]
[CustomEditor(typeof(UXButton), true)]
internal class UXButtonEditor : Editor
{
    private enum TabType
    {
        Image,
        Sound,
        Event
    }
    private SerializedProperty m_Interactable;
    private SerializedProperty m_Mode;
    private SerializedProperty m_OnValueChanged;
    private SerializedProperty m_OnClick;
    private SerializedProperty m_UXGroup;
    private SerializedProperty m_TransitionData;
    private SerializedProperty m_ChildTransitions;

    private UXGroup group;
    private int m_ButtonMode;
    private SerializedProperty m_SelectionState;

    private ReorderableList m_ChildTransitionList;

    private static Color darkZebraEven = new Color(0.22f, 0.22f, 0.22f);
    private static Color darkZebraOdd = new Color(0.27f, 0.27f, 0.27f);


    private TabType currentTab = TabType.Image;
    private GUISkin customSkin;

    private SerializedProperty hoverAudioClip;
    private SerializedProperty clickAudioClip;

    private void OnEnable()
    {
        customSkin = AssetDatabase.LoadAssetAtPath<GUISkin>("Packages/com.alicizax.unity.ui.extension/Editor/Res/GUISkin/UIExtensionGUISkin.guiskin");
        m_Interactable = serializedObject.FindProperty("m_Interactable");
        m_UXGroup = serializedObject.FindProperty("m_UXGroup");
        m_Mode = serializedObject.FindProperty("m_Mode");
        m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged");
        m_OnClick = serializedObject.FindProperty("m_OnClick");
        m_TransitionData = serializedObject.FindProperty("m_TransitionData");
        m_ChildTransitions = serializedObject.FindProperty("m_ChildTransitions");
        m_SelectionState = serializedObject.FindProperty("m_SelectionState");

        group = (UXGroup)m_UXGroup.objectReferenceValue;
        m_ButtonMode = m_Mode.enumValueIndex;

        hoverAudioClip = serializedObject.FindProperty("hoverAudioClip");
        clickAudioClip = serializedObject.FindProperty("clickAudioClip");

        CreateChildTransitionList();
    }

    private void CreateChildTransitionList()
    {
        m_ChildTransitionList = new ReorderableList(serializedObject, m_ChildTransitions, true, false, true, true);
        // m_ChildTransitionList.drawHeaderCallback = (rect) => { EditorGUI.LabelField(rect, "Other Transitions"); };

        m_ChildTransitionList.drawElementBackgroundCallback = (rect, index, isActive, isFocused) =>
        {
            var background = index % 2 == 0 ? darkZebraEven : darkZebraOdd;
            EditorGUI.DrawRect(rect, background);
        };

        m_ChildTransitionList.drawElementCallback = (rect, index, isActive, isFocused) =>
        {
            var element = m_ChildTransitionList.serializedProperty.GetArrayElementAtIndex(index);
            rect.y += 2;

            // 绘制折叠框标题（仅显示名称）
            string elementTitle = $"Null Transition";
            var targetProp = element.FindPropertyRelative("targetGraphic");
            if (targetProp.objectReferenceValue != null)
                elementTitle = targetProp.objectReferenceValue.name;

            EditorGUI.LabelField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight),
                elementTitle, EditorStyles.boldLabel);

            // 直接绘制完整内容（无折叠状态）
            rect.y += EditorGUIUtility.singleLineHeight + 2;
            DrawTransitionData(new Rect(rect.x, rect.y, rect.width, 0), element, true);
        };

        // 设置元素高度
        m_ChildTransitionList.elementHeightCallback = (index) =>
        {
            return EditorGUIUtility.singleLineHeight +
                   CalculateTransitionDataHeight(m_ChildTransitionList.serializedProperty.GetArrayElementAtIndex(index)) +
                   10;
        };

        m_ChildTransitionList.onAddCallback = (list) =>
        {
            list.serializedProperty.arraySize++;
            serializedObject.ApplyModifiedProperties();
        };

        // 添加删除按钮
        m_ChildTransitionList.onRemoveCallback = (list) => { ReorderableList.defaultBehaviours.DoRemoveButton(list); };
    }

    private void ResetEventProperty(SerializedProperty property)
    {
        SerializedProperty persistentCalls = property.FindPropertyRelative("m_PersistentCalls");
        SerializedProperty calls = persistentCalls.FindPropertyRelative("m_Calls");
        calls.arraySize = 0;
        property.serializedObject.ApplyModifiedProperties();
    }

    private void DrawTabButton(TabType tabType, string label, string iconName)
    {
        bool isActive = currentTab == tabType;
        var style = new GUIStyle(EditorStyles.toolbarButton)
        {
            fixedHeight = 25,
            fontSize = 11,
            fontStyle = isActive ? FontStyle.Bold : FontStyle.Normal
        };

        var content = new GUIContent(
            EditorGUIUtility.IconContent(iconName).image,
            label
        );

        if (GUILayout.Button(content, style))
        {
            currentTab = tabType;
        }

        // 高亮当前选中的标签页
        if (isActive)
        {
            Rect rect = GUILayoutUtility.GetLastRect();
            EditorGUI.DrawRect(new Rect(rect.x, rect.yMax - 2, rect.width, 2),
                new Color(0.1f, 0.5f, 0.9f));
        }
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        EditorGUILayout.BeginHorizontal();

        // 图像标签页按钮
        DrawTabButton(TabType.Image, "Image", "d_Texture Icon");

        // 声音标签页按钮
        DrawTabButton(TabType.Sound, "Sound", "d_AudioSource Icon");

        // 事件标签页按钮
        DrawTabButton(TabType.Event, "Event", "EventTrigger Icon");

        EditorGUILayout.EndHorizontal();

        switch (currentTab)
        {
            case TabType.Image:
                DrawGraphicsTab();
                break;
            case TabType.Sound:
                DrawAudioTab();
                break;
            case TabType.Event:
                DrawEventTab();
                break;
        }

        serializedObject.ApplyModifiedProperties();
    }

    private void DrawGraphicsTab()
    {
        EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying);
        EditorGUILayout.PropertyField(m_Mode);
        EditorGUI.EndDisabledGroup();

        var interactable = GUILayoutHelper.DrawToggle(m_Interactable.boolValue, customSkin, "Interactable");
        m_Interactable.boolValue = interactable;

        GUILayout.Space(1);
        DrawSelfTransition();

        GUILayout.Space(5);
        DrawChildTransitions();
        GUILayout.Space(1);

        DrawBasicSettings();
    }

    private void DrawEventTab()
    {
        if (m_Mode.enumValueIndex == (int)ButtonModeType.Toggle)
        {
            EditorGUILayout.Space();
            EditorGUILayout.PropertyField(m_OnValueChanged);
        }
        else
        {
            EditorGUILayout.Space();
            EditorGUILayout.PropertyField(m_OnClick);
        }
    }

    private void DrawAudioTab()
    {
        GUILayoutHelper.DrawProperty(hoverAudioClip, customSkin, "Hover Sound", "Play", () =>
        {
            if (hoverAudioClip.objectReferenceValue != null)
            {
                PlayAudio((AudioClip)hoverAudioClip.objectReferenceValue);
            }
        });
        GUILayoutHelper.DrawProperty(clickAudioClip, customSkin, "Click Sound", "Play", () =>
        {
            if (hoverAudioClip.objectReferenceValue != null)
            {
                PlayAudio((AudioClip)hoverAudioClip.objectReferenceValue);
            }
        });
    }

    private void DrawBasicSettings()
    {
        if (m_Mode.enumValueIndex != m_ButtonMode)
        {
            if (m_ButtonMode == (int)ButtonModeType.Normal)
            {
                ResetEventProperty(m_OnValueChanged);
                m_UXGroup.objectReferenceValue = null;
            }
            else
            {
                ResetEventProperty(m_OnClick);
            }

            m_ButtonMode = m_Mode.enumValueIndex;
        }

        if (m_Mode.enumValueIndex == (int)ButtonModeType.Toggle)
        {
            GUILayoutHelper.DrawProperty(m_UXGroup, customSkin, "UXGroup");

            UXGroup newGroup = (UXGroup)m_UXGroup.objectReferenceValue;
            if (newGroup != group)
            {
                UXButton self = target as UXButton;
                if (group != null)
                {
                    group.UnregisterButton(self);
                }

                group = newGroup;
                if (newGroup != null)
                {
                    newGroup.RegisterButton(self);
                }
            }
        }
    }

    private void PlayAudio(AudioClip clip)
    {
        if (clip != null)
        {
            ExtensionHelper.PreviewAudioClip(clip);
        }
    }

    private void DrawChildTransitions()
    {
        m_ChildTransitionList.DoLayoutList();
    }


    private float CalculateTransitionDataHeight(SerializedProperty transitionData)
    {
        float height = 0;
        SerializedProperty transition = transitionData.FindPropertyRelative("transition");
        var currentTransition = GetTransition(transition);

        height += EditorGUIUtility.singleLineHeight * 1.5f;
        height += EditorGUIUtility.singleLineHeight;

        SerializedProperty targetGraphic = transitionData.FindPropertyRelative("targetGraphic");
        var graphic = targetGraphic.objectReferenceValue as Graphic;
        var animator = graphic != null ? graphic.GetComponent<Animator>() : null;

        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
                if (graphic == null) height += EditorGUIUtility.singleLineHeight;
                break;
            case Selectable.Transition.SpriteSwap:
                if (!(graphic is Image)) height += EditorGUIUtility.singleLineHeight;
                break;
            case Selectable.Transition.Animation:
                if (animator == null) height += EditorGUIUtility.singleLineHeight;
                break;
        }


        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
                height += EditorGUI.GetPropertyHeight(transitionData.FindPropertyRelative("colors"));
                break;
            case Selectable.Transition.SpriteSwap:
                height += EditorGUI.GetPropertyHeight(transitionData.FindPropertyRelative("spriteState"));
                break;
            case Selectable.Transition.Animation:
                height += EditorGUI.GetPropertyHeight(transitionData.FindPropertyRelative("animationTriggers"));
                break;
        }

        return height;
    }

    private void DrawTransitionData(Rect position, SerializedProperty transitionData, bool isChild = false)
    {
        SerializedProperty targetGraphic = transitionData.FindPropertyRelative("targetGraphic");
        SerializedProperty transition = transitionData.FindPropertyRelative("transition");
        SerializedProperty colorBlock = transitionData.FindPropertyRelative("colors");
        SerializedProperty spriteState = transitionData.FindPropertyRelative("spriteState");
        SerializedProperty animationTriggers = transitionData.FindPropertyRelative("animationTriggers");

        EditorGUI.indentLevel++;
        float lineHeight = EditorGUIUtility.singleLineHeight;
        float spacing = 2f;
        float y = position.y;

        var currentTransition = GetTransition(transition);

        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
            case Selectable.Transition.SpriteSwap:
                Rect targetRect = new Rect(position.x, y, position.width, lineHeight);
                EditorGUI.PropertyField(targetRect, targetGraphic);
                y += lineHeight + spacing;
                break;
        }


        Rect transitionRect = new Rect(position.x, y, position.width, lineHeight);
        EditorGUI.PropertyField(transitionRect, transition);
        y += lineHeight + spacing;

        var graphic = targetGraphic.objectReferenceValue as Graphic;
        var animator = graphic != null ? graphic.GetComponent<Animator>() : null;

        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
                if (graphic == null)
                {
                    Rect warningRect = new Rect(position.x, y, position.width, lineHeight);
                    EditorGUI.HelpBox(warningRect, "需要Graphic组件来使用颜色过渡", MessageType.Warning);
                    y += lineHeight + spacing;
                }

                break;

            case Selectable.Transition.SpriteSwap:
                if (!(graphic is Image))
                {
                    Rect warningRect = new Rect(position.x, y, position.width, lineHeight);
                    EditorGUI.HelpBox(warningRect, "需要Image组件来使用精灵切换", MessageType.Warning);
                    y += lineHeight + spacing;
                }

                break;
            case Selectable.Transition.Animation:
                if (animator == null)
                {
                    Rect warningRect = new Rect(position.x, y, position.width, lineHeight);
                    EditorGUI.HelpBox(warningRect, "需要Animator组件来使用动画切换", MessageType.Warning);
                    y += lineHeight + spacing;
                }

                break;
        }

        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
                CheckAndSetColorDefaults(colorBlock, targetGraphic);
                Rect colorRect = new Rect(position.x, y, position.width, EditorGUI.GetPropertyHeight(colorBlock));
                EditorGUI.PropertyField(colorRect, colorBlock);
                break;

            case Selectable.Transition.SpriteSwap:
                CheckAndSetColorDefaults(colorBlock, targetGraphic);
                Rect spriteRect = new Rect(position.x, y, position.width, EditorGUI.GetPropertyHeight(spriteState));
                EditorGUI.PropertyField(spriteRect, spriteState);
                break;
            case Selectable.Transition.Animation:
                Rect animRect = new Rect(position.x, y, position.width, EditorGUI.GetPropertyHeight(animationTriggers));
                EditorGUI.PropertyField(animRect, animationTriggers);
                break;
        }

        if (graphic != null && currentTransition != (Selectable.Transition)transition.enumValueIndex &&
            ((Selectable.Transition)transition.enumValueIndex == Selectable.Transition.Animation ||
             (Selectable.Transition)transition.enumValueIndex == Selectable.Transition.None))
        {
            graphic.canvasRenderer.SetColor(Color.white);
        }
    }

    private void DrawSelfTransition()
    {
        GUILayout.BeginVertical(EditorStyles.helpBox);
        EditorGUILayout.LabelField("Main Transition", EditorStyles.boldLabel);
        SerializedProperty targetGraphic = m_TransitionData.FindPropertyRelative("targetGraphic");
        var graphic = targetGraphic.objectReferenceValue as Graphic;
        if (graphic == null)
        {
            graphic = (target as UXButton).GetComponent<Graphic>();
            targetGraphic.objectReferenceValue = graphic;
        }

        SerializedProperty transition = m_TransitionData.FindPropertyRelative("transition");
        var currentTransition = GetTransition(transition);

        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
            case Selectable.Transition.SpriteSwap:
                EditorGUILayout.PropertyField(targetGraphic);
                break;
        }


        EditorGUILayout.PropertyField(transition);

        var animator = graphic != null ? graphic.GetComponent<Animator>() : (target as UXButton).GetComponent<Animator>();
        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
                if (graphic == null)
                    EditorGUILayout.HelpBox("需要Graphic组件来使用颜色过渡", MessageType.Warning);
                break;
            case Selectable.Transition.SpriteSwap:
                if (!(graphic is Image))
                    EditorGUILayout.HelpBox("需要Image组件来使用精灵切换", MessageType.Warning);
                break;
            case Selectable.Transition.Animation:
                if (animator == null)
                    EditorGUILayout.HelpBox("需要Animator组件来使用动画切换", MessageType.Warning);
                break;
        }

        switch (currentTransition)
        {
            case Selectable.Transition.ColorTint:
                CheckAndSetColorDefaults(m_TransitionData.FindPropertyRelative("colors"), targetGraphic);
                EditorGUILayout.PropertyField(m_TransitionData.FindPropertyRelative("colors"));
                break;
            case Selectable.Transition.SpriteSwap:
                EditorGUILayout.PropertyField(m_TransitionData.FindPropertyRelative("spriteState"));
                break;
            case Selectable.Transition.Animation:
                EditorGUILayout.PropertyField(m_TransitionData.FindPropertyRelative("animationTriggers"));
                if (animator == null || animator.runtimeAnimatorController == null)
                {
                    if (GUILayout.Button("Auto Generate Animation"))
                    {
                        var animationTrigger = m_TransitionData.FindPropertyRelative("animationTriggers");
                        var controller = GenerateSelectableAnimatorContoller(animationTrigger, target as UXButton);
                        if (controller != null)
                        {
                            if (animator == null)
                                animator = (target as UXButton).gameObject.AddComponent<Animator>();

                            UnityEditor.Animations.AnimatorController.SetAnimatorController(animator, controller);
                        }
                    }
                }

                break;
        }

        if (graphic != null && currentTransition != (Selectable.Transition)transition.enumValueIndex &&
            ((Selectable.Transition)transition.enumValueIndex == Selectable.Transition.Animation ||
             (Selectable.Transition)transition.enumValueIndex == Selectable.Transition.None))
        {
            graphic.canvasRenderer.SetColor(Color.white);
        }

        EditorGUI.indentLevel--;
        EditorGUILayout.Space();
        GUILayout.EndVertical();
    }

    private static UnityEditor.Animations.AnimatorController GenerateSelectableAnimatorContoller(SerializedProperty property, UXButton target)
    {
        if (target == null)
            return null;

        var path = GetSaveControllerPath(target);
        if (string.IsNullOrEmpty(path))
            return null;
        SerializedProperty normalTrigger = property.FindPropertyRelative("m_NormalTrigger");
        SerializedProperty highlightedTrigger = property.FindPropertyRelative("m_HighlightedTrigger");
        SerializedProperty pressedTrigger = property.FindPropertyRelative("m_PressedTrigger");
        SerializedProperty selectedTrigger = property.FindPropertyRelative("m_SelectedTrigger");
        SerializedProperty disabledTrigger = property.FindPropertyRelative("m_DisabledTrigger");

        var normalName = string.IsNullOrEmpty(normalTrigger.stringValue) ? "Normal" : normalTrigger.stringValue;
        var highlightedName = string.IsNullOrEmpty(highlightedTrigger.stringValue) ? "Highlighted" : highlightedTrigger.stringValue;
        var pressedName = string.IsNullOrEmpty(pressedTrigger.stringValue) ? "Pressed" : pressedTrigger.stringValue;
        var selectedName = string.IsNullOrEmpty(selectedTrigger.stringValue) ? "Selected" : selectedTrigger.stringValue;
        var disabledName = string.IsNullOrEmpty(disabledTrigger.stringValue) ? "Disabled" : disabledTrigger.stringValue;

        var controller = UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath(path);
        GenerateTriggerableTransition(normalName, controller);
        GenerateTriggerableTransition(highlightedName, controller);
        GenerateTriggerableTransition(pressedName, controller);
        GenerateTriggerableTransition(selectedName, controller);
        GenerateTriggerableTransition(disabledName, controller);

        AssetDatabase.ImportAsset(path);

        return controller;
    }

    private static AnimationClip GenerateTriggerableTransition(string name, UnityEditor.Animations.AnimatorController controller)
    {
        // Create the clip
        var clip = UnityEditor.Animations.AnimatorController.AllocateAnimatorClip(name);
        AssetDatabase.AddObjectToAsset(clip, controller);

        // Create a state in the animatior controller for this clip
        var state = controller.AddMotion(clip);

        // Add a transition property
        controller.AddParameter(name, AnimatorControllerParameterType.Trigger);

        // Add an any state transition
        var stateMachine = controller.layers[0].stateMachine;
        var transition = stateMachine.AddAnyStateTransition(state);
        transition.AddCondition(UnityEditor.Animations.AnimatorConditionMode.If, 0, name);
        return clip;
    }

    private static string GetSaveControllerPath(UXButton target)
    {
        var defaultName = target.gameObject.name;
        var message = string.Format("Create a new animator for the game object '{0}':", defaultName);
        return EditorUtility.SaveFilePanelInProject("New Animation Contoller", defaultName, "controller", message);
    }

    void CheckAndSetColorDefaults(SerializedProperty colorBlock, SerializedProperty targetGraphic)
    {
        bool isDirty = false;
        string[] colorProps = new string[] { "m_NormalColor", "m_HighlightedColor", "m_PressedColor", "m_SelectedColor", "m_DisabledColor" };
        foreach (var propName in colorProps)
        {
            SerializedProperty prop = colorBlock.FindPropertyRelative(propName);
            Color color = prop.colorValue;
            if (color.r == 0 && color.g == 0 && color.b == 0 && color.a == 0)
            {
                isDirty = true;
                if (prop.name == "m_PressedColor")
                {
                    prop.colorValue = new Color(0.7843137f, 0.7843137f, 0.7843137f, 1.0f);
                }
                else if (prop.name == "m_DisabledColor")
                {
                    prop.colorValue = new Color(0.7843137f, 0.7843137f, 0.7843137f, 0.5f);
                }
                else
                {
                    prop.colorValue = Color.white;
                }
            }
        }

        SerializedProperty fadeDuration = colorBlock.FindPropertyRelative("m_FadeDuration");
        SerializedProperty m_ColorMultiplier = colorBlock.FindPropertyRelative("m_ColorMultiplier");
        if (isDirty)
        {
            m_ColorMultiplier.floatValue = 1f;
            fadeDuration.floatValue = 0.1f;
        }

        var graphic = targetGraphic.objectReferenceValue as Graphic;
        if (graphic != null)
        {
            if (!EditorApplication.isPlaying && (Selectable.Transition)m_SelectionState.enumValueIndex != Selectable.Transition.Animation)
            {
                Color color = colorBlock.FindPropertyRelative("m_NormalColor").colorValue;
                graphic.canvasRenderer.SetColor(color);
            }
        }
    }

    static Selectable.Transition GetTransition(SerializedProperty transition)
    {
        return (Selectable.Transition)transition.enumValueIndex;
    }
}
