using System;
using System.Collections.Generic;

using System.Text;
using UnityEngine;

using Thousandto.Cfg.Data;
using Thousandto.Code.Logic.LocalPlayerBT;
using Thousandto.Core.Asset;
using Thousandto.Core.Base;
using Thousandto.Code.Center;
using Thousandto.Code.Global;
using Thousandto.Plugins.Common.UniScene;
#pragma warning disable 0219
#pragma warning disable 0168
#pragma warning disable 0162
namespace Thousandto.Code.Logic
{
    /// <summary>
    /// 战斗的一些通用函数
    /// </summary>
    public static class CombatUtil
    {
        //查询目标时的缓存信息
        private static List<SearchTargetInfo> _searchCache = new List<SearchTargetInfo>(32);
        private static List<SearchCollectionInfo> _searchCollectCache = new List<SearchCollectionInfo>(32);

        //用于排序的比较函数
        private static Comparison<SearchTargetInfo> compareFunc;
        private static Comparison<SearchTargetInfo> compareAngleFunc;
        private static Comparison<SearchCollectionInfo> compareCollectFunc;

        //静态构造函数
        static CombatUtil()
        {
            compareFunc = (left, right) =>
            {
                return left.distanceSq.CompareTo(right.distanceSq);
            };

            compareAngleFunc = (left, right) =>
            {
                return left.angle.CompareTo(right.angle);
            };

            compareCollectFunc = (left, right) =>
            {
                return left.distanceSq.CompareTo(right.distanceSq);
            };

        }

        public static SkillHitType ConvertToHitType(int serverData)
        {
            if (IsBeatHit(serverData))
            {
                return SkillHitType.HitStiff;
            }
            else if (IsBeatBack(serverData))
            {
                return SkillHitType.HitBack;
            }
            else if (IsBeatFly(serverData))
            {
                return SkillHitType.HitFly;
            }
            else if (IsBeatGrap(serverData))
            {
                return SkillHitType.HitGrab;
            }
            return SkillHitType.None;
        }
        //受击僵直
        public static bool IsBeatHit(int type)
        {
            if ((type & (int)SkillEffectType.AttackHit) != 0)
                return true;
            return false;
        }
        //击退
        public static bool IsBeatBack(int type)
        {
            if ((type & (int)SkillEffectType.AttackBack) != 0)
                return true;
            return false;
        }
        //击飞
        public static bool IsBeatFly(int type)
        {
            if ((type & (int)SkillEffectType.AttackFly) != 0)
                return true;
            return false;
        }
        //抓取
        public static bool IsBeatGrap(int type)
        {
            if ((type & (int)SkillEffectType.AttackGrab) != 0)
                return true;
            return false;
        }
        //暴击
        public static bool IsCrit(int type)
        {
            if ((type & (uint)SkillEffectType.Crit) != 0)
                return true;
            return false;
        }
        //会心
        public static bool IsHuiXin(int type)
        {
            if ((type & (uint)SkillEffectType.HuiXin) != 0)
                return true;
            return false;
        }
        //致命一击
        public static bool IsZhuiJi(int type)
        {
            if ((type & (uint)SkillEffectType.ZhuiJi) != 0)
                return true;
            return false;
        }
        //幸运一击
        public static bool IsLianJi(int type)
        {
            if ((type & (uint)SkillEffectType.LianJi) != 0)
                return true;
            return false;
        }
        //无敌
        public static bool IsInvincible(int type)
        {
            if ((type & (uint)SkillEffectType.Invincible) != 0)
                return true;
            return false;
        }
        //免疫
        public static bool IsImmune(int type)
        {
            if ((type & (uint)SkillEffectType.Immune) != 0)
                return true;
            return false;
        }
        //是否是多倍攻击
        public static bool IsMultipleAtk(int type)
        {
            if ((type & (uint)SkillEffectType.MultipleAtk) != 0)
                return true;
            return false;
        }

        //获取技能寻路距离
        public static float GetSkillFindPathDis(SkillVisualInfo skill)
        {
            if (skill == null)
                return 0f;
            if (skill.UseNeedDis <= 1.5f)
            {
                return skill.UseNeedDis * 0.8f;
            }
            else
            {
                return skill.UseNeedDis - 1.5f;
            }
        }

