using System;
using System.Collections.Generic;
using Game.Robot;
using MrWu.Basic;
using MrWu.Debug;
using Server;
using Server.Core;
using Server.Data;

namespace Game.Queue
{
    /// <summary>
    /// 队友排队器
    /// </summary>
    public class FriendQueue : GoldQueueBase
    {
        /// <summary>
        /// 所属厅
        /// </summary>
        public override TingManager ting { get; protected set; }

        /// <summary>
        /// 最小人数
        /// </summary>
        public override int MinCnt
        {
            get { return ting.config.MinPlayerCnt; }
        }

        /// <summary>
        /// 最大人数
        /// </summary>
        public override int MaxCnt
        {
            get { return ting.config.MaxPlayerCnt; }
        }

        protected static readonly ListPool<PlayerDataAsyc> PlayerListPool = new ListPool<PlayerDataAsyc>();

        /// <summary>
        /// 最短排上队的时间
        /// </summary>
        protected const int minqueueTime = 2;

        /// <summary>
        /// 最长排上队的时间
        /// </summary>
        protected const int maxqueueTime = 10;

        /// <summary>
        /// 必须排队的几率
        /// </summary>
        protected const float needqueue = 0.05f;

        /// <summary>
        /// 创建普通排队器
        /// </summary>
        /// <param name="ting"></param>
        public FriendQueue(TingManager ting)
        {
            this.ting = ting;
        }

