#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEditor.Experimental.SceneManagement;
using UnityEngine;
using AlicizaX.UI;
using AlicizaX.UI.Runtime;
using UnityEditor.SceneManagement;
using Random = UnityEngine.Random;

[CustomEditor(typeof(UXControllerStateRecorder))]
public class UXControllerStateRecorderEditor : Editor
{
    private SerializedProperty _stateEntriesProp;
    private SerializedProperty _controller;
    private SerializedProperty _id;
    private GUIContent _removeIcon;
    private UXController _cacheController;

    private void OnEnable()
    {
        _controller = serializedObject.FindProperty("_controller");
        _id = serializedObject.FindProperty("_id");
        _stateEntriesProp = serializedObject.FindProperty("_stateEntries");
        _removeIcon = EditorGUIUtility.IconContent("d_winbtn_win_close");
    }

    private void OnDestroy()
    {
        if (target == null)
        {
            UnRegisterSelf();
        }
    }

    private void UnRegisterSelf()
    {
        UXController controller = (_cacheController != null) ? _cacheController : GetPrefabStageController();
        if (controller == null) return;
        var so = new SerializedObject(controller);
        var recorders = so.FindProperty("_recorders");
        for (int i = recorders.arraySize - 1; i >= 0; i--)
        {
            var el = recorders.GetArrayElementAtIndex(i);
            if (el.objectReferenceValue == null)
            {
                recorders.DeleteArrayElementAtIndex(i);
                break;
            }
        }

        so.ApplyModifiedProperties();
        EditorUtility.SetDirty(controller);
    }

    private void RegisterSelfToController(UXController controller)
    {
        var so = new SerializedObject(controller);
        var recorders = so.FindProperty("_recorders");
        int newIndex = recorders.arraySize;
        recorders.InsertArrayElementAtIndex(newIndex);
        var el = recorders.GetArrayElementAtIndex(newIndex);
        el.objectReferenceValue = target;
        so.ApplyModifiedProperties();
        EditorUtility.SetDirty(controller);
    }

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

        EditorGUILayout.Space();

        var recorder = target as UXControllerStateRecorder;
        UXController prefabCtrl = GetPrefabStageController();

        if (_id.intValue <= 0)
        {
            _id.intValue = Random.Range(10000000, 99999999);
        }


        EditorGUILayout.LabelField($"ID:{_id.intValue}", EditorStyles.helpBox);

        EditorGUILayout.BeginHorizontal();


        if (prefabCtrl != null && prefabCtrl != _controller.objectReferenceValue)
        {
            _controller.objectReferenceValue = prefabCtrl;
        }

        if (!prefabCtrl.HasRecorder(recorder))
        {
            RegisterSelfToController(prefabCtrl);
        }

        if (_controller.objectReferenceValue != null)
        {
            _cacheController = _controller.objectReferenceValue as UXController;
        }


        if (_controller.objectReferenceValue != null)
        {
            UXController ctl = _controller.objectReferenceValue as UXController;
            EditorGUILayout.LabelField($"{ctl.name} ({ctl.Controllers.Count} controllers)", EditorStyles.helpBox);
        }
        else
            EditorGUILayout.LabelField("(None)", EditorStyles.helpBox);


        EditorGUILayout.EndHorizontal();

        EditorGUILayout.Space();

        Rect addRect = EditorGUILayout.GetControlRect(false, GUILayout.Height(22));
        if (GUI.Button(addRect, "Add State"))
        {
            var provider = ScriptableObject.CreateInstance<StateTypeSearchProvider>();
            provider.Init(OnTypeSelected);
            var screenPos = GUIUtility.GUIToScreenPoint(new Vector2(addRect.x, addRect.yMax));
            SearchWindow.Open(new SearchWindowContext(screenPos), provider);
        }

        EditorGUILayout.Space();