        //是否可以选择玩家
        public static bool CanShowRPhead(LocalPlayer user, RemotePlayer rp)
        {
            if (rp == null || user == null)
                return false;
            if (GameCenter.LuaSystem.Adaptor.IsTeamMember(rp.ID))
            {
                return true;
            }
            //判断地图是否能够PK
            if (user.Scene.Cfg != null && user.Scene.Cfg.PkState == 0)
            {
                return true;
            }
            //判断是否在仇恨列表
            if (user.IsStrikeBack(rp.ID))
            {
                return false;
            }
            //var pkDefine = PkValueConstDefine.GetPkDefine(rp.PropMoudle.PkValue);
            //if (pkDefine != null && pkDefine.CanBeAttack)   //PK值高到可以被主动攻击
            //{
            //    return false;
            //}
            if (CheckPKModel(user, rp))
            {
                return false;
            }
            return true;
        }

        //判断两个阵营之间是否可以攻击
        public static bool MonsterSceneCampIsEnemy(int camp1, int camp2, int type)
        {
            switch (type)
            {
                case 1:
                    if (camp2 >= 1 && camp2 <= 16)
                    {
                        return (camp1 >> (camp2 - 1) & 1) == 0;
                    }
                    break;
            }
            return camp1 != camp2;
        }
        //判断两个阵营之间是否可以攻击
        public static bool PlayerSceneCampIsEnemy(int camp1, int camp2, int type)
        {
            switch (type)
            {
                case 1:
                    return (camp1 >> 16) != (camp2 >> 16);
            }
            return camp1 != camp2;
        }

        //是否是技能的目标
        public static bool CanAttackTarget(LocalPlayer user, Character c, bool checkBlock)
        {
            bool result = false;
            do
            {
                if (c == null || c.IsDead() || c.InSafeTile)
                {
                    result = false;
                    break;
                }

                //宠物不能被攻击
                if (c is Pet)
                {
                    result = false;
                    break;
                }

                if (c is Monster)
                {
                    //判断怪物阵营
                    result = MonsterSceneCampIsEnemy(user.PropMoudle.SceneCampID, c.PropMoudle.SceneCampID, user.Scene.Cfg.SceneCameMatchType);
                    break;
                }

                if (c is RemotePlayer)
                {
                    RemotePlayer rp = c as RemotePlayer;
                    if (GameCenter.LuaSystem.Adaptor.IsTeamMember(rp.ID))
                    {
                        result = false;
                        break;
                    }

                    //判断地图是否能够PK
                    if (user.Scene.Cfg != null && user.Scene.Cfg.PkState == 0)
                    {
                        result = false;
                        break;
                    }

                    //判断是否在仇恨列表
                    if (user.IsStrikeBack(rp.ID))
                    {
                        // 通过PK模式判断不能攻击的话,如果没有开启自动反击,那么就直接设置为false;
                        result = CheckPKModel(user, rp);
                        if (!result && GameCenter.GameSetting.GetSetting(GameSettingKeyCode.MandateAutoStrikeBack) <= 0)
                        {
                            result = false;
                        }
                        else
                        {
                            result = true;
                            break;
                        }
                    }

                    //最后检查PK模式
                    result = CheckPKModel(user, rp);
                }

            } while (false);

            if (result && c is RemotePlayer)
            {
                var rp = c as RemotePlayer;
                //检查变身状态
                if (user.IsChangeModel)
                {
                    //主角在变身状态
                    if (rp.IsChangeModel)
                    {
                        //其他玩家在变身状态
                        result = user.ChangeModelCfg.IsAttChange != 0 && rp.ChangeModelCfg.IsChangeAtt != 0;
                    }
                    else
                    {
                        //其他玩家不在变身状态
                        result = user.ChangeModelCfg.IsAttRole != 0;
                    }
                }
                else
                {
                    //主角不在变身状态
                    if (rp.IsChangeModel)
                    {
                        //其他玩家在变身状态
                        result = rp.ChangeModelCfg.IsRoleAtt != 0;
                    }
                }
            }

            //检测阻挡,只有攻击其他玩家会检测阻挡,防止怪物穿墙打不到
            if (checkBlock && result && c is RemotePlayer)
            {
                //判断攻击路径上是否有阻挡
                var start = user.Position2d;
                var end = c.Position2d;

                var dis = Vector2.Distance(end, start);
                var whileCount = (int)(dis / user.Scene.navigator.CellSize + 1);

                var tmpPos = Vector2.zero;
                var lerpValue = 0f;
                for (int i = 0; i <= whileCount; ++i)
                {
                    lerpValue = i / (float)whileCount;
                    tmpPos = Vector2.Lerp(start, end, lerpValue);
                    if (user.Scene.navigator.IsBlocked(tmpPos))
                    {
                        result = false;
                        break;
                    }
                }
            }
            return result;
        }

