using UnityEditor;
using UnityEngine;

namespace ImpactCFXConversion
{
    public class ImpactObjectConverter : IAssetConverter
    {
        public Object Convert(Object source, ConversionContext conversionContext)
        {
            if (source is GameObject g)
            {
                Impact.Objects.IImpactObject[] impactObjects = g.GetComponentsInChildren<Impact.Objects.IImpactObject>();
                ImpactTriggerConverter impactTriggerConverter = new ImpactTriggerConverter();

                foreach (Impact.Objects.IImpactObject obj in impactObjects)
                {
                    if (obj is Impact.Objects.ImpactObjectRigidbody rigidbody)
                    {
                        ImpactCFX.ImpactObjectRigidbody newObject = rigidbody.gameObject.AddComponent<ImpactCFX.ImpactObjectRigidbody>();
                        convertSingleMaterial(rigidbody, newObject, conversionContext);
                    }
                    else if (obj is Impact.Objects.ImpactObjectRigidbodyCheap rigidbodyCheap)
                    {
                        ImpactCFX.ImpactObjectRigidbodyCheap newObject = rigidbodyCheap.gameObject.AddComponent<ImpactCFX.ImpactObjectRigidbodyCheap>();
                        convertSingleMaterial(rigidbodyCheap, newObject, conversionContext);
                    }
                    else if (obj is Impact.Objects.ImpactObjectRigidbodyChild rigidbodyChild)
                    {
                        ImpactCFX.ImpactObjectChild newObject = rigidbodyChild.gameObject.AddComponent<ImpactCFX.ImpactObjectChild>();
                        convertSingleMaterial(rigidbodyChild, newObject, conversionContext);
                    }
                    else if (obj is Impact.Objects.ImpactObjectSingleMaterial singleMaterial)
                    {
                        ImpactCFX.ImpactObjectSingleMaterial newObject = singleMaterial.gameObject.AddComponent<ImpactCFX.ImpactObjectSingleMaterial>();
                        convertSingleMaterial(singleMaterial, newObject, conversionContext);
                    }
                    else if (obj is Impact.Objects.ImpactTerrain terrain)
                    {
                        ImpactCFX.ImpactObjectTerrain newObject = terrain.gameObject.AddComponent<ImpactCFX.ImpactObjectTerrain>();
                        convertTerrain(terrain, newObject, conversionContext);
                    }
                    else
                    {
                        Debug.LogError($"Unable to convert object '{obj}' on game object '{obj.GameObject.name}'");
                    }
                }

                impactTriggerConverter.Convert(source, conversionContext);
            }

            return source;
        }

        private void convertSingleMaterial(Impact.Objects.ImpactObjectSingleMaterial src, ImpactCFX.ImpactObjectSingleMaterial dst, ConversionContext conversionContext)
        {
            SerializedObject serializedObject = new SerializedObject(dst);

            SerializedProperty materialProperty = serializedObject.FindProperty("impactMaterial");
            if (conversionContext.TryGetConvertedObject(src.Material.GetInstanceID(), out Object converted))
            {
                materialProperty.objectReferenceValue = converted;
            }
            else
            {
                Debug.LogError($"Unable to find converted material '{src.Material.name}' for object '{src.gameObject.name}'");
            }

            serializedObject.ApplyModifiedProperties();
            serializedObject.Dispose();

            conversionContext.AddConvertedObject(src.GetInstanceID(), dst);
            conversionContext.AddObjectToDestroy(ConversionContextDestroyGroupType.Components, src);

            ConversionUtility.LogComponentConversion(src, dst, src.gameObject);
        }

        private void convertTerrain(Impact.Objects.ImpactTerrain src, ImpactCFX.ImpactObjectTerrain dst, ConversionContext conversionContext)
        {
            SerializedObject serializedObject = new SerializedObject(dst);

            serializedObject.FindProperty("terrain").objectReferenceValue = src.Terrain;

            SerializedProperty materialsArray = serializedObject.FindProperty("terrainMaterials");
            materialsArray.arraySize = src.TerrainMaterials.Count;

            for (int i = 0; i < src.TerrainMaterials.Count; i++)
            {
                if (conversionContext.TryGetConvertedObject(src.TerrainMaterials[i].GetInstanceID(), out Object converted))
                {
                    materialsArray.GetArrayElementAtIndex(i).objectReferenceValue = converted;
                }
                else
                {
                    Debug.LogError($"Unable to find converted material '{src.TerrainMaterials[i].name}' for object '{src.gameObject.name}'");
                }
            }

            serializedObject.ApplyModifiedProperties();
            serializedObject.Dispose();

            conversionContext.AddConvertedObject(src.GetInstanceID(), dst);
            conversionContext.AddObjectToDestroy(ConversionContextDestroyGroupType.Components, src);

            ConversionUtility.LogComponentConversion(src, dst, src.gameObject);
        }
    }
}