using Spine.Unity;
using System;
using UnityEngine;
using XGame.Database;
using XGame.Framework.Components;
using XGame.Framework.Interfaces;
using XGame.Framework.Time;

namespace FL.Battle.Components
{
    public interface ISpineContext
    {
        IEntity Entity { get; }
        SkeletonAnimation Skeleton { get; }
        ITimeModule Time { get; }
    }
    public class SpineComponent : Component<ISpineContext>, IAnimator, IReset
    {
        private ITimer _actionTimer;
        /// <summary>
        /// 触发器的定时器
        /// </summary>
        private ITimer _triggerTimer;
        protected override void OnDisable()
        {
            ClearTimers();
        }
        protected override void OnDispose()
        {
            ClearTimers();
        }
        private void ClearTimers()
        {
            _actionTimer?.Cancel();
            _actionTimer = null;
            _triggerTimer?.Cancel();
            _triggerTimer = null;
        }
        public bool IsLoop(EAnimationName actionName)
        {
            return actionName switch
            {
                EAnimationName.idle or EAnimationName.idle2 or EAnimationName.dizzy or EAnimationName.freeze or EAnimationName.palsy => true,
                _ => false,
            };
        }
        public void Play(EAnimationName aniName)
        {
            Play(new AnimationPlayArgs { aniName = aniName });
        }
        public void Play(AnimationPlayArgs args)
        {
            var skeleton = Context.Skeleton;
            if (skeleton == null)
                return;
            //if (_actionTimer != null)
            //{
            //    Log.Debug($"Spine Name:{skeleton.name} Now:{skeleton.AnimationName} Next:{args.aniName}");
            //}
            var isLoop = IsLoop(args.aniName);
            skeleton.loop = isLoop;
            skeleton.AnimationName = args.aniName.ToString();
            //var state = skeleton.AnimationState;
            //state.Tracks.Items[0].Animation.Duration
            ClearTimers();
            var duration = skeleton.GetDurationMS();
            if (args.onTrigger != null && args.triggerFrame > 0 && args.triggerFrame < duration)
            {
                _triggerTimer = Context.Time.AddDelayTimer(args.triggerFrame, () =>
                {
                    _triggerTimer = null;
                    args.onTrigger.SafeInvoke();
                    //try
                    //{
                    //    args.onTrigger?.Invoke();
                    //}
                    //catch (Exception ex)
                    //{
                    //    XGame.Log.Error($"SpineComponent onTrigger Exception Entity:{Context.Entity.EntityId} Name:{Context.Entity.Attr.Name}");
                    //    XGame.Log.Exception(ex);
                    //}
                });
            }
            if (!isLoop)
            { // 非循环动作才有回调
                SetSkeletonFill(Color.yellow, 0.7f);
                //var startTime = Time.realtimeSinceStartup;
                _actionTimer = Context.Time.AddDelayTimer(duration, () =>
                {
                    //Log.Debug($"SpineComponent Completed. Entity:{Context.Entity.EntityId} Name:{Context.Entity.Attr.Name} Frame:{Time.frameCount} duration:{duration} start:{startTime} used:{Time.realtimeSinceStartup - startTime}");
                    SetSkeletonFill(Color.white, 0);
                    _actionTimer = null;
                    skeleton.loop = IsLoop(args.fallback);
                    skeleton.AnimationName = args.fallback.ToString();
                    args.onCompleted.SafeInvoke();
                    //try
                    //{
                    //    args.onCompleted?.Invoke();
                    //}
                    //catch (Exception ex)
                    //{
                    //    XGame.Log.Error($"SpineComponent onCompleted Exception Entity:{Context.Entity.EntityId} Name:{Context.Entity.Attr.Name}");
                    //    XGame.Log.Exception(ex);
                    //}
                });
            }
            //state.Complete += (_) =>
            //{
            //    callback?.Invoke();
            //};
        }
        private MaterialPropertyBlock _mpb = new MaterialPropertyBlock();
        /// <summary>
        /// 设置spine的自定义颜色
        /// http://zh.esotericsoftware.com/spine-unity
        /// </summary>
        /// <param name="color"></param>
        /// <param name="phase"></param>
        private void SetSkeletonFill(Color color, float phase)
        {
            var renderer = Context.Skeleton.GetComponent<MeshRenderer>();
            if (renderer.sharedMaterial.shader.name != "Spine/Skeleton Fill")
            { // 该shader可自定义颜色叠加(color overlay)的Unlit 透明着色器. 不写 z-buffer. FillColor 决定叠加颜色, FillPhase 决定叠加强度.
                return;
            }
            //Log.Debug($"SetSkeletonFill color:{color} phase:{phase} Frame:{Time.frameCount}");
            _mpb.SetColor("_FillColor", color); // "_FillColor" is a named property on the used shader.
            _mpb.SetFloat("_FillPhase", phase); // "_FillPhase" is another named property on the used shader.
            renderer.SetPropertyBlock(_mpb);
        }

        void IReset.Reset()
        {
            ClearTimers();
        }
        //private void OnCompleted(TrackEntry trackEntry)
        //{
        //}
    }
}
