﻿using ImpactCFX;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

namespace ImpactCFXConversion
{
    public class ConversionContext
    {
        public readonly string OutputPath;

        private Dictionary<int, Object> convertedObjectMap = new Dictionary<int, Object>();
        private List<ConversionContextDestroyGroup> destroyGroups = new List<ConversionContextDestroyGroup>();

        private List<ImpactMaterialAuthoring> convertedMaterials = new List<ImpactMaterialAuthoring>();
        private ImpactMaterialRegistry impactMaterialRegistry;

        private Dictionary<string, string> moveAssetsMap = new Dictionary<string, string>();

        public ConversionContext(string outputPath)
        {
            OutputPath = outputPath;
        }

        public void AddConvertedMaterial(ImpactMaterialAuthoring impactMaterialAuthoring)
        {
            if (!convertedMaterials.Contains(impactMaterialAuthoring))
            {
                convertedMaterials.Add(impactMaterialAuthoring);
            }
        }

        public void CreateImpactMaterialRegistryAsset()
        {
            impactMaterialRegistry = ScriptableObject.CreateInstance<ImpactMaterialRegistry>();
            impactMaterialRegistry.Materials = convertedMaterials.ToArray();

            string impactMaterialRegistryPath = Path.Combine(OutputPath, "Impact CFX Material Registry.asset");
            AssetDatabase.CreateAsset(impactMaterialRegistry, impactMaterialRegistryPath);
        }

        public ImpactMaterialRegistry GetImpactMaterialRegistry()
        {
            return impactMaterialRegistry;
        }

        public void AddConvertedObject(int key, Object convertedObject)
        {
            if (!HasConvertedObject(key))
                convertedObjectMap.Add(key, convertedObject);
        }

        public bool HasConvertedObject(int key)
        {
            return convertedObjectMap.ContainsKey(key);
        }

        public bool TryGetConvertedObject(int key, out Object convertedObject)
        {
            return convertedObjectMap.TryGetValue(key, out convertedObject);
        }

        public void AddObjectToDestroy(ConversionContextDestroyGroupType group, Object o)
        {
            if (tryGetDestroyGroup(group, out ConversionContextDestroyGroup destroyGroup))
            {
                destroyGroup.AddObjectToDestroy(o);
            }
            else
            {
                ConversionContextDestroyGroup newGroup = new ConversionContextDestroyGroup()
                {
                    GroupType = group,
                    Objects = new List<Object>()
                };

                newGroup.AddObjectToDestroy(o);
                destroyGroups.Add(newGroup);
            }
        }

        private bool tryGetDestroyGroup(ConversionContextDestroyGroupType groupType, out ConversionContextDestroyGroup destroyGroup)
        {
            foreach (ConversionContextDestroyGroup group in destroyGroups)
            {
                if (group.GroupType == groupType)
                {
                    destroyGroup = group;
                    return true;
                }
            }

            destroyGroup = null;
            return false;
        }

        public void DestroyObjects(ConversionContextDestroyGroupType groupType)
        {
            foreach (ConversionContextDestroyGroup group in destroyGroups)
            {
                if (group.GroupType == groupType)
                {
                    group.DestroyObjects();
                }
            }
        }

        public void AddMoveAsset(string newAssetPath, string oldAssetPath)
        {
            if (!moveAssetsMap.ContainsKey(newAssetPath))
                moveAssetsMap.Add(newAssetPath, oldAssetPath);
        }

        public void MoveAssets()
        {
            foreach (KeyValuePair<string, string> kvp in moveAssetsMap)
            {
                AssetDatabase.MoveAsset(kvp.Key, kvp.Value);
            }
        }
    }

    public class ConversionContextDestroyGroup
    {
        public ConversionContextDestroyGroupType GroupType;
        public List<Object> Objects;

        public void AddObjectToDestroy(Object o)
        {
            if (!Objects.Contains(o))
                Objects.Add(o);
        }

        public void DestroyObjects()
        {
            foreach (Object o in Objects)
            {
                if (GroupType == ConversionContextDestroyGroupType.Assets)
                {
                    string assetPath = AssetDatabase.GetAssetPath(o);
                    AssetDatabase.DeleteAsset(assetPath);
                }
                else
                {
                    Object.DestroyImmediate(o, true);
                }

            }
            Objects.Clear();
        }
    }

    public enum ConversionContextDestroyGroupType
    {
        Assets = 0,
        Components = 1,
    }
}
