using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using Object = UnityEngine.Object;

public class EffectPool<T> : IDisposable where T : Enum
{
    private Dictionary<T, List<Object>> PoolDic;
    private Dictionary<T, Transform> PollPar;
    private List<T> temp;
    private Transform objectPoolPar;
    public Action<T, UnityAction<UnityEngine.Object>> NewObjFunc;
    public Action<T, Object> RecObjFunc;
    public Action<T, Object> GetObjFunc;


    public EffectPool(Transform _objectPoolPar = null)
    {
        objectPoolPar = _objectPoolPar;
        if (objectPoolPar == null)
        {
            objectPoolPar = new GameObject("ObjectPool").transform;
            objectPoolPar.localPosition = Vector3.zero;
            objectPoolPar.localEulerAngles = Vector3.zero;
        }

        PoolDic = new Dictionary<T, List<Object>>();
        PollPar = new Dictionary<T, Transform>();
        temp = new List<T>();
    }


    public void GetObject<Obj>(T key, UnityAction<Obj> action) where Obj : Object
    {
        if (!PoolDic.ContainsKey(key))
        {
            AddKey(key);
        }

        if (PoolDic[key].Count > 0)
        {
            var obj = PoolDic[key][0] as Obj;
            PoolDic[key].RemoveAt(0);
            GetObjFunc?.Invoke(key, obj);
            action?.Invoke(obj);
        }
        else
        {
            LoadObject(key, (obj) =>
            {
                GetObjFunc?.Invoke(key, obj);
                action?.Invoke(obj as Obj);
            });
        }
    }

    private void AddKey(T key)
    {
        PoolDic.Add(key, new List<Object>());
        Transform par = new GameObject(key.ToString()).transform;
        par.SetParent(objectPoolPar);
        par.localScale = Vector3.one;
        par.localPosition = Vector3.zero;
        par.localEulerAngles = Vector3.zero;
        PollPar.Add(key, par.transform);
    }

    private void LoadObject(T key, UnityAction<Object> action)
    {
        NewObjFunc?.Invoke(key, (obj) =>
        {
            if (obj != null)
            {
                GameObject go = obj as GameObject ?? (obj as Component).gameObject;

                if (PollPar.TryGetValue(key, out Transform par) && go != null)
                {
                    go.transform.SetParent(par);
                }
            }
            else
            {
                Debug.LogError(key.ToString() + "创建失败");
            }

            action?.Invoke(obj);
        });
    }

    public void RecObject(T key, Object obj)
    {
        if (obj == null) return;
        if (!PoolDic.ContainsKey(key))
        {
            PoolDic.Add(key, new List<Object>());
        }

        GameObject go = obj as GameObject ?? (obj as Component).gameObject;
        if (PollPar.TryGetValue(key, out Transform par))
        {
            go.transform.parent = (par);
        }

        RecObjFunc?.Invoke(key, obj);
        PoolDic[key].Add(obj);
    }

    public void RemoveKey(T key)
    {
        if (PoolDic.ContainsKey(key))
        {
            foreach (Object item in PoolDic[key])
            {
                if (item != null)
                {
                    GameObject go = item as GameObject;
                    if (go == null)
                    {
                        Component cot = item as Component;
                        go = cot.gameObject;
                    }

                    GameObject.Destroy(go);
                }
            }

            PoolDic[key].Clear();
            PoolDic.Remove(key);
        }
    }

    public void RemoveAll()
    {
        temp.Clear();
        foreach (var item in PoolDic)
        {
            temp.Add(item.Key);
        }

        foreach (var item in temp)
        {
            RemoveKey(item);
        }

        temp.Clear();
    }


    public void Dispose()
    {
        RemoveAll();
        PoolDic = null;
        PollPar = null;
        temp = null;
    }
}