using System;
using System.Collections.Generic;
using JNGame.Util;
using UnityEngine;

namespace Plugins.JNGame.Util
{
    /// <summary>
    /// 静态事件分发器
    /// </summary>
    public class EventDispatcher
    {

        public static readonly EventDispatcher Event = new EventDispatcher();
        
        public Dictionary<string, List<Delegate>> EventHandlers { get; private set; } = new();

        /// <summary>
        /// 添加事件监听器
        /// </summary>
        /// <param name="eventId">事件标识符</param>
        /// <param name="listener">事件监听器</param>
        public void AddListener(string eventId, Action listener)
        {
            if (!EventHandlers.ContainsKey(eventId))
            {
                EventHandlers[eventId] = new List<Delegate>();
            }

            EventHandlers[eventId].Add(listener);
            Debug.Log(eventId+ "AddListener" + EventHandlers[eventId].Count);
        }
        
        /// <summary>
        /// 添加事件监听器
        /// </summary>
        /// <typeparam name="T">事件参数类型</typeparam>
        /// <param name="eventId">事件标识符</param>
        /// <param name="listener">事件监听器</param>
        public void AddListener<T>(string eventId, Action<T> listener)
        {
            if (!EventHandlers.ContainsKey(eventId))
            {
                EventHandlers[eventId] = new List<Delegate>();
            }

            EventHandlers[eventId].Add(listener);
            Debug.Log(eventId+ "AddListener" + EventHandlers[eventId].Count);
        }

        /// <summary>
        /// 移除事件监听器
        /// </summary>
        /// <typeparam name="T">事件参数类型</typeparam>
        /// <param name="eventId">事件标识符</param>
        /// <param name="listener">事件监听器</param>
        public void RemoveListener(string eventId, Action listener)
        {
            if (EventHandlers.ContainsKey(eventId))
            {
                //eventHandlers[eventId] = (Action<T>)eventHandlers[eventId] - listener;
                EventHandlers[eventId].Remove(listener);
                Debug.Log(eventId + "RemoveListener" + EventHandlers[eventId].Count);
            }
        }
        public void RemoveListener<T>(string eventId, Action<T> listener)
        {
            if (EventHandlers.ContainsKey(eventId))
            {
                //eventHandlers[eventId] = (Action<T>)eventHandlers[eventId] - listener;
                EventHandlers[eventId].Remove(listener);
                Debug.Log(eventId + "RemoveListener" + EventHandlers[eventId].Count);
            }
        }

        /// <summary>
        /// 分发事件
        /// </summary>
        /// <typeparam name="T">事件参数类型</typeparam>
        /// <param name="eventId">事件标识符</param>
        /// <param name="args">事件参数</param>
        public void Dispatch<T>(string eventId, T args)
        {
            if (EventHandlers.ContainsKey(eventId) && EventHandlers[eventId] != null)
            {
                foreach(Delegate fun in EventHandlers[eventId])
                {
                    // 确保 fun 实际上是指向一个 Action<T> 类型的函数  
                    if (fun.Method.GetParameters().Length == 1 && fun.Method.GetParameters()[0].ParameterType == typeof(T))  
                    {  
                        ((Action<T>)fun)(args);  
                    }  
                }
            }
        }
        
        public void Dispatch(string eventId)
        {
            if (EventHandlers.ContainsKey(eventId) && EventHandlers[eventId] != null)
            {
                foreach(Delegate fun in EventHandlers[eventId])
                {
                    // 确保 fun 实际上是指向一个 Action<T> 类型的函数  
                    if (fun.Method.GetParameters().Length == 0)  
                    {  
                        ((Action)fun)();  
                    }  
                }
            }
        }

        /// <summary>
        /// 主线程分发事件 [禁止帧同步中使用主线分发事件]
        /// </summary>
        public void TryMainDispatch<T>(string eventId, T args)
        {
            UnityMainThreadDispatcher.Instance.Enqueue(() =>
            {
                try
                {
                    Dispatch<T>(eventId,args);
                }catch(Exception e){Debug.LogError(e.Message);}
            });
        }
        public void TryMainDispatch(string eventId)
        {
            UnityMainThreadDispatcher.Instance.Enqueue(() =>
            {
                try
                {
                    Dispatch(eventId);
                }catch(Exception e){Debug.LogError(e.Message);}
            });
        }
        
        public void Reset()
        {
            EventHandlers = new();
        }
    }
}