using DG.Tweening;
using FL.Nodes.GameMain;
using System;
using UnityEngine;
using XGame.Framework;
using XGame.Framework.Components;
using XGame.Framework.Map;
using XGame.Framework.Time;

namespace FL.Battle
{
    public interface IAttackContext
    {
        IEntity Entity { get; }
        Transform ActionRoot { get; }
        Vector3 Position { get; }
        ITimeModule Time { get; }
        SpineComponent Spine { get; }
        /// <summary>
        /// 是否有攻击动作
        /// 先简单做个标记，有标记的做个简单的动作
        /// </summary>
        public bool IsPartnerAtk {  get; }
        void FindTarget(int skillId);
        void EnqueueSkill(int skillId);
    }
    /// <summary>
    /// 普通攻击
    /// </summary>
    public class AttackComponent : Component<IAttackContext>
    {
        public override int Order => 0;

        private IEntityView _targetView;
        private IEntity _target;
        private IAlarm _cdAlarm;
        private long _lastAtkTime;
        public bool IsPlaying { get; private set; }

        public void SetTarget(IEntityView targetView, IEntity target)
        {
            _targetView = targetView;
            _target = target;
        }
        public void Start(Action onCompleted)
        {
            var owner = Context.Entity;
            //if (_target == null)
            //{
            //    Log.Error($"OnStartAttack Error: Target is null. TableId:{Context.Owner.TableId} State:{Context.Owner.State}");
            //    return;
            //}
            if (_target == null || _target.State == EEntityState.Dead)
            {
                Stop();
                onCompleted?.Invoke();
                Context.FindTarget(0);
                return;
            }
            if (owner.State == EEntityState.Dead)
            {
                Stop();
                onCompleted?.Invoke();
                return;
            }
            IsPlaying = true;
            if (!Context.IsPartnerAtk)
            {
                Context.Spine.Play(ActionName.attack, () =>
                {
                    OnHitFrame();
                    OnAttackEnd();
                    Context.Spine.Play(ActionName.idle);
                    onCompleted?.Invoke();
                });
                return;
            }
            var from = Context.Position;
            var to = _targetView.Position;
            var distance = Vector3.Distance(from, to);
            var atkRange = _target.Attr.Radius;
            if (distance > atkRange)
            { // 大于攻击距离
                //Log.Info($"PlayAttack:Owner:{Handle.Owner.EntityId} Target:{_target.EntityId}");
                var dir = (to - from).normalized;
                var moveDis = distance - atkRange;
                var atkPosition = Context.ActionRoot.localPosition + dir * moveDis;
                var moveTime = Mathf.Abs(moveDis) / 5;

                MoveTo(atkPosition, moveTime, () =>
                {
                    OnHitFrame();
                    //moveback
                    MoveTo(Vector3.zero, moveTime, () =>
                    {
                        OnAttackEnd();
                        onCompleted?.Invoke();
                    });
                });
            }
            else
            {
                OnHitFrame();
                OnAttackEnd();
                onCompleted?.Invoke();
            }
        }
        public void Stop()
        {
            Context.ActionRoot.DOKill();
            _cdAlarm?.Cancel();
            _cdAlarm = null;
            _targetView = null;
            _target = null;
            IsPlaying = false;
        }
        protected override void OnDispose()
        {
            Stop();
        }
        private void MoveTo(Vector3 to, float duration, Action callback)
        {
            var tween = Context.ActionRoot.DOLocalMove(to, duration);
            tween.onComplete = () =>
            {
                callback?.Invoke();
            };
        }
        private void OnHitFrame()
        { // 攻击帧回调
            //TODO 目标受击
            if (_target == null || _target.State == EEntityState.Dead)
                return;
            var position = _targetView.Position;
            var hpValue = _targetView.GetComponent<HpComponent>().CalculateHit(-Context.Entity.Attr.Attack);
            EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, new HpAddDto()
            {
                position = position,
                hpValue = hpValue
            });
        }
        private void OnAttackEnd()
        {
            IsPlaying = false;
            _lastAtkTime = Context.Time.GetNowTime();
            //冷却计时
            var time = _lastAtkTime + Context.Entity.Attr.AttackCD;
            _cdAlarm = Context.Time.AddAlarm(() =>
            {
                Context.EnqueueSkill(0);
            }, time);
        }
    }
}
