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

namespace FL.Battle
{
    public interface ITargetHandle
    {
        IEntity Entity { get; }
        Vector3 Position { get; }
        bool IsMoving { get; }
        float Radius { get; }
        float AtkRange { get; }
        void SelectTarget(ITargetHandle target, int skillId);
    }
    public struct FindTargetArgs
    {
        public int entityId;
        public EEntityType entityType;
        /// <summary>
        /// 范围
        /// </summary>
        public float range;
        /// <summary>
        /// 为零表示普通攻击
        /// </summary>
        public int skillId;
    }
    /// <summary>
    /// 目标选择组件
    /// </summary>
    public class TargetSelector
    {
        private Dictionary<EEntityType, HashSet<ITargetHandle>> _typeToHandlesMap;
        private Dictionary<int, ITargetHandle> _idToHandlesMap;
        private Dictionary<ITargetHandle, FindTargetArgs> _waitingMap;
        private List<ITargetHandle> _tempLst = new List<ITargetHandle>();
        public void Register(ITargetHandle handle)
        {
            if (_typeToHandlesMap == null)
            {
                _typeToHandlesMap = new Dictionary<EEntityType, HashSet<ITargetHandle>>();
                _idToHandlesMap = new Dictionary<int, ITargetHandle>();
            }
            var type = handle.Entity.EntityType;
            if (!_typeToHandlesMap.TryGetValue(type, out var handles))
            {
                handles = new HashSet<ITargetHandle>();
                _typeToHandlesMap.Add(type, handles);
            }
            handles.Add(handle);
            _idToHandlesMap.Add(handle.Entity.EntityId, handle);
        }
        public void Unregister(ITargetHandle handle)
        {
            if (_typeToHandlesMap == null) return;
            foreach(var handles in _typeToHandlesMap.Values)
            {
                if (handles.Contains(handle))
                {
                    handles.Remove(handle);
                    break;
                }
            }
            _idToHandlesMap.Remove(handle.Entity.EntityId);
            _waitingMap?.Remove(handle);
        }
        public void Start(FindTargetArgs args)
        {
            if (_idToHandlesMap == null || _idToHandlesMap.TryGetValue(args.entityId, out var handle) == false)
            {
                return;
            }
            if (_waitingMap == null)
            {
                _waitingMap = new Dictionary<ITargetHandle, FindTargetArgs>();
            }
            _waitingMap[handle] = args;
        }
        public void Selects()
        {
            var count = _waitingMap?.Count ?? 0;
            if (count == 0)
                return;
            _tempLst.AddRange(_waitingMap.Keys);
            for(var i = 0; i < count; i++)
            {
                var director = _tempLst[i];
                if (director.Entity.State == EEntityState.Dead || director.IsMoving)
                    continue;
                if (!_waitingMap.TryGetValue(director, out var args))
                {
                    continue;
                }
                if (!TryGetTargets(args.entityType, out var targets))
                {
                    Log.Debug($"没有可选目标 Entity:{director.Entity.TableId} Relation:{director.Entity.EntityType} Target:{args.entityType}");
                    continue;
                }
                ITargetHandle preTarget = null;
                var distanceMin = float.MaxValue;
                foreach (var target in targets)
                {
                    if (target.IsMoving)
                        continue;
                    if (IsInRange(director, target, args.range, out var distance))
                    {
                        if (preTarget == null || distanceMin > distance)
                        {
                            preTarget = target;
                            distanceMin = distance;
                        }
                    }
                }
                if (preTarget != null)
                {
                    try
                    {
                        director.SelectTarget(preTarget, args.skillId);
                        _waitingMap.Remove(director);
                    }
                    catch (Exception ex)
                    {
                        Log.Exception(ex);
                    }
                }
            }
            _tempLst.Clear();
        }
        private bool TryGetTargets(EEntityType entityType, out HashSet<ITargetHandle> targets)
        {
            if (_typeToHandlesMap != null && _typeToHandlesMap.TryGetValue(entityType, out targets))
            {
                return true;
            }
            targets = null;
            return false;
        }
        private bool IsInRange(ITargetHandle director, ITargetHandle target, float range, out float distance)
        {
            if (target.Entity.State == EEntityState.Dead)
            {
                distance = 0;
                return false;
            }
            distance = Vector3.Distance(target.Position, director.Position);
            distance -= (director.Radius + target.Radius); // 去掉双方的半径
            return true;// range >= distance;
        }
        public void Clear()
        {
            _typeToHandlesMap?.Clear();
            _idToHandlesMap?.Clear();
            _waitingMap?.Clear();
            _tempLst?.Clear();
        }
        
    }

}

