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

public class StateTypeSearchProvider : ScriptableObject, ISearchWindowProvider
{
    private Action<Type> _onSelect;
    private List<SearchTreeEntry> _entries;

    public void Init(Action<Type> onSelect)
    {
        _onSelect = onSelect;
        BuildEntries();
    }

    private void BuildEntries()
    {
        _entries = new List<SearchTreeEntry>();

        _entries.Add(new SearchTreeGroupEntry(new GUIContent("States")));

        var all = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(a =>
            {
                try { return a.GetTypes(); }
                catch { return new Type[0]; }
            })
            .Where(t => typeof(ControllerStateBase).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
            .Select(t =>
            {
                var attr = t.GetCustomAttribute<ControlerStateNameAttribute>();
                var tag = attr != null ? attr.StateName : t.Name;
                return (type: t, tag);
            })
            .OrderBy(x => x.tag)
            .ToArray();


        var groups = new Dictionary<string, List<(Type type, string fullTag, string display)>>();
        foreach (var item in all)
        {
            string[] parts = item.tag.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            string g = parts.Length > 0 ? parts[0] : "Other";
            string child = parts.Length > 1 ? string.Join("/", parts.Skip(1)) : (parts.Length == 1 ? parts[0] : item.type.Name);
            string display = $"{child}";

            if (!groups.TryGetValue(g, out var list)) { list = new List<(Type, string, string)>(); groups[g] = list; }
            list.Add((item.type, item.tag, display));
        }

        foreach (var kv in groups.OrderBy(k => k.Key))
        {
            _entries.Add(new SearchTreeGroupEntry(new GUIContent(kv.Key)) { level = 1 });
            foreach (var child in kv.Value.OrderBy(c => c.fullTag))
            {
                var entry = new SearchTreeEntry(new GUIContent(child.display)) { level = 2, userData = child.type };
                _entries.Add(entry);
            }
        }
    }

    public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
    {
        if (_entries == null) BuildEntries();
        return _entries;
    }

    public bool OnSelectEntry(SearchTreeEntry entry, SearchWindowContext context)
    {
        var t = entry.userData as Type;
        if (t != null)
        {
            _onSelect?.Invoke(t);
            return true;
        }
        return false;
    }
}
#endif
