using FL.Battle.Actions;
using FL.Battle.Skills;
using System;
using System.Collections.Generic;
using UnityEngine;
using XGame;
using XGame.Database;
using XGame.Framework;
using XGame.Framework.Components;

namespace FL.Battle.Components.AI
{
    public interface IBulletAIContext
    {
        long UID { get; }
        long MasterId { get; }
        int TableId { get; }
        ITargetSelector Selector { get; }
        Vector3 Position { get; }
        VfxComponent Vfx { get; }
        MoveComponent Move { get; }
    }
    /// <summary>
    /// AI组件和具体的EntityView绑定，其他Component最好不要尝试获取AI组件
    /// </summary>
    public class BulletAI : Component<IBulletAIContext>
    {
        /// <summary>
        /// 已攻击过的目标id
        /// </summary>
        private HashSet<long> _lastTargetIds = new HashSet<long>();
        private SkillTable _skill;
        private SkillVfxsTable _skillVfxs;
        protected override void OnDispose()
        {
            _skill = null;
            _skillVfxs = null;
            _lastTargetIds.Clear();
        }

        public void Start(long targetId, Vector3 targetPosition, EEntityType targetType, int delay)
        {
            _skill = SkillTableRepo.Get(Context.TableId);
            _skillVfxs = SkillVfxsTableRepo.Get(Context.TableId);
            var bulletType = (ESkillVfxType)_skill.SkillVfxType;
            _lastTargetIds.Clear();
            // 子弹的移动方向
            var direction = Vector3.Normalize(targetPosition - Context.Position);
            var moveArgs = new MoveArgs()
            {
                target = targetPosition,
                speed = _skillVfxs.SkillVfxSpeed,
                timeScale = 1,
                delay = delay,
                moveType = (EMoveType)(_skillVfxs.SkillVfxMoveType - 1),
                onComplete = () =>
                {
                    if (bulletType == ESkillVfxType.BulletMortar)
                    {
                        MortarExplode(targetPosition, targetType);
                        End();
                        return;
                    }
                    var target = Context.Selector.GetTarget(targetId);
                    if (target == null || target.IsDead)
                    {
                        //Log.Debug($"子弹移动到目标位置, 目标已死亡. Target:{targetId} Bullet:{Context.TableId}");
                        End();
                        return;
                    }
                    PlayHitVfx(_skillVfxs.HitVfx, targetPosition);
                    target.Calculation.Damage(-_skill.Damage, Context.MasterId, _skill);
                    switch (bulletType)
                    {
                        case ESkillVfxType.BulletSplit:
                            // 分裂
                            _lastTargetIds.Add(targetId);
                            Split(direction, target.Entity.EntityType);
                            End();
                            break;
                        case ESkillVfxType.BulletJump:
                            // 弹跳
                            _lastTargetIds.Add(targetId);
                            Jump(target.Entity.EntityType, 1);
                            break;
                        default:
                            End();
                            break;
                    }
                }
            };
            if (Enum.TryParse<DG.Tweening.Ease>(_skillVfxs.SkillVfxMoveEase, true, out var ease))
            {
                moveArgs.ease = ease;
            }
            Context.Move.MoveTo(moveArgs);
        }
        /// <summary>
        /// 受击特效
        /// </summary>
        /// <param name="hitVfx"></param>
        /// <param name="targetPosition"></param>
        private void PlayHitVfx(string hitVfx, Vector3 targetPosition)
        {
            var actPosition = ObjectPool.Acquire<PositionAction>();
            actPosition.position = targetPosition;
            var hitArgs = ObjectPool.Acquire<VfxArgs>();
            hitArgs.vfxName = hitVfx;
            hitArgs.duration = _skillVfxs.HitVfxTime;
            hitArgs.followType = EVfxFollowType.World;
            hitArgs.action = actPosition;
            Context.Vfx.Play(hitArgs);
        }

