using System;
using System.Collections.Generic;
using UnityEngine;

// Override to create events that pass back specific data to listeners of the event
public class CallbackEvent
{
    public string m_Type
    {
        get; set;
    }

    public CallbackEvent()
    {
        m_Type = "CallbackEvent";
    }
}

struct TriggeredEvent
{
    public string eventName;
    public CallbackEvent eventData;

    public TriggeredEvent(string aEventName, CallbackEvent aEventData)
    {
        eventName = aEventName;
        eventData = aEventData;
    }
}


public class EventManager : BaseManager<EventManager>
{
    private Dictionary<string, Dictionary<string, Action<CallbackEvent>>> eventDictionary;
    private List<TriggeredEvent> triggeredEvents;

    // prevent multiple copies of this manager
    protected EventManager()
    {
        eventDictionary = new Dictionary<string, Dictionary<string, Action<CallbackEvent>>>();
        triggeredEvents = new List<TriggeredEvent>();
    }

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        // We want to fire off the events all at once in succession the order they came in.
        // This allows for a more accurate sequence of events when we have lots of events being triggered all at the same time.
        if(triggeredEvents.Count > 0)
        {
            for (int i = 0; i <  triggeredEvents.Count; ++i)
            {
                string eventName = triggeredEvents[i].eventName;
                Dictionary<string, Action<CallbackEvent>> eventCallbackDictionary;
                if (Instance.eventDictionary.TryGetValue(eventName, out eventCallbackDictionary))
                {
                    CallbackEvent eventData = triggeredEvents[i].eventData;
                    foreach (KeyValuePair<string, Action<CallbackEvent>> keyValuePair in eventCallbackDictionary)
                    {
                        Action<CallbackEvent> action = keyValuePair.Value;
                        action(eventData);
                    }
                }
            }

            triggeredEvents.Clear();
        }
    }

    public static void RegisterEvent(string aEventName, string aUniqueId, Action<CallbackEvent> aCallback)
    {
        Dictionary<string, Action<CallbackEvent>> eventCallbackDictionary;
        if (!Instance.eventDictionary.TryGetValue(aEventName, out eventCallbackDictionary))
        {
            eventCallbackDictionary = new Dictionary<string, Action<CallbackEvent>>();
            Instance.eventDictionary.Add(aEventName, eventCallbackDictionary);
        }

        Action<CallbackEvent> action;
        if (eventCallbackDictionary.TryGetValue(aUniqueId, out action))
        {
            Debug.LogWarning("[EventManager] WARNING - trying to assign a callback for id: " + aUniqueId +
                             "and one already exists. This will override the current callback set");
        }

        eventCallbackDictionary.Add(aUniqueId, aCallback);
    }

    public static void UnregisterEvent(string aEventName, string aUniqueId)
    {
        Dictionary<string, Action<CallbackEvent>> eventCallbackDictionary;
        if (Instance.eventDictionary.TryGetValue(aEventName, out eventCallbackDictionary))
        {
            Action<CallbackEvent> action;
            if (eventCallbackDictionary.TryGetValue(aUniqueId, out action))
            {
                eventCallbackDictionary.Remove(aUniqueId);
                if (eventCallbackDictionary.Count == 0)
                {
                    Instance.eventDictionary.Remove(aEventName);
                }
            }
        }
    }

    public static void TriggerEvent(string aEventName, CallbackEvent aEvent)
    {
        TriggeredEvent newEvent = new TriggeredEvent(aEventName, aEvent);
        Instance.triggeredEvents.Add(newEvent);
    }
}