using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using VContainer.Diagnostics;

namespace VContainer.Editor.Diagnostics
{
    public sealed class VContainerInstanceTreeView : TreeView
    {
        static int idSeed;
        static int NextId() => ++idSeed;

        static string Stringify(object instance)
        {
            if (ReferenceEquals(instance, null))
                return "null";
            if (instance is UnityEngine.Object obj && obj == null)
                return "null or destroyed";
            return instance.ToString();
        }

        public DiagnosticsInfo CurrentDiagnosticsInfo { get; set; }

        public VContainerInstanceTreeView() : base(new TreeViewState())
        {
            Reload();
        }

        protected override TreeViewItem BuildRoot()
        {
            var root = new TreeViewItem(NextId(), -1, "Root");
            var children = new List<TreeViewItem>();
            if (CurrentDiagnosticsInfo is DiagnosticsInfo info)
            {
                for (var i = 0; i < info.ResolveInfo.Instances.Count; i++)
                {
                    var instance = info.ResolveInfo.Instances[i];
                    var item = new TreeViewItem(NextId(), 0,
                        $"({TypeNameHelper.GetTypeAlias(instance.GetType())}) {Stringify(instance)}");
                    AddProperties(instance, item);
                    children.Add(item);
                    SetExpanded(item.id, true);
                }
            }

            root.children = children;
            return root;
        }

        void AddProperties(object instance, TreeViewItem parent)
        {
            if (instance == null) return;

            var type = instance.GetType();
            var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            foreach (var prop in props)
            {
                if (prop.PropertyType.IsSubclassOf(typeof(UnityEngine.Object)) &&
                    prop.IsDefined(typeof(ObsoleteAttribute), true))
                {
                    continue;
                }

                try
                {
                    if (prop.CanRead)
                    {
                        var value = prop.GetValue(instance);
                        var displayName = $"{prop.Name} = ({TypeNameHelper.GetTypeAlias(prop.PropertyType)}) {Stringify(value)}";
                        parent.AddChild(new TreeViewItem(NextId(), parent.depth + 1, displayName));
                    }
                    else
                    {
                        var displayName = $"{prop.Name} = (write-only {TypeNameHelper.GetTypeAlias(prop.PropertyType)})";
                        parent.AddChild(new TreeViewItem(NextId(), parent.depth + 1, displayName));
                    }
                }
                catch (MissingReferenceException)
                {
                }
                catch (NotSupportedException)
                {
                }
            }

            foreach (var field in fields)
            {
                if ((field.FieldType.IsSubclassOf(typeof(UnityEngine.Object)) &&
                    field.IsDefined(typeof(ObsoleteAttribute), true)) ||
                    field.IsDefined(typeof(CompilerGeneratedAttribute), true))
                {
                    continue;
                }

                try
                {
                    var value = field.GetValue(instance);
                    var displayName = $"{field.Name} = ({TypeNameHelper.GetTypeAlias(field.FieldType)}) {Stringify(value)}";
                    parent.AddChild(new TreeViewItem(NextId(), parent.depth + 1, displayName));
                }
                catch (MissingReferenceException)
                {
                }
                catch (NotSupportedException)
                {
                }
            }
        }
    }
}
