using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Gamecraft.Tweaks;
using HarmonyLib;
using Svelto.ECS;

namespace CodeGenerator
{
    public static class ECSAnalyzer
    {
        public static ECSClassInfo AnalyzeEntityDescriptor(Type entityDescriptorType)
        {
            // TODO: Add support for creating/deleting entities (getting an up to date server/client engines root)
            var templateType = typeof(EntityDescriptorTemplate<>).MakeGenericType(entityDescriptorType);
            var templateDescriptor = AccessTools.Property(templateType, "descriptor");
            var getDescriptorExpr = Expression.MakeMemberAccess(null, templateDescriptor ?? throw new InvalidOperationException());
            var getTemplateDescriptorExpr =
                Expression.Lambda<Func<IEntityDescriptor>>(getDescriptorExpr);
            var getTemplateDescriptor = getTemplateDescriptorExpr.Compile();
            // TODO: Crashes on constructing the descriptor type. Maybe move the analysis part to a mod.
            var builders = getTemplateDescriptor().componentsToBuild;
            return new ECSClassInfo
            {
                Name = entityDescriptorType.Name.Replace("EntityComponent", "").Replace("EntityStruct", ""),
                Properties = builders.Select(builder => builder.GetEntityComponentType()).SelectMany(AnalyzeFields).ToArray()
            };
        }

        private static ECSPropertyInfo[] AnalyzeFields(Type componentType)
        {
            bool useReflection = componentType.IsNotPublic;
            var result = new List<ECSPropertyInfo>();
            foreach (var field in componentType.GetFields())
            {
                var attr = field.GetCustomAttribute<TweakableStatAttribute>();
                string propName = field.Name;
                if (attr != null)
                    propName = attr.propertyName;

                propName = char.ToUpper(propName[0]) + propName[1..];
                if (useReflection)
                {
                    result.Add(new ECSReflectedPropertyInfo
                    {
                        Name = propName,
                        Type = field.FieldType,
                        OriginalClassName = componentType.FullName,
                        ComponentType = componentType
                    });
                }

                result.Add(new ECSPropertyInfo
                {
                    Name = propName,
                    Type = field.FieldType,
                    ComponentType = componentType
                });
            }

            return result.ToArray();
        }
    }
}