using FL.Battle.Vfxs;
using FL.Nodes.GameMain;
using System;
using UnityEngine;
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 ISkillContext
    {
        IEntity Entity { get; }
        Vector3 Position { get; }
        ITimeModule Time { get; }
        SpineComponent Spine { get; }
        VfxComponent Vfx { get; }
        void FindTarget(int skillId);
        void EnqueueSkill(int skillId);
    }
    public class SkillComponent : Component<ISkillContext>, IReset
    {
        public override int Order => 0;

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

        public void SetTarget(IEntityView targetView, IEntity target)
        {
            _targetView = targetView;
            _target = target;
        }
        public void Start(int skillId, Action onCompleted)
        {
            var skill = SkillTableRepo.Get(skillId);
            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(skillId);
                return;
            }
            if (owner.State == EEntityState.Dead)
            {
                Stop();
                onCompleted?.Invoke();
                return;
            }
            var hpValue = _targetView.GetComponent<HpComponent>().CalculateHit(-10);
            var to = _targetView.Position;
            void PushHpAdd()
            {
                var hpAdd = new HpAddDto()
                {
                    position = to,
                    hpValue = hpValue,
                };
                EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, hpAdd);
            }
            void OnSkillVfxFinish()
            {
                if (!string.IsNullOrEmpty(skill.BulletEffect))
                {
                    var bulletCount = skill.BulletArgs.Length > 0 ? skill.BulletArgs[0] : 1;
                    var delay = 0;
                    for(var i = 0; i < bulletCount; i++)
                    {
                        var actMove = ObjectPool.Acquire<VfxActionMove>();
                        actMove.from = Context.Position;
                        actMove.to = to;
                        actMove.duration = 500;
                        var bulletArgs = ObjectPool.Acquire<VfxArgs>();
                        bulletArgs.vfxName = skill.BulletEffect;
                        bulletArgs.delay = delay;
                        bulletArgs.duration = 500;
                        bulletArgs.followType = EVfxFollowType.World;
                        bulletArgs.action = actMove;
                        bulletArgs.onFinish = PushHpAdd;
                        if (!string.IsNullOrEmpty(skill.HitEffect))
                        {
                            var actPosition = ObjectPool.Acquire<VfxActionPosition>();
                            actPosition.position = to;
                            var hitArgs = ObjectPool.Acquire<VfxArgs>();
                            hitArgs.vfxName = skill.HitEffect;
                            hitArgs.duration = skill.HitEffect == "effect_sk_hit_13521" ? 3000 : 2000;
                            hitArgs.followType = EVfxFollowType.World;
                            hitArgs.action = actPosition;
                            bulletArgs.next = hitArgs;
                        }
                        Context.Vfx.Play(bulletArgs);
                        if (bulletCount > 1)
                            delay += skill.BulletArgs[1];
                    }
                }
                else
                {
                    PushHpAdd();
                    if (!string.IsNullOrEmpty(skill.HitEffect))
                    {
                        var actPosition = ObjectPool.Acquire<VfxActionPosition>();
                        actPosition.position = to;
                        var hitArgs = ObjectPool.Acquire<VfxArgs>();
                        hitArgs.vfxName = skill.HitEffect;
                        hitArgs.duration = skill.HitEffect == "effect_sk_hit_13521" ? 3000 : 2000;
                        hitArgs.followType = EVfxFollowType.World;
                        hitArgs.action = actPosition;
                        Context.Vfx.Play(hitArgs);
                    }
                }
            }
            if (!string.IsNullOrEmpty(skill.SkillEffect))
            {
                VfxArgs vfxArgs = ObjectPool.Acquire<VfxArgs>();
                vfxArgs.vfxName = skill.SkillEffect;
                vfxArgs.duration = skill.EndureTime;
                vfxArgs.followType = EVfxFollowType.CastPoint;
                if (skillId == 200705)
                {
                    var actFoword = ObjectPool.Acquire<VfxActionForword>();
                    actFoword.forword = (to - Context.Position).normalized;
                    vfxArgs.action = actFoword;
                }
                vfxArgs.onFinish = OnSkillVfxFinish;
                Context.Vfx.Play(vfxArgs);
            }
            else
            {
                OnSkillVfxFinish();
            }
            //var dto = new SkillEffectDto()
            //{
            //    skillEffect = skill.SkillEffect,
            //    hitEffect = skill.HitEffect,
            //    bulletEffect = skill.BulletEffect,
            //    skillTime = skill.EndureTime,
            //    from = Context.Position,
            //    to = _targetView.Position,
            //    hpAdd = new HpAddDto()
            //    {
            //        position = _targetView.Position,
            //        hpValue = hpValue,
            //    }
            //};
            //EventSingle.Instance.Notify(EventDefine.GameMainMapSkillEffect, dto);
            if (skill.EndureTime > 0)
            {
                if (Context.Entity.EntityType == EEntityType.Partner)
                { //TODO 随从有技能动作
                    Context.Spine.Play(ActionName.skill, () =>
                    {
                        Context.Spine.Play(ActionName.idle/* + UnityEngine.Random.Range(0, 100) % 2*/);
                        OnAttackEnd(skillId);
                        onCompleted?.Invoke();
                    });
                }
                else
                {
                    _skillTimer = Context.Time.AddDelayTimer(skill.EndureTime, () =>
                    {
                        OnAttackEnd(skillId);
                        onCompleted?.Invoke();
                    });
                }

            }
            else
            {
                OnAttackEnd(skillId);
                onCompleted?.Invoke();
            }
        }
        public void Stop()
        {
            _cdAlarm?.Cancel();
            _cdAlarm = null;
            _skillTimer?.Cancel();
            _skillTimer = null;
            _targetView = null;
            _target = null;
        }
        protected override void OnDispose()
        {
            Stop();
        }
        private void OnAttackEnd(int skillId)
        {
            _lastAtkTime = Context.Time.GetNowTime();
            //冷却计时
            var time = _lastAtkTime + SkillTableRepo.Get(skillId).RestTime;
            _cdAlarm = Context.Time.AddAlarm(() =>
            {
                Context.EnqueueSkill(skillId);
            }, time);
        }

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