using System;
using System.Collections.Generic;
using UnityEngine;
using XGame;

namespace FL.Battle
{
    /// <summary>
    /// 目标选择组件
    /// </summary>
    public class TargetSelector : ITargetSelector
    {
        struct FindTargetArgs
        {
            public EEntityType targetType;
            public ETargetFindType findType;
            /// <summary>
            /// 目标选择回调函数，同步查找目标时该方法无效
            /// <选中的目标>
            /// </summary>
            public Action<ITarget> onSelected;
        }

        private Dictionary<EEntityType, HashSet<ITarget>> _typeToTargetsMap;
        private Dictionary<long, ITarget> _idToTargetMap;
        private Dictionary<ITarget, FindTargetArgs> _waitingMap;
        private List<ITarget> _tempLst = new List<ITarget>();
        private long _playerEntityId;
        public void Register(ITarget target)
        {
            if (_typeToTargetsMap == null)
            {
                _typeToTargetsMap = new Dictionary<EEntityType, HashSet<ITarget>>();
                _idToTargetMap = new Dictionary<long, ITarget>();
            }
            var type = target.Entity.EntityType;
            if (!_typeToTargetsMap.TryGetValue(type, out var targets))
            {
                targets = new HashSet<ITarget>();
                _typeToTargetsMap.Add(type, targets);
            }
            targets.Add(target);
            _idToTargetMap.Add(target.Entity.EntityId, target);
            if (target.Entity.EntityType == EEntityType.Player)
            {
                _playerEntityId = target.Entity.EntityId;
            }
        }
        public void Unregister(ITarget target)
        {
            if (_typeToTargetsMap == null) return;
            foreach (var targets in _typeToTargetsMap.Values)
            {
                if (targets.Contains(target))
                {
                    targets.Remove(target);
                    break;
                }
            }
            _idToTargetMap.Remove(target.Entity.EntityId);
            _waitingMap?.Remove(target);
            if (target.Entity.EntityId == _playerEntityId)
            {
                _playerEntityId = 0;
            }
        }
        public ITarget GetTarget(long entityId)
        {
            ITarget target = null;
            _idToTargetMap?.TryGetValue(entityId, out target);
            return target;
        }
        public ITarget GetPlayer()
        {
            return GetTarget(_playerEntityId);
        }
        ITarget ITargetSelector.FindSync(ITarget finder, EEntityType targetType, ETargetFindType findType, Func<ITarget, bool> customFilter)
        {
            var info = new FinderInfo()
            {
                uid = finder.Entity.EntityId,
                position = finder.Position,
                radius = finder.Entity.Attr.Radius
            };
            return FindTarget(info, targetType, findType, customFilter);
        }
        ITarget ITargetSelector.FindSync(FinderInfo finder, EEntityType targetType, ETargetFindType findType, Func<ITarget, bool> customFilter)
        {
            return FindTarget(finder, targetType, findType, customFilter);
        }
        bool ITargetSelector.FindTargets(FinderInfo finder, EEntityType targetType, ETargetFindType findType, Func<ITarget, bool> customFilter, ref List<ITarget> targets)
        {
            if (!TryGetTargets(targetType, out var preTargets))
            {
                Log.Debug($"没有可选目标 Finder:{finder.uid}  TargetType:{targetType}");
                return false;
            }
            if (targets == null)
                targets = new List<ITarget>();
            foreach (var target in preTargets)
            {
                if (!IsCanSelect(target, findType is ETargetFindType.NearestAlive or ETargetFindType.InRangeAlive))
                    continue;
                if (customFilter.SafeInvoke(target))
                {
                    continue;
                }
                if (IsInRange(finder, target, out var distance))
                {
                    targets.Add(target);
                }
            }
            return targets.Count > 0;
        }
        bool ITargetSelector.FindTargets(Rect rect, EEntityType targetType, ETargetFindType findType, Func<ITarget, bool> customFilter, ref List<ITarget> targets)
        {
            if (!TryGetTargets(targetType, out var preTargets))
            {
                Log.Debug($"没有可选目标 Rect:{rect} TargetType:{targetType}");
                return false;
            }
            if (targets == null)
                targets = new List<ITarget>();
            foreach (var target in preTargets)
            {
                if (!IsCanSelect(target, findType is ETargetFindType.NearestAlive or ETargetFindType.InRangeAlive))
                    continue;
                if (customFilter.SafeInvoke(target))
                {
                    continue;
                }
                if (rect.Contains(target.Position))
                {
                    targets.Add(target);
                }
            }
            return targets.Count > 0;
        }
        void ITargetSelector.FindAsync(ITarget finder, EEntityType targetType, ETargetFindType findType, Action<ITarget> onSelected)
        {
            if (_waitingMap == null)
            {
                _waitingMap = new Dictionary<ITarget, FindTargetArgs>();
            }
            _waitingMap[finder] = new FindTargetArgs()
            {
                targetType = targetType,
                findType = findType,
                onSelected = onSelected
            };
        }
        public void OnUpdate(int times)
        {
            var count = _waitingMap?.Count ?? 0;
            if (count == 0)
                return;
            _tempLst.AddRange(_waitingMap.Keys);
            for (var i = 0; i < count; i++)
            {
                var finder = _tempLst[i];
                if (!IsCanSelect(finder, false))
                    continue;
                if (!_waitingMap.TryGetValue(finder, out var args))
                {
                    continue;
                }
                var info = new FinderInfo()
                {
                    uid = finder.Entity.EntityId,
                    position = finder.Position,
                    radius = finder.Entity.Attr.Radius
                };
                var target = FindTarget(info, args.targetType, args.findType, null);
                if (target != null)
                { // 找到目标了才回调，并删除数据
                    args.onSelected.SafeInvoke(target);
                    _waitingMap.Remove(finder);
                }
            }
            _tempLst.Clear();
        }
        /// <summary>
        /// 查找目标
        /// </summary>
        /// <param name="finder"></param>
        /// <param name="targetType"></param>
        /// <param name="findType"></param>
        /// <param name="customFilter">过滤器，不能选择时返回true</param>
        /// <returns></returns>
        private ITarget FindTarget(FinderInfo finder, EEntityType targetType, ETargetFindType findType, Func<ITarget, bool> customFilter)
        {
            if (!TryGetTargets(targetType, out var targets))
            {
                Log.Debug($"没有可选目标 Finder:{finder.uid}  TargetType:{targetType}");
                return null;
            }
            ITarget result = null;
            var distanceMin = float.MaxValue;
            foreach (var target in targets)
            {
                if (!IsCanSelect(target, findType is ETargetFindType.NearestAlive or ETargetFindType.InRangeAlive))
                    continue;
                if (customFilter.SafeInvoke(target))
                {
                    continue;
                }
                var isInRange = IsInRange(finder, target, out var distance);
                if (findType is ETargetFindType.Nearest or ETargetFindType.NearestAlive)
                {
                    if (result == null || distanceMin > distance)
                    {
                        result = target;
                        distanceMin = distance;
                    }
                }
                else if (isInRange)
                {
                    result = target;
                    break;
                }
            }
            return result;
        }
        /// <summary>
        /// 目标是否可选择
        /// </summary>
        /// <param name="target"></param>
        /// <param name="isAlive">True: 除了死亡状态，其他状态都可选</param>
        /// <returns></returns>
        private bool IsCanSelect(ITarget target, bool isAlive)
        {
            if (target.IsDead) return false;
            if (target.Entity.IsState(EEntityState.Moving))
                return isAlive;
            return isAlive || target.IsMoving == false;
            //return target.Entity.State switch
            //{
            //    EEntityState.Idle or EEntityState.Battle => isAlive || target.IsMoving == false,
            //    EEntityState.Dead => false,
            //    _ => isAlive,
            //};
        }
        private bool TryGetTargets(EEntityType entityType, out HashSet<ITarget> targets)
        {
            if (_typeToTargetsMap != null && _typeToTargetsMap.TryGetValue(entityType, out targets))
            {
                return true;
            }
            targets = null;
            return false;
        }
        private bool IsInRange(FinderInfo finder, ITarget target, out float distance)
        {
            distance = Vector3.Distance(target.Position, finder.position);
            distance -= (finder.radius + target.Entity.Attr.Radius); // 去掉双方的半径
            return distance <= 0;
        }
        public void Clear()
        {
            _typeToTargetsMap?.Clear();
            _idToTargetMap?.Clear();
            _waitingMap?.Clear();
            _tempLst?.Clear();
            _playerEntityId = 0;
        }
    }

}