        for (int i = 0; i < _stateEntriesProp.arraySize; i++)
        {
            var entryProp = _stateEntriesProp.GetArrayElementAtIndex(i);
            if (entryProp == null) continue;

            var stateProp = entryProp.FindPropertyRelative("State");
            var controllerNameProp = entryProp.FindPropertyRelative("ControllerName");
            var controllerIndexProp = entryProp.FindPropertyRelative("ControllerIndex");

            if (stateProp == null)
            {
                EditorGUILayout.HelpBox($"Unable to find 'State' on entry {i}.", MessageType.Error);
                if (GUILayout.Button("Remove"))
                {
                    _stateEntriesProp.DeleteArrayElementAtIndex(i);
                    break;
                }

                continue;
            }

            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            var t = stateProp.managedReferenceValue.GetType();
            var attr = t.GetCustomAttribute<ControlerStateNameAttribute>();
            var tag = attr != null ? attr.StateName : t.Name;
            EditorGUILayout.LabelField($"State:{tag}", EditorStyles.helpBox);
            EditorGUILayout.BeginHorizontal();


            var controllerNames = GetControllerNamesForRecorder(recorder);
            int selIdx = -1;
            if (!string.IsNullOrEmpty(controllerNameProp.stringValue))
            {
                selIdx = controllerNames.IndexOf(controllerNameProp.stringValue);
            }

            GUILayoutOption ctrlWidth = GUILayout.Width(140);
            if (controllerNames.Count > 0)
            {
                int newSel = EditorGUILayout.Popup(selIdx, controllerNames.ToArray(), ctrlWidth);
                if (newSel >= 0 && newSel < controllerNames.Count)
                    controllerNameProp.stringValue = controllerNames[newSel];
            }
            else
            {
                if (!string.IsNullOrEmpty(controllerNameProp.stringValue))
                {
                    EditorGUI.BeginDisabledGroup(true);
                    EditorGUILayout.HelpBox($"绑定控制器 [{controllerNameProp.stringValue}] 不存在", MessageType.Error);
                    EditorGUI.EndDisabledGroup();
                }
                else
                {
                    EditorGUILayout.HelpBox($"暂无控制器", MessageType.Warning);
                }
            }


            int ctrlLen = GetSelectedControllerLength(recorder, controllerNameProp.stringValue);
            if (ctrlLen <= 0) ctrlLen = 1;
            controllerIndexProp.intValue = Mathf.Clamp(controllerIndexProp.intValue, 0, ctrlLen - 1);
            string[] idxOptions = new string[ctrlLen];
            for (int j = 0; j < ctrlLen; j++) idxOptions[j] = j.ToString();
            int curIdx = Mathf.Clamp(controllerIndexProp.intValue, 0, ctrlLen - 1);

            if (controllerNames.Count > 0)
            {
                int newIdx = EditorGUILayout.Popup(curIdx, idxOptions, GUILayout.Width(60));
                if (newIdx != curIdx) controllerIndexProp.intValue = newIdx;
            }

            GUILayout.FlexibleSpace();


            if (GUILayout.Button(_removeIcon, GUILayout.Width(28), GUILayout.Height(20)))
            {
                _stateEntriesProp.DeleteArrayElementAtIndex(i);
                break;
            }

            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space(4);

            if (stateProp.managedReferenceValue == null)
            {
                EditorGUILayout.HelpBox("State instance is null. Remove and re-add.", MessageType.Warning);
            }
            else
            {
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                EditorGUILayout.LabelField(new GUIContent("属性"), EditorStyles.boldLabel);
                SerializedClassDrawer.DrawSerializableProperty(stateProp);
                EditorGUILayout.EndVertical();
            }

            bool valid = true;
            try
            {
                var inst = stateProp.managedReferenceValue as ControllerStateBase;
                if (inst != null) valid = inst.Valid(recorder);
            }
            catch (Exception ex)
            {
                valid = false;
                Debug.LogException(ex);
            }

            if (!valid)
            {
                EditorGUILayout.HelpBox($"当前状态核验失败 请查看{stateProp.managedReferenceValue.GetType().FullName}脚本Valid", MessageType.Error);
            }

            EditorGUILayout.EndVertical();
            EditorGUILayout.Space();
        }

        serializedObject.ApplyModifiedProperties();
    }


    private void OnTypeSelected(Type type)
    {
        if (type == null) return;

        // 撤销支持
        Undo.RecordObject(serializedObject.targetObject, "Add Controller State");

        serializedObject.Update();

        int idx = _stateEntriesProp.arraySize;
        _stateEntriesProp.InsertArrayElementAtIndex(idx);
        var entryProp = _stateEntriesProp.GetArrayElementAtIndex(idx);
        var stateProp = entryProp.FindPropertyRelative("State");
        var controllerNameProp = entryProp.FindPropertyRelative("ControllerName");
        var controllerIndexProp = entryProp.FindPropertyRelative("ControllerIndex");
        var defaultValueProp = entryProp.FindPropertyRelative("DefaultValue");
        ControllerStateBase instance = null;
        try
        {
            instance = (ControllerStateBase)Activator.CreateInstance(type);
        }
        catch (Exception ex)
        {
            Debug.LogException(ex);
        }

        if (instance != null)
        {
            var recorder = serializedObject.targetObject as UXControllerStateRecorder;
            instance.Init(recorder);
        }

        // 把实例写进 SerializedProperty（需保证你的 State 字段用了 [SerializeReference]）
        if (stateProp != null) stateProp.managedReferenceValue = instance;
        if (stateProp != null) stateProp.isExpanded = true;
        controllerNameProp.stringValue = "";
        controllerIndexProp.intValue = 0;

        serializedObject.ApplyModifiedProperties();
        EditorUtility.SetDirty(serializedObject.targetObject);
    }


    private UXController GetPrefabStageController()
    {
        var stage = PrefabStageUtility.GetCurrentPrefabStage();
        if (stage == null) return null;
        var root = stage.prefabContentsRoot;
        if (root == null) return null;
        return root.GetComponentInChildren<UXController>();
    }

    private List<string> GetControllerNamesForRecorder(UXControllerStateRecorder recorder)
    {
        var names = new List<string>();
        var prefabCtrl = GetPrefabStageController();
        if (prefabCtrl != null)
        {
            foreach (var cd in prefabCtrl.Controllers) names.Add(cd.Name);
            return names;
        }

        var assigned = recorder.Controller;
        if (assigned != null)
        {
            foreach (var cd in assigned.Controllers) names.Add(cd.Name);
            return names;
        }

        var inScene = recorder.gameObject.GetComponentInParent<UXController>();
        if (inScene != null)
        {
            foreach (var cd in inScene.Controllers) names.Add(cd.Name);
            return names;
        }

        return names;
    }

    private int GetSelectedControllerLength(UXControllerStateRecorder recorder, string controllerName)
    {
        var prefabCtrl = GetPrefabStageController();
        if (prefabCtrl != null)
        {
            var ch = prefabCtrl.Controllers.ToList().Find(x => x.Name == controllerName);
            if (ch != null) return ch.Length;
        }

        var assigned = recorder.Controller;
        if (assigned != null)
        {
            var ch = assigned.Controllers.ToList().Find(x => x.Name == controllerName);
            if (ch != null) return ch.Length;
        }

        var inScene = recorder.gameObject.GetComponentInParent<UXController>();
        if (inScene != null)
        {
            var ch = inScene.Controllers.ToList().Find(x => x.Name == controllerName);
            if (ch != null) return ch.Length;
        }

        return 1;
    }
}
#endif