        //通过PK模式来判断是否攻击
        public static bool CheckPKModel(LocalPlayer user, RemotePlayer rp)
        {
            bool result = false;
            //判断PK模式
            switch (user.PropMoudle.PkModel)
            {
                //和平攻击模式,不能攻击
                case PKMode.PeaceMode:
                    result = false;
                    break;
                //全体攻击模式,可以攻击队友以外的 , 这里没有判断是否是队友,是因为如果是队友肯定不能被攻击,这个在攻击判断的最前面已经做了判断.IsTeamMember()
                case PKMode.AllMode:
                    result = true;
                    break;
                //本服模式
                case PKMode.SelfServer:
                    result = user.PropMoudle.ServerID != rp.PropMoudle.ServerID;
                    break;
                //场景阵营模式,可以攻击对立场景阵营的玩家
                case PKMode.SceneCampMode:
                    result = PlayerSceneCampIsEnemy(user.PropMoudle.SceneCampID, rp.PropMoudle.SceneCampID, user.Scene.Cfg.SceneCameMatchType);
                    break;
                // 公会:玩家可以攻击除公会外的其他玩家
                case PKMode.GuildMode:
                    if (user.GuildID <= 0)
                    {
                        result = true;
                    }
                    else
                    {
                        result = user.GuildID != rp.GuildID;
                    }
                    break;
            }
            return result;
        }

