using Entitas;
using System;
using System.Collections.Generic;
using UnityEngine;
using Game;
/// 
/// 主角的技能连招系统
/// 
public class ComboSystem : IExecuteSystem, IInitializeSystem
{
    public void Initialize()
    {
        EventManager.Instance.AddEvent(EEvent.PlayerInput, OnPlayerAction);
        EventManager.Instance.AddEvent(EEvent.EntityMoveInput, OnEntityMove);
    }
    public void Execute()
    {
        var entity = Util.GetMaster();
        if (Util.IsPause(entity))
        {
            return;
        }
        UpdateComboStance(entity); //更新技能姿态
        UpdateCheckCacheTime(entity); //技能缓存时间检查
        //检查技能取消 可清除buff
        if (UpdateCheckCancel(entity))
        {
            RemoveControl(entity);
        }
        //硬直状态无法释放技能
        if (!Util.EntityIsStagger(entity))
        {
            UpdateComboCast(entity); //技能释放
        }
    }
    private static void RemoveControl(GameEntity entity)
    {
        Util.RemoveControlBuffAll(entity.ID());
        entity.move.IsFlowing = false;
    }
    private static void UpdateComboStance(GameEntity entity)
    {
        var combo = entity.combo;
        var skill = entity.skill;
        var move = entity.move;
        var isGround = entity.move.IsGroundLogic;
        if (combo.Stance == EComboStance.Idle || combo.Stance == EComboStance.AirIdle)
        {
            combo.Stance = isGround ? EComboStance.Idle : EComboStance.AirIdle;
        }
        var hasSkill = skill.IsRunning;
        if (isGround && hasSkill)
        {
            //落地取消
            if (combo.IsGroundCancelable)
            {
                Util.EndSkillTimeline(entity);
            }
        }
    }
    private static void UpdateCheckCacheTime(GameEntity entity)
    {
        var combo = entity.combo;
        var dt = Time.deltaTime;
        var count = combo.InputQueue.Count;
        if (count == 0)
            return;
        foreach (var info in combo.InputQueue)
        {
            info.TimeRecord -= dt * 2;
            if (info.TimeRecord < 0)
            {
                info.Active = false;
            }
        }
        for (int i = count - 1; i >= 0; i--)
        {
            var info = combo.InputQueue[i];
            if (!info.Active)
            {
                combo.InputQueue.RemoveAt(i);
            }
        }
        //取消缓存的保护时间
        var safeTime = combo.TriggerCancelSafeTime;
        if (safeTime > 0)
        {
            safeTime -= dt;
            if (safeTime < 0)
            {
                safeTime = 0;
            }
            combo.TriggerCancelSafeTime = safeTime;
        }
    }
    private static bool UpdateCheckCancel(GameEntity entity)
    {
        var combo = entity.combo;
        var isCancel = false;
        foreach (var info in combo.InputQueue)
        {
            var triggerType = GetSkillTriggerType(info.InputInfo);
            if (Util.HasComboAny(entity, triggerType))
            {
                isCancel = true;
                break;
            }
        }
        if (isCancel)
        {
            //删除取消指令之前的所有指令
            foreach (var info in combo.InputQueue)
            {
                var triggerType = GetSkillTriggerType(info.InputInfo);
                if (Util.HasComboAny(entity, triggerType))
                {
                    break;
                }
                info.Active = false;
            }
        }
        return isCancel;
    }
    private static void UpdateComboCast(GameEntity entity)
    {
        var combo = entity.combo;
        var skill = entity.skill;
        var move = entity.move;
        var hasSkill = skill.IsRunning;
        if (combo.InputQueue.Count == 0)
            return;
        if (!move.IsSkillAble)
            return;
        //成功触发一个 则删除前面的全部
        var isTrigger = false;
        for (int i = 0; i < combo.InputQueue.Count; i++)
        {
            var input = combo.InputQueue[i];
            if (!input.Active)
            {
                continue;
            }
            var stanceNow = combo.Stance;
            var triggerType = GetSkillTriggerType(input.InputInfo);
            if (triggerType == EComboTriggerType.Jump)
            {
                if (hasSkill)
                {
                    //JC
                    if (combo.IsJumpCancelable)
                    {
                        move.IsJumpCommand = true;
                        isTrigger = true;
                        Util.EndSkillTimeline(entity);
                    }
                }
                else
                {
                    //正常跳跃
                    if (combo.Stance == EComboStance.Idle)
                    {
                        entity.move.IsJumpCommand = true;
                        isTrigger = true;
                    }
                }
            }
            else
            {
                var skillCastId = "";
                if (Util.HasComboAny(entity, triggerType))
                {
                    //任意姿态技能
                    if (!hasSkill || combo.IsSkillCancelable)
                    {
                        skillCastId = Util.GetComboAny(entity, triggerType);
                    }
                }
                else
                {
                    //指定姿态技能
                    var skillKey = new Tuple(stanceNow, triggerType);
                    if (Util.HasCombo(entity, skillKey))
                    {
                        skillCastId = Util.GetCombo(entity, skillKey);
                    }
                }
                if (!string.IsNullOrEmpty(skillCastId))
                {
                    ComboCast(entity, skillCastId);
                    isTrigger = true;
                }
            }
            if (isTrigger)
            {
                //成功触发技能,对指令队列进行更新
                if (isTrigger)
                {
                    for (int j = 0; j < combo.InputQueue.Count; j++)
                    {
                        var info = combo.InputQueue[j];
                        if (j < i)
                        {
                            //触发指令之前的指令全部失效,保护时间内不处理
                            if (combo.TriggerCancelSafeTime == 0)
                            {
                                info.Active = false;
                            }
                        }
                        else if (j == i)
                        {
                            //触发的指令失效
                            info.Active = false;
                        }
                        else
                        {
                            break;
                        }
                    }
                    //更新combo最后触发时间
                    combo.TriggerCancelSafeTime = GameConst.InputRecordTriggerCancelSafeTime;
                }
                break;
            }
        }
    }
    private static void ComboCast(GameEntity entity, string skillCastId)
    {
        var combo = entity.combo;
        var skill = entity.skill;
        var skillCfg = Util.GetSkillMasterConfig(skillCastId);
        var skillCfgCombo = skillCfg.SkillCombo;
        combo.PreStance = (EComboStance)skillCfgCombo.StanceEnd;
        // combo.stance = skillCfg.StanceCache ? combo.stance : EComboStance.None;
        // TODO step系统做法待定
        combo.Stance = EComboStance.None;
        var castDir = GetSkillCastDir(entity, skillCfgCombo.FreeLock);
        Util.CastSkill(entity, skillCastId, skillCfg.Skill.Timeline, castDir);
    }
    private static Vector3 GetSkillCastDir(GameEntity entity, bool isFreeLock)
    {
        var combo = entity.combo;
        var move = entity.move;
        var castDir = Vector3.zero;
        if (!isFreeLock && combo.TargetLock > 0)
        {
            var target = Util.GetEntity(combo.TargetLock);
            castDir = (target.move.Position - move.Position).normalized;
        }
        else
        {
            Vector3 moveDir;
            if (GameConst.MoveCommand2Dir.TryGetValue(combo.MoveCommand, out moveDir))
            {
                castDir = moveDir;
            }
        }
        if (castDir.x == 0 && castDir.z == 0)
        {
            castDir = move.IsRight ? Vector3.right : Vector3.left;
        }
        return castDir;
    }
    private static void OnEntityMove(PEntityMoveInput param)
    {
        var master = Util.GetMaster();
        master.combo.MoveCommand = param.Command;
    }
    private static void OnPlayerAction(PPlayerInput info)
    {
        var master = Util.GetMaster();
        var pressSet = master.combo.KeyPressSet;
        if (info.Action == EKeyActionType.Press)
        {
            pressSet.Add(info.Key);
        }
        else if (info.Action == EKeyActionType.Release)
        {
            if (pressSet.Contains(info.Key))
            {
                pressSet.Remove(info.Key);
            }
        }
        if (!Util.IsControl())
        {
            //处于Combo系统不接收输入的状态
            return;
        }
        var weaponChangeType = GetEWeaponChangeType(info);
        if (weaponChangeType != EWeaponChangeType.None)
        {
            //武器更换
            ChangeWeapon(weaponChangeType);
            return;
        }
        if (GetSkillTriggerType(info) != EComboTriggerType.None)
        {
            //技能指令输入
            master.combo.InputQueue.Add(new ComboInputRecord()
            {
                InputInfo = info,
                TimeRecord = GameConst.InputRecordTime,
                Active = true,
            });
            return;
        }
    }
    private static void ChangeWeapon(EWeaponChangeType changeType)
    {
        var master = Util.GetMaster();
        var combo = master.combo;
        var weaponNum = combo.WeaponList.Count;
        var weaponNow = combo.WeaponNow;
        var weaponNew = weaponNow.Value;
        switch (changeType)
        {
            case EWeaponChangeType.None:
                break;
            case EWeaponChangeType.SetNext:
                weaponNew = weaponNow.Value + 1;
                break;
            case EWeaponChangeType.SetPre:
                weaponNew = weaponNow.Value - 1;
                break;
            default:
                weaponNew = (int)changeType;
                break;
        }
        weaponNow.Value = (weaponNew + weaponNum) % weaponNum;
        //切换武器时重置姿态
        // combo.stance = EComboStance.Idle;
        // combo.preStance = EComboStance.Idle;
    }
    private static EComboTriggerType GetSkillTriggerType(PPlayerInput info)
    {
        if (info.Action == EKeyActionType.Press)
        {
            if (info.Key == EFunctionKey.LightAttack)
            {
                return EComboTriggerType.LightAttack;
            }
            if (info.Key == EFunctionKey.HeavyAttack)
            {
                return EComboTriggerType.HeavyAttack;
            }
            if (info.Key == EFunctionKey.Flash)
            {
                return EComboTriggerType.Flash;
            }
            if (info.Key == EFunctionKey.Jump)
            {
                return EComboTriggerType.Jump;
            }
        }
        if (info.Action == EKeyActionType.Release)
        {
            if (info.Key == EFunctionKey.LightAttack)
            {
                return EComboTriggerType.LightAttackRelease;
            }
            if (info.Key == EFunctionKey.HeavyAttack)
            {
                return EComboTriggerType.HeavyAttackRelease;
            }
        }
        return EComboTriggerType.None;
    }
    private static EWeaponChangeType GetEWeaponChangeType(PPlayerInput info)
    {
        var ret = EWeaponChangeType.None;
        if (info.Action != EKeyActionType.Press)
        {
            return ret;
        }
        switch (info.Key)
        {
            case EFunctionKey.WeaponPre:
                ret = EWeaponChangeType.SetPre;
                break;
            case EFunctionKey.WeaponNext:
                ret = EWeaponChangeType.SetNext;
                break;
            case EFunctionKey.Weapon0:
                ret = EWeaponChangeType.Set0;
                break;
            case EFunctionKey.Weapon1:
                ret = EWeaponChangeType.Set1;
                break;
            case EFunctionKey.Weapon2:
                ret = EWeaponChangeType.Set2;
                break;
            case EFunctionKey.Weapon3:
                ret = EWeaponChangeType.Set3;
                break;
        }
        return ret;
    }
}