        /// <summary>
        /// 子弹分裂
        /// DamageArgs[数量，夹角(为零则就近原则找目标)，缩放万分比]
        /// DamageArgs[1]大于零时，以子弹的初始移动方向为中心，按顺序(先左后右)累加角度获取分裂后子弹的方向
        /// 怪物在该方向上则命中，否则子弹按直线飞出屏幕
        /// </summary>
        /// <param name="direction">子弹的移动方向</param>
        /// <param name="targetType">目标类型</param>
        private void Split(Vector3 direction, EEntityType targetType)
        {
            var childCount = _skill.DamageArgs[0];
            var childAngle = _skill.DamageArgs[1];
            var childScale = _skill.DamageArgs[2];
            var from = Context.Position;
            var finderInfo = new FinderInfo()
            {
                uid = Context.UID,
                position = from,
                radius = 0,
            };
            for (var i = 0; i < childCount; i++)
            {
                var target = Context.Selector.FindSync(finderInfo, targetType, ETargetFindType.Nearest, (a) =>
                {
                    if (_lastTargetIds.Contains(a.Entity.EntityId))
                    {
                        return true;
                    }
                    if (childAngle == 0)
                        return false;
                    var tarAngle = ((i + 1) / 2) * childAngle;
                    var tempDir = Vector3.Normalize(a.Position - from);
                    // angle:[0, 180]
                    var angle = Vector3.Angle(direction, tempDir);
                    //Log.Debug($"Bullet Split index:{i} direction:{direction} temp:{tempDir} angle:{angle} tar:{tarAngle}");
                    if (Mathf.Abs(angle - tarAngle) < 20)
                    { //角度范围-5到5
                        if (i == 0)
                            return false;
                        //cross.z > 0 目标向量在方向向量的左侧
                        var cross = Vector3.Cross(direction, tempDir);
                        if (i % 2 == 0)
                        { // i为偶数在右边
                            return cross.z > 0;
                        }
                        return cross.z < 0;
                    }
                    return true;
                });

                if (target == null && childAngle == 0)
                {
                    continue;
                }
                Vector3 to;
                if (target != null)
                {
                    _lastTargetIds.Add(target.Entity.EntityId);
                    to = target.Position;
                }
                else
                {
                    if (i == 0)
                    {
                        to = from + direction * 12;
                    }
                    else
                    {
                        // i为偶数在右边 负数
                        var sign = i % 2 == 0 ? -1 : 1;
                        var tarAngle = ((i + 1) / 2) * childAngle;
                        //var tempDir = direction.RotateLeft(sign * tarAngle);
                        //var angle = Vector3.Angle(direction, tempDir);
                        //Log.Debug($"Bullet Split index:{i} direction:{direction} temp:{tempDir} angle:{angle} tar:{tarAngle} {Vector3.Angle(direction, Vector3.up)} {Vector3.Angle(tempDir, Vector3.up)}");
                        to = from + direction.RotateLeft(sign * tarAngle) * 12;
                    }
                }
                //子弹移动
                var duration = Mathf.RoundToInt(Vector3.Distance(from, to) * 1000 / _skillVfxs.SkillVfxSpeed);
                var actMove = ObjectPool.Acquire<MoveLineAction>();
                actMove.args = new MoveActionArgs()
                {
                    from = from,
                    to = to,
                    duration = duration
                };
                //子弹特效
                var bulletArgs = ObjectPool.Acquire<VfxArgs>();
                bulletArgs.vfxName = _skillVfxs.SkillVfx;
                bulletArgs.duration = duration;
                bulletArgs.followType = EVfxFollowType.World;
                bulletArgs.action = actMove;
                if (target != null)
                {
                    var skill = _skill;
                    var masterId = Context.MasterId;
                    bulletArgs.onFinish = () =>
                    {
                        if (target == null || target.IsDead)
                        {
                            return;
                        }
                        target.Calculation.Damage(-skill.Damage, masterId, skill);
                    };
                    //受击特效位置
                    var actPosition = ObjectPool.Acquire<PositionAction>();
                    actPosition.position = to;
                    //受击特效
                    var hitArgs = ObjectPool.Acquire<VfxArgs>();
                    hitArgs.vfxName = _skillVfxs.HitVfx;
                    hitArgs.duration = _skillVfxs.HitVfxTime;
                    hitArgs.followType = EVfxFollowType.World;
                    hitArgs.action = actPosition;
                    bulletArgs.next = hitArgs;
                }
                Context.Vfx.Play(bulletArgs);
            }
        }
        /// <summary>
        /// 弹跳
        /// DamageArgs[弹跳次数,伤害递减万分比]
        /// </summary>
        /// <param name="targetType">目标类型</param>
        /// <param name="jumpTimes">弹跳次数</param>
        private void Jump(EEntityType targetType, int jumpTimes)
        {
            var jumpLimit = _skill.DamageArgs[0];
            var hurtReduce = _skill.DamageArgs[1];
            var finderInfo = new FinderInfo()
            {
                uid = Context.UID,
                position = Context.Position,
                radius = 0,
            };
            var target = Context.Selector.FindSync(finderInfo, targetType, ETargetFindType.Nearest, (a) =>
            {
                if (_lastTargetIds.Contains(a.Entity.EntityId))
                {
                    return true;
                }
                return false;
            });
            if (target == null)
            {
                End();
                return;
            }
            var targetId = target.Entity.EntityId;
            _lastTargetIds.Add(targetId);
            var tarPosition = target.Position;
            var moveArgs = new MoveArgs()
            {
                target = tarPosition,
                speed = _skillVfxs.SkillVfxSpeed * 0.8f,
                timeScale = 1,
                onComplete = () =>
                {
                    target = Context.Selector.GetTarget(targetId);
                    if (target == null || target.IsDead)
                    {
                        Log.Debug($"子弹移动到目标位置, 目标已死亡. Target:{targetId} Bullet:{Context.TableId}");
                        End();
                        return;
                    }
                    // 受击特效
                    PlayHitVfx(_skillVfxs.HitVfx, tarPosition);
                    // 计算受击伤害
                    target.Calculation.Damage(-JumpHurt(_skill.Damage, jumpTimes, hurtReduce), Context.MasterId, _skill);
                    jumpTimes++;
                    if (jumpTimes > jumpLimit)
                    {
                        End();
                        return;
                    }
                    Jump(targetType, jumpTimes);
                }
            };
            Context.Move.MoveTo(moveArgs);
        }
        private int JumpHurt(int baseVal, int jumpTimes, int hurtReduce)
        {
            float hurtVal = baseVal;
            for (var i = 0; i < jumpTimes; i++)
            {
                hurtVal *= (1 - hurtReduce * 0.0001f);
            }
            return Mathf.RoundToInt(hurtVal);
        }
        /// <summary>
        /// 迫击炮爆炸
        /// </summary>
        /// <param name="targetPosition"></param>
        /// <param name="targetType"></param>
        private void MortarExplode(Vector3 targetPosition, EEntityType targetType)
        {
            var hitRadius = _skill.Ranges[0];
            var explodeRadius = _skill.Ranges[1];
            var explodeHurt = _skill.DamageArgs[0];
            PlayHitVfx(_skillVfxs.HitVfx, targetPosition);
            // 查找受击目标
            var finderInfo = new FinderInfo()
            {
                uid = Context.UID,
                position = Context.Position,
                radius = hitRadius,
            };
            var hitTarget = Context.Selector.FindSync(finderInfo, targetType, ETargetFindType.NearestAlive);
            if (hitTarget != null)
            {

                hitTarget.Calculation.Damage(-_skill.Damage, Context.MasterId, _skill);
            }
            // 查找爆炸受击目标
            finderInfo.radius = explodeRadius;
            var targets = new List<ITarget>();
            if (Context.Selector.FindTargets(finderInfo, targetType, ETargetFindType.InRangeAlive, null, ref targets))
            {
                foreach (var explodeTar in targets)
                {
                    explodeTar.Calculation.Damage(-explodeHurt, Context.MasterId, _skill);
                }
            }
        }
        /// <summary>
        /// 结束
        /// </summary>
        private void End()
        {
            _skill = null;
            _skillVfxs = null;
            _lastTargetIds.Clear();
            EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveSimpleEntity, Context.UID);
        }

    }
}
