using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using AlicizaX.UI;
using UnityEngine.UI;
using Object = UnityEngine.Object;

[CustomEditor(typeof(RecyclerView))]
public class RecyclerViewEditor : Editor
{
    // Layout Manager
    private SerializedProperty _layoutManagerTypeName;
    private SerializedProperty _layoutManager;
    private List<string> _layoutTypeNames = new List<string>();
    private int _selectedLayoutIndex;

    // Scroller
    private SerializedProperty scroll;
    private SerializedProperty _scroller;
    private SerializedProperty _scrollerTypeName;
    private List<Type> _scrollerTypes = new List<Type>();
    private List<string> _scrollerTypeNames;
    private int _selectedScrollerIndex;

    // Base Properties
    private SerializedProperty direction;
    private SerializedProperty alignment;
    private SerializedProperty content;
    private SerializedProperty spacing;
    private SerializedProperty padding;
    private SerializedProperty snap;
    private SerializedProperty scrollSpeed;
    private SerializedProperty wheelSpeed;
    private SerializedProperty templates;

    private SerializedProperty _showScrollBar;
    private SerializedProperty _scrollbar;

    private const string NoneOptionName = "None";

    private void OnEnable()
    {
        // Layout Manager
        _layoutManagerTypeName = serializedObject.FindProperty("_layoutManagerTypeName");
        _layoutManager = serializedObject.FindProperty("_layoutManager");
        RefreshLayoutTypes();

        // Scroller
        scroll = serializedObject.FindProperty("scroll");
        _scroller = serializedObject.FindProperty("_scroller");
        _scrollerTypeName = serializedObject.FindProperty("_scrollerTypeName");
        RefreshScrollerTypes();
        SyncExistingScroller();

        // Base Properties
        direction = serializedObject.FindProperty("direction");
        alignment = serializedObject.FindProperty("alignment");
        content = serializedObject.FindProperty("content");
        spacing = serializedObject.FindProperty("spacing");
        padding = serializedObject.FindProperty("padding");
        snap = serializedObject.FindProperty("snap");
        scrollSpeed = serializedObject.FindProperty("scrollSpeed");
        wheelSpeed = serializedObject.FindProperty("wheelSpeed");
        templates = serializedObject.FindProperty("templates");
        _showScrollBar = serializedObject.FindProperty("_showScrollBar");
        _scrollbar = serializedObject.FindProperty("_scrollbar");
    }

    #region Layout Manager

    void RefreshLayoutTypes()
    {
        _layoutTypeNames.Clear();
        _layoutTypeNames.Add(NoneOptionName);

        // 获取所有实现ILayoutManager的非Mono类型
        var types = AlicizaX.Utility.Assembly.GetRuntimeTypes(typeof(ILayoutManager));
        foreach (var type in types)
        {
            if (!typeof(MonoBehaviour).IsAssignableFrom(type))
            {
                _layoutTypeNames.Add(type.FullName);
            }
        }

        _selectedLayoutIndex = Mathf.Clamp(
            _layoutTypeNames.IndexOf(_layoutManagerTypeName.stringValue),
            0,
            _layoutTypeNames.Count - 1
        );
    }

    #endregion

    #region Scroller

    void RefreshScrollerTypes()
    {
        _scrollerTypes = TypeCache.GetTypesDerivedFrom<IScroller>()
            .Where(t => t.IsSubclassOf(typeof(MonoBehaviour)))
            .ToList();

        _scrollerTypeNames = _scrollerTypes
            .Select(t => t.FullName)
            .Prepend(NoneOptionName)
            .ToList();
    }

    void SyncExistingScroller()
    {
        var rv = target as RecyclerView;
        if (rv == null) return;

        var existing = rv.GetComponent<IScroller>();
        if (existing != null)
        {
            _scrollerTypeName.stringValue = existing.GetType().FullName;
            _selectedScrollerIndex = _scrollerTypeNames.IndexOf(_scrollerTypeName.stringValue);
        }
        else
        {
            _selectedScrollerIndex = 0;
        }
    }

    #endregion

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        bool isPlaying = Application.isPlaying;

        DrawLayoutManagerSection(isPlaying);
        DrawBaseSettings(isPlaying);
        DrawScrollerSettings(isPlaying);
        DrawTemplatesSection();