        //查找技能目标,根据技能方向来决定选择哪些目标
        public static List<Character> MatchSkillTarget(LocalPlayer user, Vector2 userPos, Vector2 userDir, FindTargetInfo findInfo)
        {
            var scene = GameCenter.GameSceneSystem.GetActivedScene();
            if (scene == null)
            {
                return null;
            }

            userDir = userDir.normalized;
            _searchCache.Clear();
            var selectTarget = user.GetCurSelectedTarget();
            switch (findInfo.AreaType)
            {
                case SkillTargetArea.Rectangle:   //矩形
                    {
                        float width = findInfo.RectWidth + 0.2f;
                        float height = findInfo.RectHeight + 0.2f;

                        List<Character> toBeSelectList = scene.FindAll<Character>();
                        if (toBeSelectList == null || toBeSelectList.Count <= 0)
                            return null;
                        var skillAreaShape = new Math2d.Obb(userPos, userDir, width / 2, height, 0);

                        for (int i = 0; i < toBeSelectList.Count; ++i)
                        {
                            var c = toBeSelectList[i];
                            var tarCircle = new Math2d.Circle(c.Position2d, c.PropMoudle.LogicBodyRadius);
                            if (Math2d.CollisionTest(skillAreaShape, tarCircle))
                            {
                                if (CanAttackTarget(user, c, true))
                                {
                                    float disSq = (selectTarget == c) ? 0f : (userPos - c.Position2d).sqrMagnitude;
                                    _searchCache.Add(new SearchTargetInfo(c, disSq));
                                }
                            }
                        }
                    }
                    break;

                case SkillTargetArea.FanShaped:  //扇形
                    {
                        int angle = (int)findInfo.SectorAngle;
                        float radius = findInfo.SectorRadius + 0.2f;

                        List<Character> toBeSelectList = scene.FindAll<Character>();
                        if (toBeSelectList == null || toBeSelectList.Count <= 0)
                            return null;

                        var skillAreaShape = new Math2d.Sector(userPos, radius, userDir, angle * Mathf.Deg2Rad * 0.5f);
                        for (int i = 0; i < toBeSelectList.Count; ++i)
                        {
                            var c = toBeSelectList[i];
                            var tarCircle = new Math2d.Circle(c.Position2d, c.PropMoudle.LogicBodyRadius);
                            if (Math2d.CollisionTest(ref skillAreaShape, ref tarCircle))
                            {
                                if (CanAttackTarget(user, c, true))
                                {
                                    float disSq = (selectTarget == c) ? 0f : (userPos - c.Position2d).sqrMagnitude;
                                    _searchCache.Add(new SearchTargetInfo(c, disSq));
                                }
                            }
                        }
                    }
                    break;

                case SkillTargetArea.Round:      //圆形
                    {
                        float radius = findInfo.RoundRadius + 0.2f;

                        List<Character> toBeSelectList = scene.FindAll<Character>();
                        if (toBeSelectList == null || toBeSelectList.Count <= 0)
                            return null;

                        var skillCircle = new Math2d.Circle(userPos, radius + user.PropMoudle.LogicBodyRadius);
                        for (int i = 0; i < toBeSelectList.Count; ++i)
                        {
                            var c = toBeSelectList[i];
                            var tarCircle = new Math2d.Circle(c.Position2d, c.PropMoudle.LogicBodyRadius);
                            if (Math2d.CollisionTest(ref skillCircle, ref tarCircle))
                            {
                                if (CanAttackTarget(user, c, true))
                                {
                                    float disSq = (selectTarget == c) ? 0f : (userPos - c.Position2d).sqrMagnitude;
                                    _searchCache.Add(new SearchTargetInfo(c, disSq));
                                }
                            }
                        }
                    }
                    break;
            }

            if (_searchCache.Count > 0)
            {
                _searchCache.Sort(compareFunc);


                List<Character> result = new List<Character>();
                for (int i = 0; result.Count < findInfo.MaxTargetCount && i < _searchCache.Count; ++i)
                {
                    if (!result.Contains(_searchCache[i].target))
                    {
                        result.Add(_searchCache[i].target);
                    }
                }
                _searchCache.Clear();
                return result;
            }
            return null;
        }

        public static Character FindSkillMainTarget(LocalPlayer user, Vector2 findDir, float dis)
        {
            List<Character> toBeSelectList = GameCenter.GameSceneSystem.ActivedScene.FindAll<Character>();
            _searchCache.Clear();
            List<SearchTargetInfo> playerCache = new List<SearchTargetInfo>(32);
            for (int i = 0; i < toBeSelectList.Count && _searchCache.Count < 32; ++i)
            {
                Character c = toBeSelectList[i];
                if (CanAttackTarget(user, c, false) && c.CanBeSelect && CheckDistanceValid(user, c, dis))
                {
                    var serachInfo = new SearchTargetInfo(c, user.GetSqrDistance2d(c.Position2d), (int)Vector2.Angle(findDir.normalized, (c.Position2d - user.Position2d).normalized));
                    _searchCache.Add(serachInfo);
                    if (c is RemotePlayer)
                    {
                        playerCache.Add(serachInfo);
                    }
                }
            }
            if (playerCache.Count > 0)
            {
                playerCache.Sort(compareAngleFunc);

                return playerCache[0].target;
            }
            if (_searchCache.Count > 0)
            {
                _searchCache.Sort(compareAngleFunc);
                return _searchCache[0].target;
            }
            return null;
        }

        public static Character FindCanAtkRecentlyTarget(LocalPlayer user)
        {
            List<Character> toBeSelectList = GameCenter.GameSceneSystem.ActivedScene.FindAll<Character>();
            _searchCache.Clear();
            for (int i = 0; i < toBeSelectList.Count && _searchCache.Count < 32; ++i)
            {
                Character c = toBeSelectList[i];
                if (CanAttackTarget(user, c, false) && c.CanBeSelect)
                {
                    float disSq = user.GetSqrDistance2d(c.Position2d);
                    _searchCache.Add(new SearchTargetInfo(c, disSq));
                }
            }

            if (_searchCache.Count > 0)
            {
                _searchCache.Sort(compareFunc);
                return _searchCache[0].target;
            }

            return null;
        }


