using Impact.Utility.ObjectPool;
using UnityEditor;
using UnityEngine;

namespace ImpactCFXConversion
{
    public delegate void ConvertPrefabDelegate<TConvertFrom, TConvertTo>(
        TConvertFrom from,
        SerializedObject fromObject,
        TConvertTo to,
        SerializedObject toObject)
        where TConvertFrom : Component where TConvertTo : Component;

    public static class ConversionUtility
    {
        public static void ConvertRange(Impact.Utility.Range src, SerializedProperty dst)
        {
            SerializedProperty min = dst.FindPropertyRelative("Min");
            SerializedProperty max = dst.FindPropertyRelative("Max");

            min.floatValue = src.Min;
            max.floatValue = src.Max;
        }

        public static void ConvertObjectPoolConfig(int poolSize, ObjectPoolFallbackMode fallbackMode, SerializedProperty dst)
        {
            SerializedProperty size = dst.FindPropertyRelative("PoolSize");
            SerializedProperty stealing = dst.FindPropertyRelative("Stealing");

            size.intValue = poolSize;
            stealing.enumValueIndex = (int)fallbackMode;
        }

        public static TConvertTo ConvertPrefab<TConvertFrom, TConvertTo>(
            TConvertFrom src,
            ConversionContext conversionContext,
            ConvertPrefabDelegate<TConvertFrom, TConvertTo> convert)
            where TConvertFrom : Component where TConvertTo : Component
        {
            if (src == null || src.Equals(null))
                return default;

            if (conversionContext.TryGetConvertedObject(src.GetInstanceID(), out Object convertedAsset))
            {
                return convertedAsset as TConvertTo;
            }
            else if (src.gameObject != null && !src.gameObject.Equals(null))
            {
                TConvertFrom oldComponent = src.gameObject.GetComponent<TConvertFrom>();
                SerializedObject oldSerializedObject = new SerializedObject(src);

                //Add new component
                TConvertTo newComponent = src.gameObject.AddComponent<TConvertTo>();
                SerializedObject newSerializedObject = new SerializedObject(newComponent);

                //Convert
                convert(oldComponent, oldSerializedObject, newComponent, newSerializedObject);

                //Save
                newSerializedObject.ApplyModifiedProperties();
                newSerializedObject.Dispose();
                oldSerializedObject.Dispose();

                PrefabUtility.SavePrefabAsset(newComponent.gameObject);

                //Add to converted asset map
                conversionContext.AddConvertedObject(src.GetInstanceID(), newComponent);

                conversionContext.AddObjectToDestroy(ConversionContextDestroyGroupType.Components, oldComponent);

                return newComponent;
            }

            return default;
        }

        public static void ConvertImpactTagMask(Impact.ImpactTagMask src, SerializedProperty dst)
        {
            dst.FindPropertyRelative("Value").intValue = src.Value;
        }

        public static void LogComponentConversion(Component src, Component dst, GameObject gameObject)
        {
            Debug.Log($"[Impact CFX Conversion Component] Converted '{src}' to '{dst}' on game object '{gameObject}'");
        }

        public static void LogAssetConversion(Object src, Object dst)
        {
            Debug.Log($"[Impact CFX Conversion Asset] Converted '{src}' to '{dst}'");
        }
    }
}