﻿using JLGames.RocketDriver.CSharp;
using UnityEngine;

namespace JLGames.RocketDriver.Actions.Animatorx
{
    [RequireComponent(typeof(Animator))]
    public class AnimationEventProxy : MonoBehaviour
    {
        private Animator m_Animator;

        private void Awake()
        {
            m_Animator = GetComponent<Animator>();
        }

        /// <summary>
        /// Add a frame event to the end of the animation
        /// 添加一个帧事件到动画的结尾处
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="eventName"></param>
        /// <param name="callFunc"></param>
        public void AddInvokerEventEnd(string clipName, string eventName, Callback.Func callFunc)
        {
            var callback = new Callback(callFunc);
            AddInvokerEventEnd(clipName, eventName, callback);
        }

        /// <summary>
        /// Add a frame event to the end of the animation
        /// 添加一个帧事件到动画的结尾处
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="eventName"></param>
        /// <param name="callback"></param>
        public void AddInvokerEventEnd(string clipName, string eventName, Callback callback)
        {
            if (string.IsNullOrEmpty(clipName) || string.IsNullOrEmpty(eventName) || null == callback) return;
            var clip = m_Animator.FindClip(clipName);
            if (null == clip) return;
            clip.AddInvokerEventEnd(gameObject, eventName, callback);
        }

        /// <summary>
        /// Add a one-time frame event to the end of the animation
        /// 添加一个一次性帧事件到动画的结尾处
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="eventName"></param>
        /// <param name="callFunc"></param>
        public void OnceInvokerEventEnd(string clipName, string eventName, Callback.Func callFunc)
        {
            OnceInvokerEventEnd(clipName, eventName, new Callback(callFunc));
        }

        /// <summary>
        /// Add a one-time frame event to the end of the animation
        /// 添加一个一次性帧事件到动画的结尾处
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="eventName"></param>
        /// <param name="callback"></param>
        public void OnceInvokerEventEnd(string clipName, string eventName, Callback callback)
        {
            var newCallback = new Callback(AutoRemove, callback, clipName, eventName);
            AddInvokerEventEnd(clipName, eventName, newCallback);
        }

        /// <summary>
        /// Add a frame event to the specified time point of the animation
        /// 添加一个帧事件到动画的指定时间点
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="seconds"></param>
        /// <param name="eventName"></param>
        /// <param name="callFunc"></param>
        public void AddInvokerEvent(string clipName, float seconds, string eventName, Callback.Func callFunc)
        {
            var callback = new Callback(callFunc);
            AddInvokerEvent(clipName, seconds, eventName, callback);
        }

        /// <summary>
        /// Add a frame event to the specified time point of the animation
        /// 添加一个帧事件到动画的指定时间点
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="seconds"></param>
        /// <param name="eventName"></param>
        /// <param name="callback"></param>
        public void AddInvokerEvent(string clipName, float seconds, string eventName, Callback callback)
        {
            if (string.IsNullOrEmpty(clipName) || string.IsNullOrEmpty(eventName) || null == callback) return;
            var clip = m_Animator.FindClip(clipName);
            if (null == clip) return;
            clip.AddInvokerEvent(gameObject, seconds, eventName, callback);
        }

        /// <summary>
        /// Add a one-time frame event to the specified time point of the animation
        /// 添加一个一次性帧事件到动画的指定时间点
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="seconds"></param>
        /// <param name="eventName"></param>
        /// <param name="callFunc"></param>
        public void OnceInvokerEvent(string clipName, float seconds, string eventName, Callback.Func callFunc)
        {
            OnceInvokerEvent(clipName, seconds, eventName, new Callback(callFunc));
        }

        /// <summary>
        /// Add a one-time frame event to the specified time point of the animation
        /// 添加一个一次性帧事件到动画的指定时间点
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="seconds"></param>
        /// <param name="eventName"></param>
        /// <param name="callback"></param>
        public void OnceInvokerEvent(string clipName, float seconds, string eventName, Callback callback)
        {
            var newCallback = new Callback(AutoRemove, callback, clipName, eventName);
            AddInvokerEvent(clipName, seconds, eventName, newCallback);
        }

        private void AutoRemove(params object[] args)
        {
            var callback = args[0] as Callback;
            callback?.Invoke();
            var clipName = args[1] as string;
            var eventName = args[2] as string;
            RemoveInvokerEvent(clipName, eventName);
        }

        /// <summary>
        /// Removes a specified frame event from the specified animation
        /// 移除指定动画中的一个指定帧事件
        /// </summary>
        /// <param name="clipName"></param>
        /// <param name="eventName"></param>
        public void RemoveInvokerEvent(string clipName, string eventName)
        {
            if (string.IsNullOrEmpty(clipName) || string.IsNullOrEmpty(eventName)) return;
            m_Animator.FindClip(clipName)?.RemoveInvokerEvent(gameObject, eventName);
        }
    }
}