        //查找挂机攻击目标
        public static Character FindMandateTarget(LocalPlayer user, int targetID)
        {
            if (GameCenter.GameSceneSystem.ActivedScene == null)
            {
                return null;
            }
            if (targetID != 0)
            {

                List<Monster> toBeSelectList = GameCenter.GameSceneSystem.ActivedScene.FindAll<Monster>();
                _searchCache.Clear();
                for (int i = 0; i < toBeSelectList.Count && _searchCache.Count < 64; ++i)
                {
                    Monster c = toBeSelectList[i];
                    if (c.PropMoudle.CfgID == targetID && CanAttackTarget(user, c, false) && c.CanBeSelect)
                    {
                        float disSq = user.GetSqrDistance2d(c.Position2d);
                        _searchCache.Add(new SearchTargetInfo(c, disSq));
                    }
                }

                if (_searchCache.Count > 0)
                {
                    _searchCache.Sort(compareFunc);
                    return _searchCache[0].target;
                }
            }
            else
            {
                List<Character> toBeSelectList = GameCenter.GameSceneSystem.ActivedScene.FindAll<Character>();
                _searchCache.Clear();
                for (int i = 0; i < toBeSelectList.Count && _searchCache.Count < 64; ++i)
                {
                    Character c = toBeSelectList[i];
                    if (CanAttackTarget(user, c, false) && c.CanBeSelect)
                    {
                        float disSq = user.GetSqrDistance2d(c.Position2d);
                        var serchInfo = new SearchTargetInfo(c, disSq);
                        _searchCache.Add(serchInfo);
                    }
                }

                if (_searchCache.Count > 0)
                {
                    _searchCache.Sort(compareFunc);
                    return _searchCache[0].target;
                }
            }
            return null;
        }

        public static Collection FindCollectTarget(LocalPlayer user, int collectID)
        {
            List<Collection> toBeSelectList = GameCenter.GameSceneSystem.ActivedScene.FindAll<Collection>();
            _searchCollectCache.Clear();
            for (int i = 0; i < toBeSelectList.Count; ++i)
            {
                Collection c = toBeSelectList[i];
                if (c.PropMoudle.CfgID == collectID)
                {
                    float disSq = user.GetSqrDistance2d(c.Position2d);
                    _searchCollectCache.Add(new SearchCollectionInfo(c, disSq));
                }
            }

            if (_searchCollectCache.Count > 0)
            {
                _searchCollectCache.Sort(compareCollectFunc);
            }
            return _searchCollectCache.Count > 0 ? _searchCollectCache[0].target : null;
        }

        public static bool CheckDistanceValid(Character user, Character target, float length)
        {
            bool result = false;
            if (user != null && target != null && user.ModelTransform != null && target.ModelTransform != null)
            {
                var distance = (user.GetDistance2d(target.Position2d)) - target.PropMoudle.LogicBodyRadius / 2f;
                if (distance <= 0f)
                    return true;
                Vector2 hitPos;
                if (distance <= length)
                {
                    result = true;
                }
            }

            return result;
        }

        public static bool CheckMandeteDistanceValid(Character user, Character target, float length)
        {
            if (length > 6)
            {
                length = 6;
            }
            bool result = false;
            if (user != null && target != null && user.ModelTransform != null && target.ModelTransform != null)
            {
                var distance = (user.GetDistance2d(target.Position2d));// - target.PropMoudle.LogicBodyRadius / 2f;
                if (distance <= 0f)
                    return true;
                Vector2 hitPos;
                if (distance < length)
                {
                    result = true;
                }
            }

            return result;
        }

