using DG.Tweening;
using FL.Battle.Vfxs;
using FL.Nodes.GameMain;
using System;
using UnityEngine;
using XGame;
using XGame.Database;
using XGame.Framework;
using XGame.Framework.Components;
using XGame.Framework.Interfaces;
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; }
        VfxComponent Vfx { get; }
        void FindTarget(int skillId);
        void EnqueueSkill(int skillId);
    }
    /// <summary>
    /// 普通攻击
    /// </summary>
    public class AttackComponent : Component<IAttackContext>, IReset
    {
        public override int Order => 0;

        private IEntityView _targetView;
        private IEntity _target;
        private IAlarm _cdAlarm;
        private long _lastAtkTime;

        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.SafeInvoke();
                Context.FindTarget(0);
                return;
            }
            if (owner.State == EEntityState.Dead)
            {
                Stop();
                onCompleted.SafeInvoke();
                return;
            }
            if (Context.Entity.EntityType != EEntityType.Partner)
            { // 玩家或者怪物
                PlaySkillAtk(onCompleted);
                //Context.Spine.Play(ActionName.attack, () =>
                //{
                //    OnHitFrame();
                //    OnAttackEnd();
                //    Context.Spine.Play(ActionName.idle);
                //    onCompleted?.Invoke();
                //});
                return;
            }
            // 随从
            PartnerType partnerType = (PartnerType)((Context.Entity.TableId / 100) % 10);
            //单手剑、双手剑、法杖使用法术类型攻击
            var isSkill = partnerType == PartnerType.Sword || partnerType == PartnerType.SwordTH || partnerType == PartnerType.Staff;
            if (isSkill)
            {
                PlaySkillAtk(onCompleted);
            }
            else
            {
                if (partnerType == PartnerType.Axe)
                {
                    Log.Debug($"Axe Attack. Frame:{UnityEngine.Time.frameCount}");
                }
                PartnerNormalAtk(onCompleted);
            }
        }

        private void PlaySkillAtk(Action onCompleted)
        {
            Context.Spine.Play(ActionName.attack, () =>
            {
                Context.Spine.Play(ActionName.idle/* + UnityEngine.Random.Range(0, 100) % 2*/);
                if (_target == null || _target.State == EEntityState.Dead)
                {
                    OnAttackEnd();
                    onCompleted.SafeInvoke();
                    return;
                }
                var hpValue = _targetView.GetComponent<HpComponent>().CalculateHit(-Context.Entity.Attr.Attack);
                var to = _targetView.Position;
                void PushHpAdd()
                {
                    var hpAdd = new HpAddDto()
                    {
                        position = to,
                        hpValue = hpValue,
                    };
                    EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, hpAdd);
                }
                var actMove = ObjectPool.Acquire<VfxActionMove>();
                actMove.from = Context.Position;
                actMove.to = to;
                actMove.duration = 500;
                var bulletArgs = ObjectPool.Acquire<VfxArgs>();
                bulletArgs.vfxName = Context.Entity.EntityType == EEntityType.Partner ? "effect_atk_bullet_20181" : "atk_007";
                bulletArgs.duration = 500;
                bulletArgs.followType = EVfxFollowType.World;
                bulletArgs.action = actMove;
                bulletArgs.onFinish = PushHpAdd;

                var actPosition = ObjectPool.Acquire<VfxActionPosition>();
                actPosition.position = to;
                var hitArgs = ObjectPool.Acquire<VfxArgs>();
                hitArgs.vfxName = Context.Entity.EntityType == EEntityType.Partner ? "effect_atk_hit_20181" : "hit_007";
                hitArgs.duration = 2000;
                hitArgs.followType = EVfxFollowType.World;
                hitArgs.action = actPosition;
                bulletArgs.next = hitArgs;
                Context.Vfx.Play(bulletArgs);
                //var dto = new SkillEffectDto()
                //{
                //    skillEffect = "",
                //    skillTime = 667,
                //    from = Context.Position,
                //    to = _targetView.Position,
                //    hpAdd = new HpAddDto()
                //    {
                //        position = _targetView.Position,
                //        hpValue = hpValue,
                //    }
                //};
                //if (Context.Entity.EntityType == EEntityType.Partner)
                //{
                //    dto.hitEffect = "effect_atk_hit_20181";
                //    dto.bulletEffect = "effect_atk_bullet_20181";
                //}
                //else
                //{
                //    dto.hitEffect = "hit_007";
                //    dto.bulletEffect = "atk_007";
                //}
                //EventSingle.Instance.Notify(EventDefine.GameMainMapSkillEffect, dto);

                OnAttackEnd();
                onCompleted.SafeInvoke();
            });
        }
        private void PartnerNormalAtk(Action onCompleted)
        {
            var from = Context.Position;
            var to = _targetView.Position;
            var distance = Vector3.Distance(from, to);
            var atkRange = 0;// _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 = 0.3f;// Mathf.Abs(moveDis) / 5;
                //Context.ActionRoot.localPosition = atkPosition;
                //Context.Spine.Play(ActionName.attack, () =>
                //{
                //    Context.Spine.Play(ActionName.idle/* + UnityEngine.Random.Range(0, 100) % 2*/);
                //    Context.ActionRoot.localPosition = Vector3.zero;
                //    var endArgs = ObjectPool.Acquire<VfxArgs>();
                //    endArgs.vfxName = "effect_melee_appear";
                //    endArgs.duration = 500;
                //    Context.Vfx.Play(endArgs);

                //    OnHitFrame();
                //    OnAttackEnd();
                //    onCompleted?.Invoke();
                //});
                var startArgs = ObjectPool.Acquire<VfxArgs>();
                startArgs.vfxName = "effect_trail";
                startArgs.duration = 300;
                startArgs.followType= EVfxFollowType.CastPoint;
                Context.Vfx.Play(startArgs);
                MoveTo(atkPosition, moveTime, 0, () =>
                {
                    OnHitFrame();
                    //等待拖尾消失
                    MoveTo(Vector3.zero, moveTime, 0.2f, () =>
                    {
                        OnAttackEnd();
                        onCompleted?.Invoke();
                    });
                });
            }
            else
            {
                OnHitFrame();
                OnAttackEnd();
                onCompleted?.Invoke();
            }
        }
        public void Stop()
        {
            Context.ActionRoot.DOKill();
            Context.ActionRoot.localPosition = Vector3.zero;
            _cdAlarm?.Cancel();
            _cdAlarm = null;
            _targetView = null;
            _target = null;
        }
        protected override void OnDispose()
        {
            Stop();
        }
        private void MoveTo(Vector3 to, float duration, float delay, Action callback)
        {
            var tween = Context.ActionRoot.DOLocalMove(to, duration);
            if (delay > 0)
            {
                tween.SetDelay(delay);
            }
            tween.onComplete = () =>
            {
                callback.SafeInvoke();
            };
        }
        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()
        {
            _lastAtkTime = Context.Time.GetNowTime();
            //冷却计时
            var time = _lastAtkTime + Context.Entity.Attr.AttackCD;
            _cdAlarm = Context.Time.AddAlarm(() =>
            {
                Context.EnqueueSkill(0);
            }, time);
        }

        void IReset.Reset()
        {
            Stop();
        }
    }
}
