using System.Collections;
using Server.Data;
using System.Collections.Generic;
using MrWu.Debug;
using Server.Core;

namespace Game.Player
{
    public class PlayerCollection : SingleInstance<PlayerCollection>
    {
        private readonly int _maxPlayer;

        public int PlayerCnt { get; private set; }

        public int RobotCnt { get; private set; }

        public int RealPlayerCnt => PlayerCnt - RobotCnt;

        private readonly object _playerLock = new object();

        private int _nextId;

        private readonly PlayerDataAsyc[] _players;

        /// <summary>
        /// 空闲下来的索引
        /// </summary>
        public readonly Queue<int> _ileIds = new Queue<int>();

        /// <summary>
        /// userid 与玩家数据 字典
        /// </summary>
        public readonly Dictionary<int, PlayerDataAsyc> _playersDic = new Dictionary<int, PlayerDataAsyc>();

        public int GetMaxId()
        {
            return _nextId;
        }

        public PlayerCollection()
        {
            this._maxPlayer = 100000;
            _players = new PlayerDataAsyc[_maxPlayer];
        }

        /// <summary>
        /// 把玩家加载到在线列表中
        /// </summary>
        /// <param name="pl">要添加的玩家</param>
        /// <returns>-1 表示玩家已到最大值 -2添加到内存失败 1添加成功</returns>
        public int AddPlayer(PlayerDataAsyc pl)
        {
            lock (_playerLock)
            {
                if (PlayerCnt >= _maxPlayer)
                {
                    return -1;
                }

                if (_playersDic.ContainsKey(pl.userid))
                {
                    return -2;
                }

                int id = 0;
                if (_ileIds.Count > 0)
                {
                    id = _ileIds.Dequeue();
                }
                else
                {
                    id = _nextId++;
                }

                _players[id] = pl;
                pl.id = id;
                PlayerCnt++;
                _playersDic[pl.userid] = pl;

                if (pl.userid < 0)
                {
                    RobotCnt++;
                }

                return 1;
            }
        }

        public int RemovePlayer(PlayerDataAsyc pl)
        {
            lock (_playerLock)
            {
                int id = pl.id;
                if (id < 0 || id >= _nextId || _players[id] == null)
                {
                    return -1;
                }

                if (!_playersDic.Remove(pl.userid))
                {
                    return -1;
                }

                _players[id] = null;
                pl.id = -1;
                PlayerCnt--;
                _ileIds.Enqueue(id);

                if (pl.userid < 0)
                {
                    RobotCnt--;
                }

                return 1;
            }
        }

        public PlayerDataAsyc FindPlayer(int id)
        {
            lock (_playerLock)
            {
                if (id < 0 || id >= _nextId)
                {
                    return null;
                }

                return _players[id];
            }
        }

        public PlayerDataAsyc FindPlayerByUserId(int userid)
        {
            lock (_playerLock)
            {
                if (!_playersDic.TryGetValue(userid, out var player))
                {
                    return null;
                }

                return player;
            }
        }

        public List<int> GetPlayerUserIds()
        {
            List<int> result = new List<int>();
            lock (_playerLock)
            {
                result.AddRange(_playersDic.Keys);
            }

            return result;
        }

        public IEnumerator GetEnumerator()
        {
            return GetPlayerUserIds().GetEnumerator();
        }

        public List<PlayerDataAsyc> GetPlayers()
        {
            List<PlayerDataAsyc> result = new List<PlayerDataAsyc>();
            lock (_playerLock)
            {
                result.AddRange(_playersDic.Values);
            }

            return result;
        }
    }
}