        private bool _DoQueue(int idx)
        {
            //从第一个人开始计算,,, 如果有人. 先配对
            if (idx >= QueuePlayer.Count)
            {
                return false;
            }

            var pl = QueuePlayer[idx];
            pl.queuetime++;

            //排队有两种 -- 自然排队 -- 自然+机器人  --纯机器人排队
            //那种排队时间到了很久的 必须要补机器人
            //自然排队可以排队上的，不处理 -- 如果人少，，则需要老是排队
            //只能跟机器人的,随机时间开战

            //排队分两种 第一种全真人
            //还没到时间，下一个
            if (pl.queuetime < minqueueTime)
            {
                return false;
            }

            //是否是必须排队上  10% 必须排队上
            bool isneedqueue = GetNeedQueue(pl);

            //凑一桌的人
            List<PlayerDataAsyc> result = PlayerListPool.Get();
            bool isSuccess = false;
            //Debug.Info($"_DoQueue {isneedqueue}");

            if (!isneedqueue)
            {
                //不是必须排队上, 自然的
                if (pl.QueueSet.Count >= (MinCnt - 1))
                {
                    //必须要满足最小开战人数
                    //从最多的开始算
                    for (int i = MaxCnt; i >= MinCnt; i--)
                    {
                        //取 i-1 个人 和现在的玩家凑成一桌
                        if (GetQueueList(pl, i - 1, result))
                        {
                            result.Add(pl);
                            isSuccess = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                //强行补齐
                //能凑几个真人凑几个, 凑完之后补机器人
                for (int i = MaxCnt; i >= 2; i--)
                {
                    if (i % 2 == 1)
                    {
                        continue;
                        //取单数个真人，为了让真人凑一桌
                    }
                    
                    if (GetQueueList(pl, i - 1, result))
                    {
                        result.Add(pl);
                        isSuccess = true;
                        break;
                    }
                }

                //补机器人
                if (!isSuccess)
                {
                    result.Clear();
                    result.Add(pl);
                }

                int allcnt = MinCnt;

                if (MinCnt != MaxCnt)
                {
                    Debug.Info($"玩家最小数量:{MinCnt} {MaxCnt}");
                    //最小值
                    int minCnt = Math.Max(result.Count, MinCnt);
                    if (minCnt != MaxCnt)
                    {
                        allcnt = GetRandomQueueCnt(minCnt, MaxCnt);
                    }
                    else
                    {
                        allcnt = minCnt;
                    }
                }

                //要补充机器人的数量
                int robotcnt = allcnt - result.Count;

                //Debug.Info($"排队强行补齐! 需要机器人数量:{robotcnt}");

                isSuccess = true;
                for (int i = 0; i < robotcnt; i++)
                {
                    var tmp = RobotController.instance.GetRobot(ting.id);
                    if (tmp == null)
                    {
                        //再把机器人放回池中
                        int len = result.Count;
                        for (int j = len - 1; j >= 0; j--)
                        {
                            if (result[j].isRobot)
                            {
                                //是机器人，机器人放入池中的数据
                                RobotController.instance.PushRobot(result[j], ting.id); //放回池中 
                            }
                            else
                                break;
                        }

                        isSuccess = false;
                        break;
                    }
                    else
                    {
                        result.Add(tmp);
                    }
                }
            }

            try
            {
                //Debug.Info($"排队结果:{isSuccess} {idx}");
                if (isSuccess)
                {
                    //凑桌 -- 开战
                    //先拿到一个人的桌子
                    if (result.Count > 0)
                    {
                        //Debug.Log("桌子id:" + result[0].deskid);
                        MergeDesk(result);
                        Debug.Info("移出排队列表:" + result[0].userid + "," + result[0].id);
                        return true;
                    }
                }

                return false;
            }
            finally
            {
                PlayerListPool.Recycle(result);
            }
        }

        /// <summary>
        /// 把这些人凑一桌
        /// </summary>
        /// <param name="pls"></param>
        private void MergeDesk(List<PlayerDataAsyc> pls)
        {
            //拿到第一个人的桌子
            if (pls == null || pls.Count == 0)
            {
                Debug.Error("凑桌时玩家列表是空?");
                return;
            }

            if (pls.Count == 4)
            {
                //调换位置，让真人成为队友
                if (!pls[0].isRobot)
                {
                    if (pls[2].isRobot)
                    {
                        if (!pls[1].isRobot)
                        {
                            (pls[1],pls[2]) = (pls[2],pls[1]);
                        }else if (!pls[3].isRobot)
                        {
                            (pls[3], pls[2]) = (pls[2], pls[3]);
                        }
                    }
                    //如果是四个真人，让大房间的成为队友
                    bool isAllReal = true;
                    for (int i = 0; i < pls.Count; i++)
                    {
                        if (!pls[i].isRobot)
                        {
                            continue;
                        }
                        isAllReal = false;
                        break;
                    }
                    if (isAllReal)
                    {
                        //让 roomid 较大的两个玩家成为队友（坐对面）
                        var sorted = new List<PlayerDataAsyc>(pls);
                        sorted.Sort((a, b) => b.roomid.CompareTo(a.roomid)); // 降序排序
                        // roomid 最大的两个玩家坐对面 (0 和 2)
                        pls[0] = sorted[0];  // roomid 最大
                        pls[2] = sorted[1];  // roomid 第二大
                        pls[1] = sorted[2];  // roomid 第三大
                        pls[3] = sorted[3];  // roomid 最小
                    }
                }
            }
            
            
            Desk desk = ting.desks[pls[0].deskid];
            for (int i = 1; i < pls.Count; i++)
            {
                var pl = pls[i];
                //其他人加入到第一个人的桌子
                int roomId = pls[i].roomid;

                if (pl.deskid != desk.id)
                {
                    //不是这个桌子的 
                    if (pl.deskid > -1)
                    {
                        //有桌子要先退出桌子
                        ting.QuitDesk(pls[i], false); //先退出桌子-- 这里会回收掉桌子
                    }

                    if (!desk.AddPlayer(pls[i], roomId))
                    {
                        Debug.Error("玩家进入桌子失败!" + pls[i].id + "," + roomId);
                    }
                    else
                    {
                        Debug.Info("玩家进入桌子成功!" + pls[i].id);
                    }
                }

                if (!pl.isRobot)
                {
                    //上面的 QuitDesk 实际上已经让玩家退出排队列表了，这里再执行一次是怕有别的问题
                    RemoveQueueList(pl); //把玩家移除排队列表
                }
            }

            if (!pls[0].isRobot)
            {
                RemoveQueueList(pls[0]); //把第一个玩家移出列表
            }
        }

        /// <summary>
        /// 处理排队
        /// </summary>
        public override void DoQueue()
        {
            int idx = 0;
            //Debug.Info($"执行排队:{QueuePlayer.Count}");
            while (idx < QueuePlayer.Count)
            {
                //没排队成功就 idx++
                if (!_DoQueue(idx))
                {
                    idx++;
                }
            }
        }
        
        /// <summary>
        /// 从可以排队列表中 凑出一桌(cnt个人)
        /// </summary>
        /// <returns></returns>
        private static bool GetQueueList(PlayerDataAsyc pl, int cnt, List<PlayerDataAsyc> result)
        {
            result.Clear();
            if (pl.QueueSet.Count < cnt)
            {
                return false;
            }

            //Debug.Info($"GetQueueList begin {cnt}!");
            // 预先筛选和排序，减少后续处理量
            List<PlayerDataAsyc> candidates = PlayerListPool.Get(); // new List<PlayerDataAsyc>(pl.QueueSet);
            candidates.AddRange(pl.QueueSet);
            candidates.Sort((a, b) => ComparePlayerPriority(pl, a, b));

            // Find a group of mutually acceptable players
            if (GetDeskPlayerGroup(candidates, cnt, result))
            {
                PlayerListPool.Recycle(candidates);
                return true;
            }

            //Debug.Info("GetQueueList end!");

            PlayerListPool.Recycle(candidates);
            return false;
        }

        private static bool GetDeskPlayerGroup(List<PlayerDataAsyc> openList, int cnt, List<PlayerDataAsyc> result)
        {
            //Debug.Info($"GetDeskPlayerGroup begin openList:{openList.Count} cnt:{cnt}");
            if (openList.Count < cnt)
            {
                return false;
            }

            //只要一个人
            if (cnt == 1)
            {
                result.Add(openList[0]);
                return true;
            }

            for (int i = 0; i < openList.Count - 1; i++)
            {
                //i 是第二个人
                List<PlayerDataAsyc> candidates = PlayerListPool.Get();
                for (int j = 0; j < openList.Count; j++)
                {
                    if (j == i)
                    {
                        continue;
                    }

                    // j 是第三个人
                    if (openList[i].QueueSet.Contains(openList[j]))
                    {
                        candidates.Add(openList[j]);
                    }
                }

                //处理成功
                if (GetDeskPlayerGroup(candidates, cnt - 1, result))
                {
                    PlayerListPool.Recycle(candidates);
                    result.Add(openList[i]);
                    return true;
                }

                PlayerListPool.Recycle(candidates);
            }

            return false;
        }


        /// <summary>
        /// Compares two players' priority relative to the base player
        /// </summary>
        /// <param name="pl">Base player</param>
        /// <param name="a">First player to compare</param>
        /// <param name="b">Second player to compare</param>
        /// <returns>Negative if a has higher priority, positive if b has higher priority, 0 if equal</returns>
        private static int ComparePlayerPriority(PlayerDataAsyc pl, PlayerDataAsyc a, PlayerDataAsyc b)
        {
            if (a == null)
            {
                Debug.Error("Player A is null");
                return 1;
            }

            if (b == null)
            {
                Debug.Error("Player B is null");
                return -1;
            }

            if (pl == null)
            {
                Debug.Error("Base player is null");
                return 0;
            }
            
            //相同平台的玩家优先
            if (pl.device != null)
            {
                bool samePlatA = a.device != null && pl.device.plat == a.device.plat;
                bool samePlatB = b.device != null && pl.device.plat == b.device.plat;
                
                if (samePlatA && !samePlatB)
                {
                    return -1;
                }

                if (!samePlatA && samePlatB)
                {
                    return 1;
                }
            }
            
            // 房间接近的优先
            // {
            //     int diffA = Math.Abs(a.roomid - pl.roomid);
            //     int diffB = Math.Abs(b.roomid - pl.roomid);
            //
            //     if (diffA < diffB)
            //     {
            //         return -1;
            //     }
            //     else if (diffA > diffB)
            //     {
            //         return 1;
            //     }
            // }

            //胜率接近的优先
            if (pl.WarData != null && a.WarData != null && b.WarData != null)
            {
                float diffA = Math.Abs(pl.WarData.VictoryRate - a.WarData.VictoryRate);
                float diffB = Math.Abs(pl.WarData.VictoryRate - b.WarData.VictoryRate);

                if (diffA < diffB) //A优先
                {
                    return -1;
                }
                else if (diffA > diffB)
                {
                    return 1;
                }
            }

            return 0;
        }

        /// <summary>
        /// 在minCnt 与 MaxCnt 之间取一个随机值 值越大的几率越大
        /// </summary>
        /// <param name="minCnt">最小数量</param>
        /// <param name="maxCnt">最大数量</param>
        /// <returns></returns>
        int GetRandomQueueCnt(int minCnt, int maxCnt)
        {
            return BaseFun.random.Next(minCnt, maxCnt + 1);
        }
    }
}