        serializedObject.ApplyModifiedProperties();
    }

    #region Drawing Methods

    void DrawLayoutManagerSection(bool isPlaying)
    {
        EditorGUILayout.BeginVertical("box");
        {
            EditorGUILayout.LabelField("Layout Manager", EditorStyles.boldLabel);

            using (new EditorGUI.DisabledScope(isPlaying))
            {
                // 强制允许选择空值
                int newIndex = EditorGUILayout.Popup("Layout Type", _selectedLayoutIndex, _layoutTypeNames.ToArray());
                if (newIndex != _selectedLayoutIndex)
                {
                    _selectedLayoutIndex = newIndex; // 立即更新索引
                    UpdateLayoutManager(newIndex);
                    serializedObject.ApplyModifiedProperties();
                }
            }

            // 显示布局属性或警告
            if (_layoutManager.managedReferenceValue != null)
            {
                EditorGUILayout.Space(3);
                DrawManagedProperties(_layoutManager);
            }
            else
            {
                EditorGUILayout.HelpBox("Need Choose LayoutManager", MessageType.Error);
            }
        }
        EditorGUILayout.EndVertical();
    }

    void DrawBaseSettings(bool isPlaying)
    {
        EditorGUILayout.BeginVertical("box");
        {
            EditorGUILayout.LabelField("Base Settings", EditorStyles.boldLabel);

            using (new EditorGUI.DisabledScope(isPlaying))
            {
                EditorGUILayout.PropertyField(direction);
                EditorGUILayout.PropertyField(alignment);
                EditorGUILayout.PropertyField(content);
            }

            EditorGUILayout.Space(5);
            EditorGUILayout.LabelField("Spacing", EditorStyles.boldLabel);
            EditorGUILayout.PropertyField(spacing);
            EditorGUILayout.PropertyField(padding);

            EditorGUILayout.Space(5);
            EditorGUILayout.LabelField("Scrolling", EditorStyles.boldLabel);

            using (new EditorGUI.DisabledScope(isPlaying))
            {
                bool prevScrollValue = scroll.boolValue;
                EditorGUILayout.PropertyField(scroll);

                if (scroll.boolValue != prevScrollValue)
                {
                    HandleScrollToggle();
                    if (!scroll.boolValue)
                    {
                        ClearScrollBar();
                    }
                }
            }

            if (scroll.boolValue)
            {
                using (new EditorGUI.DisabledScope(isPlaying))
                {
                    bool prevShowScrollBarValue = _showScrollBar.boolValue;
                    EditorGUILayout.PropertyField(_showScrollBar);

                    if (_showScrollBar.boolValue != prevShowScrollBarValue)
                    {
                        HandleScrollBarToggle();
                    }
                }
            }


            EditorGUILayout.PropertyField(snap);
        }
        EditorGUILayout.EndVertical();
    }

    void DrawScrollerSettings(bool isPlaying)
    {
        if (!scroll.boolValue) return;

        EditorGUILayout.BeginVertical("box");
        {
            EditorGUILayout.LabelField("Scroller Settings", EditorStyles.boldLabel);

            using (new EditorGUI.DisabledScope(isPlaying))
            {
                int newIndex = EditorGUILayout.Popup("Scroller Type", _selectedScrollerIndex, _scrollerTypeNames.ToArray());
                if (newIndex != _selectedScrollerIndex)
                {
                    UpdateScroller(newIndex);
                    serializedObject.ApplyModifiedProperties();
                }
            }

            var rv = target as RecyclerView;
            if (rv != null)
            {
                var scrollerComponent = rv.GetComponent<IScroller>();
                if (scrollerComponent != null)
                {
                    DrawComponentProperties(scrollerComponent as MonoBehaviour, "Scroller Properties");
                }
                else
                {
                    EditorGUILayout.HelpBox("Must choose to use a Scroller.", MessageType.Error);
                }
            }

            EditorGUILayout.Space(3);
            EditorGUILayout.PropertyField(scrollSpeed);
            EditorGUILayout.PropertyField(wheelSpeed);
        }
        EditorGUILayout.EndVertical();
    }

    void DrawComponentProperties(MonoBehaviour component, string header = null)
    {
        if (component == null) return;

        EditorGUILayout.Space(3);
        if (!string.IsNullOrEmpty(header))
        {
            EditorGUILayout.LabelField(header, EditorStyles.boldLabel);
        }

        SerializedObject so = new SerializedObject(component);
        so.Update();

        SerializedProperty prop = so.GetIterator();
        bool enterChildren = true;
        while (prop.NextVisible(enterChildren))
        {
            enterChildren = false;
            if (prop.name == "m_Script") continue;
            EditorGUILayout.PropertyField(prop, true);
        }

        so.ApplyModifiedProperties();
    }

    void DrawTemplatesSection()
    {
        EditorGUILayout.Space(5);
        EditorGUILayout.LabelField("Item Templates", EditorStyles.boldLabel);

        DrawTemplatesList();

        DrawDragAndDropArea();
    }

    void DrawTemplatesList()
    {
        if (templates == null || !templates.isArray) return;

        serializedObject.Update();

        for (int i = 0; i < templates.arraySize; i++)
        {
            DrawTemplateItem(i);
        }
    }

    void DrawTemplateItem(int index)
    {
        if (index < 0 || index >= templates.arraySize) return;

        SerializedProperty item = templates.GetArrayElementAtIndex(index);

        EditorGUILayout.BeginHorizontal();
        {
            EditorGUI.BeginDisabledGroup(true);
            EditorGUILayout.PropertyField(item, GUIContent.none, true);
            EditorGUI.EndDisabledGroup();

            if (GUILayout.Button("×", GUILayout.Width(20), GUILayout.Height(EditorGUIUtility.singleLineHeight)))
            {
                RemoveTemplateItem(index);
                return;
            }
        }
        EditorGUILayout.EndHorizontal();
    }

    void RemoveTemplateItem(int index)
    {
        if (templates == null || index < 0 || index >= templates.arraySize) return;

        templates.DeleteArrayElementAtIndex(index);
        serializedObject.ApplyModifiedProperties();
        GUIUtility.ExitGUI();
    }

    void DrawDragAndDropArea()
    {
        Rect dropArea = GUILayoutUtility.GetRect(0f, 50f, GUILayout.ExpandWidth(true));
        GUI.Box(dropArea, "Drag Template to here", EditorStyles.helpBox);

        // 处理拖拽事件
        HandleDragAndDrop(dropArea);
    }

    void HandleDragAndDrop(Rect dropArea)
    {
        Event evt = Event.current;

        switch (evt.type)
        {
            case EventType.DragUpdated:
            case EventType.DragPerform:
                if (!dropArea.Contains(evt.mousePosition))
                    return;

                DragAndDrop.visualMode = DragAndDropVisualMode.Copy;

                if (evt.type == EventType.DragPerform)
                {
                    DragAndDrop.AcceptDrag();
                    AddTemplatesFromDrag();
                    evt.Use();
                }

                break;
        }
    }

    void AddTemplatesFromDrag()
    {
        foreach (UnityEngine.Object draggedObject in DragAndDrop.objectReferences)
        {
            if (draggedObject is GameObject gameObject && gameObject.GetComponent<ViewHolder>() != null)
            {
                AddTemplate(gameObject);
            }
            else
            {
                Debug.LogWarning("模板必须为GameObject资源 同时挂载继承ViewHolder脚本!");
            }
        }
    }

    void AddTemplate(GameObject templatePrefab)
    {
        if (templates == null) return;

        for (int i = 0; i < templates.arraySize; i++)
        {
            SerializedProperty existingItem = templates.GetArrayElementAtIndex(i);
            var refrence = (ViewHolder)existingItem.objectReferenceValue;
            if (refrence.GetType() != templatePrefab.GetType())
            {
                Debug.LogWarning("列表元素重复项,禁止再次添加!");
                return;
            }
        }

        templates.arraySize++;
        SerializedProperty newItem = templates.GetArrayElementAtIndex(templates.arraySize - 1);
        newItem.objectReferenceValue = templatePrefab;

        serializedObject.ApplyModifiedProperties();
    }

    #endregion

    #region Update Handlers

    void UpdateLayoutManager(int selectedIndex)
    {
        try
        {
            // 强制清空逻辑
            if (selectedIndex == 0)
            {
                _layoutManager.managedReferenceValue = null;
                _layoutManagerTypeName.stringValue = "";
                _selectedLayoutIndex = 0; // 确保索引同步
                return;
            }

            // 有效性检查
            if (selectedIndex < 0 || selectedIndex >= _layoutTypeNames.Count)
            {
                Debug.LogError($"Invalid layout index: {selectedIndex}");
                _selectedLayoutIndex = 0;
                return;
            }

            string typeName = _layoutTypeNames[selectedIndex];
            Type type = AlicizaX.Utility.Assembly.GetType(typeName);

            if (type != null && typeof(ILayoutManager).IsAssignableFrom(type))
            {
                _layoutManager.managedReferenceValue = Activator.CreateInstance(type);
                _layoutManagerTypeName.stringValue = typeName;
                _selectedLayoutIndex = selectedIndex;
            }
            else
            {
                Debug.LogError($"Invalid layout type: {typeName}");
                _selectedLayoutIndex = 0;
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"Layout Manager Error: {e.Message}");
            _layoutManager.managedReferenceValue = null;
            _layoutManagerTypeName.stringValue = "";
            _selectedLayoutIndex = 0;
        }
    }

    void UpdateScroller(int selectedIndex)
    {
        try
        {
            var rv = target as RecyclerView;
            if (rv == null) return;

            Undo.RecordObjects(new UnityEngine.Object[] { rv, this }, "Update Scroller");

            // 移除旧组件
            var oldScroller = rv.GetComponent<IScroller>();
            if (oldScroller != null)
            {
                Undo.DestroyObjectImmediate(oldScroller as MonoBehaviour);
            }

            if (selectedIndex == 0)
            {
                // 清除序列化引用
                _scroller.objectReferenceValue = null;
                _scrollerTypeName.stringValue = "";
                return;
            }

            // 添加新组件
            Type selectedType = _scrollerTypes[selectedIndex - 1];
            var newScroller = Undo.AddComponent(rv.gameObject, selectedType) as IScroller;

            // 同步到序列化属性
            _scroller.objectReferenceValue = newScroller as MonoBehaviour;
            _scrollerTypeName.stringValue = selectedType.FullName;
            _selectedScrollerIndex = selectedIndex;

            // 立即应用修改
            serializedObject.ApplyModifiedProperties();
            EditorUtility.SetDirty(rv); // 标记对象需要保存
        }
        catch (Exception e)
        {
            Debug.LogError($"Scroller Error: {e}");
            _selectedScrollerIndex = 0;
            _scrollerTypeName.stringValue = "";
            _scroller.objectReferenceValue = null;
        }
    }

    void HandleScrollToggle()
    {
        var rv = target as RecyclerView;
        if (rv == null) return;

        if (!scroll.boolValue)
        {
            // Remove scroller component
            var scrollerComponent = rv.GetComponent<IScroller>();
            if (scrollerComponent != null)
            {
                Undo.DestroyObjectImmediate(scrollerComponent as MonoBehaviour);
            }

            _scrollerTypeName.stringValue = "";
            _selectedScrollerIndex = 0;
        }
    }

    void HandleScrollBarToggle()
    {
        var rv = target as RecyclerView;
        if (rv == null) return;
        if (_showScrollBar.boolValue)
        {
            Direction direction = (Direction)this.direction.enumValueIndex;
            if (direction == Direction.Vertical)
            {
                const string path = "Packages/com.alicizax.unity.ui.extension/Editor/RecyclerView/Res/vertical.prefab";
                InstantiateScrollBar(path, rv.transform);
            }
            else if (direction == Direction.Horizontal)
            {
                const string path = "Packages/com.alicizax.unity.ui.extension/Editor/RecyclerView/Res/horizontal.prefab";
                InstantiateScrollBar(path, rv.transform);
            }
        }
        else
        {
            ClearScrollBar();
        }
    }

    void ClearScrollBar()
    {
        _showScrollBar.boolValue = false;
        if (_scrollbar.objectReferenceValue != null)
        {
            Scrollbar scrollbar = _scrollbar.objectReferenceValue as Scrollbar;
            _scrollbar.objectReferenceValue = null;
            Object.DestroyImmediate(scrollbar.gameObject);
        }
    }

    #endregion

    void DrawManagedProperties(SerializedProperty property)
    {
        SerializedProperty iterator = property.Copy();
        bool enterChildren = true;

        while (iterator.NextVisible(enterChildren))
        {
            enterChildren = false;
            if (iterator.name == "m_Script") continue;
            EditorGUILayout.PropertyField(iterator, true);
        }
    }

    void InstantiateScrollBar(string path, Transform parent)
    {
        GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
        GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab, parent);
        PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.Completely, InteractionMode.UserAction);
        _scrollbar.objectReferenceValue = instance.GetComponent<Scrollbar>();
    }
}