        //是否是技能的目标
        public static bool CanShowWarningFiled(LocalPlayer user, Character target)
        {
            if (user == null)
                return false;
            if (target == null || target.IsDead())
            {
                return false;
            }
            if (target is Monster)
            {
                //判断怪物阵营
                return MonsterSceneCampIsEnemy(user.PropMoudle.SceneCampID, target.PropMoudle.SceneCampID, user.Scene.Cfg.SceneCameMatchType);
            }

            //宠物
            RemotePlayer rp = null;
            if (target is Pet)
            {
                var pet = target as Pet;
                rp = GameCenter.GameSceneSystem.FindEntity<RemotePlayer>(pet.PropMoudle.MasterID);
            }

            if (target is RemotePlayer)
            {
                rp = target as RemotePlayer;
            }

            if (rp != null)
            {
                if (GameCenter.LuaSystem.Adaptor.IsTeamMember(rp.ID))
                {
                    return false;
                }

                //判断地图是否能够PK
                if (user.Scene.Cfg != null && user.Scene.Cfg.PkState == 0)
                {
                    return false;
                }

                //判断是否在仇恨列表
                if (user.IsStrikeBack(rp.ID))
                {
                    return true;
                }

                //最后判断PK模式
                return CheckPKModel(user, rp);
            }
            return false;
        }

        //展示警示圈
        public static void ShowWarningFiled(SkillVisualInfo cfg, Entity owner)
        {
            if (owner is Character && !CanShowWarningFiled(GameCenter.GameSceneSystem.GetLocalPlayer(), owner as Character))
            {
                //只有敌对角色才会展示警示圈
                return;
            }
            //展示警示圈
            var findEvents = cfg.FindEvent(SkillEventDefine.PlayHit);
            if (findEvents.Count > 0)
            {
                var findEvent = findEvents[0] as PlayHitEventInfo;
                if (findEvent.FindInfo.ShowWarningField)
                {
                    var hitTime = findEvent.EventFrame * Skill.OneFrameTime;
                    switch (findEvent.FindInfo.AreaType)
                    {
                        case SkillTargetArea.Rectangle:
                            GameCenter.WarningFiledManager.AddFiled(owner, false, false, findEvent.FindInfo.AreaType, findEvent.FindInfo.RectWidth, findEvent.FindInfo.RectHeight, findEvent.FindInfo.StartDis, hitTime);
                            break;
                        case SkillTargetArea.FanShaped:
                            GameCenter.WarningFiledManager.AddFiled(owner, false, false, findEvent.FindInfo.AreaType, findEvent.FindInfo.SectorAngle, findEvent.FindInfo.SectorRadius, findEvent.FindInfo.StartDis, hitTime);
                            break;
                        case SkillTargetArea.Round:
                            GameCenter.WarningFiledManager.AddFiled(owner, false, false, findEvent.FindInfo.AreaType, findEvent.FindInfo.RoundRadius, 0f, findEvent.FindInfo.StartDis, hitTime);
                            break;
                    }
                    GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_SHOWBOSS_WARNINGFILED, new object[] { owner.Position2d, owner.GetFacingDirection2d(), hitTime, findEvent });
                }
            }
        }

        //展示boss技能提示
        public static void ShowBossSkillWarning(DeclareSkill cfg, Entity owner)
        {
            var monster = owner as Monster;
            if (monster == null)
                return;
            if (string.IsNullOrEmpty(cfg.PromptText) || cfg.PromptLifeTime <= 0)
                return;

            GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_SHOWSKILLWARNING_EFFECT, new object[] { cfg.PromptText, cfg.PromptDelay / 1000f, cfg.PromptLifeTime / 1000f });

        }

        #region //私有类以及结构
        struct SearchTargetInfo
        {
            public Character target;
            public float distanceSq;
            public int angle;
            public SearchTargetInfo(Character target, float distanceSq, int angle = 0)
            {
                this.target = target;
                this.distanceSq = distanceSq;
                this.angle = angle;
            }
        }

        //查询的采集物信息
        private struct SearchCollectionInfo
        {
            public Collection target;
            public float distanceSq;
            public SearchCollectionInfo(Collection target, float distanceSq)
            {
                this.target = target;
                this.distanceSq = distanceSq;
            }
        }
        #endregion
    }
}