/*
 * 作者:吴隆健
 * 日期: 2019-04-22
 * 时间: 13:20
 * 
 */

using System;
using Server.DB.Redis;
using StackExchange.Redis;
using MrWu.Debug;
using GameData;
using Server.Data;
using System.Data;
using Server.DB.Sql;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using GameMessage;
using Newtonsoft.Json;
using Server;

namespace GameDAL.FriendRoom
{
    /// <summary>
    /// 房间管理
    /// </summary>
    public static class Room
    {
        /// <summary>
        /// 战斗数据保存的文件夹  --服务器目录
        /// </summary>
        public const string RoomFightPath = "RoomFightPath";

        /// <summary>
        /// 密码
        /// </summary>
        public const string pwdField = "pwd";

        /// <summary>
        /// 最大玩家数量
        /// </summary>
        public const string maxCntField = "maxCnt";

        /// <summary>
        /// 最小玩家数量
        /// </summary>
        public const string minCntField = "minCnt";

        /// <summary>
        /// 朋友房多少局
        /// </summary>
        public const string warCntField = "warCnt";

        /// <summary>
        /// 当前开战的是第几场
        /// </summary>
        public const string nowCntField = "nowCnt";

        /// <summary>
        /// 结束的局数
        /// </summary>
        public const string overCntField = "overCnt";

        /// <summary>
        /// 房间所属游戏
        /// </summary>
        public const string gameidField = "gameid";

        /// <summary>
        /// 服务器版本
        /// </summary>
        public const string serverVerField = "serVer";

        /// <summary>
        /// 0普通开    1代开房间     5竞技比赛创建房间
        /// </summary>
        public const string CreateStyleField = "createStyle";

        /// <summary>
        /// 创建房间id  如果是普通创建房间 则此id为玩家userid 竞技比赛创建则为竞技比赛id
        /// </summary>
        public const string CreateIdField = "CreateId";

        /// <summary>
        /// 创建房间的房卡数量
        /// </summary>
        public const string fangkaField = "Fangka";

        /// <summary>
        /// 座位标记
        /// </summary>
        public const string seatTagField = "seatTag";

        /// <summary>
        /// 房间规则
        /// </summary>
        public const string roomRuleField = "RoomRule";

        /// <summary>
        /// 创建时间
        /// </summary>
        public const string CreateTimeField = "CreateTime";

        /// <summary>
        /// userid
        /// </summary>
        public const string useridField = "Userid";

        /// <summary>
        /// 昵称
        /// </summary>
        public const string nickNameField = "nickName";

        /// <summary>
        /// 性别
        /// </summary>
        public const string sexField = "sex";

        /// <summary>
        /// 头像
        /// </summary>
        public const string photoField = "photo";

        /// <summary>
        /// 房主
        /// </summary>
        public const string fangzhuField = "fangzhu";

        /// <summary>
        /// 战斗id
        /// </summary>
        public const string fightField = "fightid";

        /// <summary>
        /// 玩家的分值
        /// </summary>
        public const string scorejsonField = "playerScore";

        /// <summary>
        /// 战斗座位
        /// </summary>
        public const string fightseatField = "seat";

        /// <summary>
        /// 是否拦截ip
        /// </summary>
        public const string interceptIpField = "interceptIp";

        /// <summary>
        /// 是否拦截不是微信的账号
        /// </summary>
        public const string interceptWeChatField = "interceptWeChat";

        /// <summary>
        /// 是否关闭
        /// </summary>
        public const string isCloseField = "closeField";

        /// <summary>
        /// 关闭时间
        /// </summary>
        public const string closeTimeField = "closeTime";

        /// <summary>
        /// 房间号
        /// </summary>
        public const string roomNumField = "roomNum";

        /// <summary>
        /// 战斗超时时间
        /// </summary>
        public const string wartimeOutField = "warTimeOut";

        /// <summary>
        /// 加入超时时间
        /// </summary>
        public const string jointimeOutField = "jointimeOut";

        /// <summary>
        /// 玩法的id
        /// </summary>
        public const string wayidField = "wayid";

        /// <summary>
        /// 拓展字段
        /// </summary>
        public const string exField = "ex";

        /// <summary>
        /// 拓展字段
        /// </summary>
        public const string ruleexField = "ruleEx";

        /// <summary>
        /// 房间的最大数量
        /// </summary>
        public const int MaxCnt = 1000000;

        /// <summary>
        /// 是否保存战斗数据到数据库
        /// </summary>
        //public static bool IsSaveFightToDB = false;

        /// <summary>
        /// 房间分布式锁
        /// </summary>
        public static DistributedLock roomlock = new DistributedLock(100);

        /// <summary>
        /// 获的一个房间号
        /// </summary>
        /// <returns></returns>
        public static int GetRoomNum()
        {
            DateTime lastCreateTime = DateTime.Now;
            string lastCreateNum = "000000";

            try
            {
                var hes = redisManager.db.HashGetAll(RedisDictionary.lastRoomNum);

                if (hes != null && hes.Length > 0)
                {
                    foreach (var he in hes)
                    {
                        switch (he.Name)
                        {
                            case RedisDictionary.lastCreatRoomTime: //上次创建的时间
                                lastCreateTime = DateTime.Parse(he.Value);
                                break;
                            case RedisDictionary.lastRoomNum:
                                lastCreateNum = he.Value;
                                break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.Error("7B69BB45-9B1A-49DF-BC81-3370D8CEDE59:" + e.ToString());
            }

            int lastCreateNum_ = int.Parse(lastCreateNum);

            //时间差值，秒钟
            int betweenTime = (int)(DateTime.Now - lastCreateTime).TotalSeconds;

            //房间增量
            int deltanum = betweenTime / 10 % 1000;

            int roomNum_ = (lastCreateNum_ + deltanum) % MaxCnt;

            while (roomNum_ == lastCreateNum_ || roomNum_ == 0)
            {
                roomNum_++;
                roomNum_ = roomNum_ % MaxCnt;
            }

            try
            {
                HashEntry[] hhe = new HashEntry[2];
                hhe[0] = new HashEntry(RedisDictionary.lastCreatRoomTime, DateTime.Now.ToString());
                hhe[1] = new HashEntry(RedisDictionary.lastRoomNum, roomNum_);
                redisManager.db.HashSetAsync(RedisDictionary.lastRoomNum, hhe, CommandFlags.FireAndForget);
            }
            finally
            {
            }

            return roomNum_;
        }

        /// <summary>
        /// 获取朋友房数据的key
        /// </summary>
        /// <returns></returns>
        public static string GetWeiYiMaKey(string weiyima)
        {
            return RedisDictionary.friendRoomField + weiyima;
        }

        /// <summary>
        /// 获取朋友房中玩家数据key
        /// </summary>
        /// <param name="weiyima"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static string GetPlayerKey(string weiyima, int index)
        {
            return RedisDictionary.friendRoomField + weiyima + ":" + index;
        }

        /// <summary>
        /// 存储玩家所在的房间号以及唯一码
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public static string GetPlayerNumKey(int userid)
        {
            return "Game:FriendRoom:Player:" + userid;
        }

        /// <summary>
        /// 获取每局详情key
        /// </summary>
        /// <param name="weiyima"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static string GetBureauKey(string weiyima, int index)
        {
            return RedisDictionary.friendRoomField + weiyima + "." + index;
        }

        /// <summary>
        /// 设置当前开战次数
        /// </summary>
        /// <param name="deskinfo"></param>
        public static void SetNowCnt(DeskInfo deskinfo)
        {
            string key = GetWeiYiMaKey(deskinfo.weiyima);
            redisManager.db.HashSet(key, nowCntField, deskinfo.nowCnt);
        }

        /// <summary>
        /// 设置结束次数
        /// </summary>
        /// <param name="deskinfo"></param>
        public static void SetOverCnt(DeskInfo deskinfo)
        {
            string key = GetWeiYiMaKey(deskinfo.weiyima);
            redisManager.db.HashSet(key, overCntField, deskinfo.overCnt);
        }

        /// <summary>
        /// 加载房间号
        /// </summary>
        /// <param name="roomnum">房间号</param>
        /// <param name="weiyima">唯一码</param>
        /// <returns></returns>
        public static bool LoadPlayerNum(int userid, ref string roomnum, ref string weiyima)
        {
            string plNumKey = GetPlayerNumKey(userid);
            var hes = redisManager.db.HashGetAll(plNumKey);

            if (hes == null || hes.Length == 0)
                return false;

            int len = hes.Length;
            for (int i = 0; i < len; i++)
            {
                switch (hes[i].Name)
                {
                    case "num":
                        roomnum = hes[i].Value;
                        break;
                    case "weiyima":
                        weiyima = hes[i].Value;
                        break;
                }
            }

            return true;
        }

        /// <summary>
        /// 清楚玩家所在的房间号
        /// </summary>
        public static void ClearPlayerNum(int userid)
        {
            string plNumkey = GetPlayerNumKey(userid);
            redisManager.db.KeyDelete(plNumkey);
        }

        /// <summary>
        /// 获取房间的唯一码
        /// </summary>
        /// <param name="roomnum"></param>
        /// <returns></returns>
        public static bool GetWeiyima(int roomnum, ref string weiyima, ref ServerNode node)
        {
            string key = Roomkey(roomnum.ToString());

            var hes = redisManager.db.HashGetAll(key);
            if (hes == null || hes.Length == 0)
                return false;

            int len = hes.Length;
            for (int i = 0; i < len; i++)
            {
                switch (hes[i].Name)
                {
                    case "weiyima":
                        weiyima = hes[i].Value;
                        break;
                    case "server":
                        node = JsonPack.GetData<ServerNode>(hes[i].Value);
                        break;
                }
            }

            return true;
        }

        /// <summary>
        /// 保存玩家数据到redis中
        /// </summary>
        /// <param name="dskinfo"></param>
        /// <param name="index"></param>
        public static bool SavePlayerToRedis(DeskInfo dskinfo, int index)
        {
            DeskInfo.PlayerData pl = dskinfo.pls[index];
            if (pl == null)
            {
                Debug.Error("程序错误....playerdata is null index:{0}", index);
                return false;
            }

            string plNumKey = GetPlayerNumKey(pl.userid);
            string key = GetPlayerKey(dskinfo.weiyima, index);

            IDatabase db = redisManager.GetDataBase();

            var tran = db.CreateTransaction();

            tran.AddCondition(Condition.KeyNotExists(plNumKey));
            tran.AddCondition(Condition.KeyNotExists(key));
            
            var numhes = new HashEntry[2];
            numhes[0] = new HashEntry("num", dskinfo.roomNum); //房间号
            numhes[1] = new HashEntry("weiyima", dskinfo.weiyima); //唯一码
            tran.HashSetAsync(plNumKey, numhes); //保存玩家的房间号以及唯一码

            HashEntry[] hes = new HashEntry[6];
            hes[0] = new HashEntry(useridField, pl.userid);
            hes[1] = new HashEntry(fangzhuField, pl.fangzhu);
            if (pl.nickName == null)
                pl.nickName = string.Empty;
            hes[2] = new HashEntry(nickNameField, pl.nickName);
            if (pl.photo == null)
                pl.photo = string.Empty;
            hes[3] = new HashEntry(photoField, pl.photo);
            hes[4] = new HashEntry(sexField, pl.sex);
            hes[5] = new HashEntry("clubid", pl.ClubId);
            tran.HashSetAsync(key, hes); //保存玩家数据


            key = GetWeiYiMaKey(dskinfo.weiyima);
            Debug.Info("key1:" + key + "," + plNumKey);
            tran.AddCondition(Condition.KeyExists(key));
            tran.HashSetAsync(key, seatTagField, JsonPack.GetJson(dskinfo.seat)); //保存房间数据中的座位信息

            Debug.Log("key2:" + key);

            return tran.Execute();
        }

        /// <summary>
        /// 从redis中清楚玩家数据
        /// </summary>
        /// <param name="dskinfo"></param>
        /// <param name="index"></param>
        public static bool ClearPlayerToRedis(DeskInfo dskinfo, int index, int userid)
        {
            string key = GetPlayerKey(dskinfo.weiyima, index);

            var db = redisManager.GetDataBase();

            var tran = db.CreateTransaction();

            tran.KeyDeleteAsync(key); //清空玩家数据

            key = GetPlayerNumKey(userid);
            tran.KeyDeleteAsync(key);

            key = GetWeiYiMaKey(dskinfo.weiyima);
            tran.AddCondition(Condition.KeyExists(key));
            tran.HashSetAsync(key, seatTagField, JsonPack.GetJson(dskinfo.seat));

            return tran.Execute();
        }

        /// <summary>
        /// 保存单局详情_修改及保存
        /// </summary>
        /// <param name="deskinfo">桌子信息</param>
        /// <param name="index"></param>
        public static void SaveBureau(DeskInfo deskinfo, int index)
        {
            string key = GetBureauKey(deskinfo.weiyima, index);

            redisManager.db.StringSet(key, JsonPack.GetJson(deskinfo.burs[index]));
        }
        
        /// <summary>
        /// 保存牌局数据包
        /// </summary>
        /// <param name="weiyima"></param>
        /// <param name="data"></param>
        public static void SaveFightData(string weiyima, byte[] data)
        {
            FightDataManager.Instance.SaveFightData(weiyima,data);
        }

        public static void DelFightData(string weiyima)
        {
            FightDataManager.Instance.DelFightData(weiyima);
        }

        /// <summary>
        /// 加载牌局数据包
        /// </summary>
        /// <param name="weiyima"></param>
        /// <returns></returns>
        public static byte[] LoadFightData(string weiyima,out bool isOld)
        {
            byte[] data = FightDataManager.Instance.LoadFightData(weiyima,out isOld);
            return data;
        }

        /// <summary>
        /// 加载战斗记录-回放用 --- todo 改成二进制存储
        /// </summary>
        /// <param name="weiyima">朋友房唯一码</param>
        /// <param name="playCnt">玩的场次</param>
        /// <param name="data">战斗数据</param>
        public static void LoadFightRecord(string weiyima, int playCnt, out FightData data)
        {
            string key = RedisDictionary.friendRoomfightRecord + playCnt + ":" + weiyima;

            //先找文本
            string fileName = $"fightRecord/{key}";
            fileName = fileName.Replace(":", "");
            if (File.Exists(fileName))
            {
                try
                {

                    string jsonData = File.ReadAllText(fileName);
                    data = JsonConvert.DeserializeObject<FightData>(jsonData);
                    File.Delete(fileName);
                    Debug.Info("读取回放数据!!");
                    return;
                }
                catch (Exception e)
                {
                    Debug.Error($"加载战绩报错!{weiyima},{playCnt}" + e.Message);
                }
            }
            
            var values = redisManager.db.ListRange(key);
            if (values == null || values.Length == 0)
            {
                data = new FightData();
                return;
            }
            else
            {
                data = new FightData();
                try
                {
                    int len = values.Length;
                    for (int i = 1; i < len; i++)
                    {
                        var dataone = JsonPack.GetData<fightdataone>(values[i]);
                        data.fightPack.Add(dataone);
                    }
                }
                catch (Exception e)
                {
                    Debug.Error($"加载战斗数据-出现错误!!! {e.Message}");
                }
            }
        }

        
        /// <summary>
        /// 设置总结算
        /// </summary>
        public static void SetSumBurs(DeskInfo deskinfo)
        {
            if (deskinfo == null) return;
            //if (!deskinfo.isAllOver) return;
            if (deskinfo.seat == null || deskinfo.seat.Length <= 0 || deskinfo.burs == null ||
                deskinfo.burs.Count <= 0) return;
            try
            {
                deskinfo.SumBurs.Clear();
                int[] seat = new int[deskinfo.seat.Length];
                decimal[] score = new decimal[seat.Length];
                for (int i = 0; i < deskinfo.seat.Length; i++)
                {
                    seat[i] = deskinfo.seat[i];
                    var num = deskinfo.GetTotalScore(seat[i]);
                    score[i] = num * (decimal)deskinfo.rule.peilv;
                }

                score = CalcCapping(score, deskinfo.rule.Capping);
                for (int i = 0; i < seat.Length; i++)
                {
                    DeskInfo.SummaryBureau temp = new DeskInfo.SummaryBureau { seat = seat[i], Score = score[i] };
                    deskinfo.SumBurs.Add(temp);
                }
            }
            catch (Exception e)
            {
                Debug.Error($"SetSumBurs error:{e.Message},code:{e.StackTrace},Data info");
            }
        }

        /// <summary>
        /// 计算超过封顶的玩家，让赢的玩家均摊
        /// </summary>
        /// <param name="playScore"></param>
        /// <param name="capping"></param>
        /// <returns></returns>
        public static decimal[] CalcCapping(decimal[] playScore, int capping)
        {
            if (capping <= 0) return playScore;
            int len = playScore.Length;
            decimal zongDuo = 0; //输的多出来的总数
            decimal zongShu = 0; //超过封顶的玩家 输的总数            
            List<int> winIdx = new List<int>(); //赢钱人的下标
            List<decimal> winJian = new List<decimal>(); //存储赢钱人平均摊的数值
            for (int i = 0; i < len; i++)
            {
                var temp = Math.Abs(playScore[i]);
                if (playScore[i] < 0 && temp > capping)
                {
                    zongDuo += temp - capping;
                    playScore[i] = 0 - capping;
                }

                if (playScore[i] > 0)
                {
                    zongShu += playScore[i];
                    winIdx.Add(i);
                }
            }

            for (int i = 0; i < winIdx.Count - 1; i++)
            {
                var temp = zongDuo * playScore[winIdx[i]] / zongShu;
                winJian.Add(Math.Round(temp, 2));
            }

            var temp1 = zongDuo - winJian.Sum();
            winJian.Add(temp1);
            for (int i = 0; i < winIdx.Count; i++)
            {
                playScore[winIdx[i]] = playScore[winIdx[i]] - winJian[i];
            }

            return playScore;
        }
        
        /// <summary>
        /// 根据唯一码获取房间号
        /// </summary>
        /// <param name="weiyima">唯一码</param>
        /// <returns>房间号</returns>
        public static string GetRoomNum(string weiyima)
        {
            string key = GetWeiYiMaKey(weiyima);

            return redisManager.db.HashGet(key, roomNumField);
        }

        /// <summary>
        /// 加载房间数据_当前房间
        /// </summary>
        /// <param name="weiyima">唯一码</param>
        /// <param name="data">房间数据</param>
        /// <returns>是否加载成功</returns>
        public static bool LoadRoom(string weiyima, out DeskInfo data)
        {
            string key = GetWeiYiMaKey(weiyima);

            data = new DeskInfo();

            DeskInfo dt = data;
            dt.rule = new DeskRule();
            DeskRule rule = dt.rule;

            Func<bool> func = () =>
            {
                dt.weiyima = weiyima;
                try
                {
                    //获取朋友房数据   //朋友房基本数据
                    HashEntry[] hes = redisManager.db.HashGetAll(key);
                    if (hes == null || hes.Length <= 0)
                        return false;
                    foreach (var he in hes)
                    {
                        switch (he.Name)
                        {
                            case roomNumField:
                                dt.roomNum = he.Value;
                                break;
                            case pwdField:
                                rule.pwd = he.Value;
                                break;
                            case maxCntField:
                                rule.maxCnt = int.Parse(he.Value);
                                break;
                            case minCntField:
                                rule.minCnt = int.Parse(he.Value);
                                break;
                            case warCntField:
                                rule.warCnt = int.Parse(he.Value);
                                break;
                            case exField:
                                var ex = JsonPack.GetData<string[]>(he.Value);
                                rule.ex = ex;
                                break;
                            case ruleexField:
                                var exstr = he.value;
                                rule.RuleEx = string.IsNullOrEmpty(exstr)
                                    ? new DeskRuleEx()
                                    : JsonPack.GetData<DeskRuleEx>(exstr);
                                break;
                            case "peilv":
                                rule.peilv = float.Parse(he.Value);
                                break;
                            case "Capping":
                                rule.Capping = int.Parse(he.value);
                                break;
                            case "Remarks":
                                rule.Remarks = he.value;
                                break;
                            case overCntField:
                                dt.overCnt = int.Parse(he.Value);
                                break;
                            case gameidField:
                                rule.game_serid = int.Parse(he.Value);
                                break;
                            case serverVerField:
                                dt.serverVer = int.Parse(he.Value);
                                break;
                            case CreateStyleField:
                                dt.creatStyle = int.Parse(he.Value);
                                break;
                            case CreateIdField:
                                dt.creatUserid = int.Parse(he.Value);
                                break;
                            case fangkaField:
                                dt.fangka = int.Parse(he.Value);
                                break;

                            case seatTagField:
                                dt.seat = JsonPack.GetData<int[]>(he.Value);
                                Debug.Info("座位号:" + he.Value);
                                break;
                            case roomRuleField:
                                dt.rule.roomrule = he.Value;
                                break;
                            case CreateTimeField:
                                dt.CreateTime = DateTime.Parse(he.Value);
                                break;
                            case nowCntField:
                                dt.nowCnt = int.Parse(he.Value);
                                break;
                            case interceptIpField:
                                rule.interceptIp = int.Parse(he.Value);
                                break;
                            case interceptWeChatField:
                                rule.interceptWeChat = int.Parse(he.Value);
                                break;
                            case isCloseField:
                                dt.isClose = int.Parse(he.Value);
                                break;
                            case closeTimeField:
                                dt.closeTime = DateTime.Parse(he.Value);
                                break;
                            case jointimeOutField:
                                dt.jointimeOutDis = DateTime.Parse(he.Value);
                                break;
                            case wartimeOutField:
                                dt.wartimeOutDis = DateTime.Parse(he.Value);
                                break;
                            case wayidField:
                                dt.wayid = he.Value;
                                break;
                        }
                    }

                    //RedisDictionary.friendRoomPlayerField+

                    dt.pls = new DeskInfo.PlayerData[rule.maxCnt];
                    dt.OnceFight = new int[rule.maxCnt];
                    for (int i = 0; i < rule.maxCnt; i++)
                    {
                        //加载玩家数据
                        string
                            plkey = GetPlayerKey(weiyima, i); // RedisDictionary.friendRoomPlayerField + weiyima+"."+i;

                        HashEntry[] plhes = redisManager.db.HashGetAll(plkey);

                        if (plhes == null || plhes.Length <= 0)
                        {
                            dt.pls[i] = null;
                        }
                        else
                        {
                            dt.pls[i] = new DeskInfo.PlayerData();
                            foreach (HashEntry he in plhes)
                            {
                                switch (he.Name)
                                {
                                    case useridField:
                                        dt.pls[i].userid = int.Parse(he.Value);
                                        break;
                                    case nickNameField:
                                        dt.pls[i].nickName = he.Value;
                                        break;
                                    case sexField:
                                        dt.pls[i].sex = int.Parse(he.Value);
                                        break;
                                    case photoField:
                                        dt.pls[i].photo = he.Value;
                                        break;
                                    case fangzhuField:
                                        dt.pls[i].fangzhu = int.Parse(he.Value);
                                        break;
                                    case "clubid":
                                        dt.pls[i].ClubId = int.Parse(he.Value);
                                        break;
                                }
                            }
                        }
                    }

                    //加载战斗记录
                    int cnt = dt.nowCnt != 0 ? dt.nowCnt : dt.overCnt;
                    for (int i = 0; i < cnt; i++)
                    {
                        string fightkey = GetBureauKey(weiyima, i); // RedisDictionary.friendRoomField+weiyima+i;

                        DeskInfo.Bureau bru = new DeskInfo.Bureau();
                        bru.id = i;

                        string jsonfihtrecord = redisManager.db.StringGet(fightkey);
                        if (jsonfihtrecord != null)
                            bru = JsonPack.GetData<DeskInfo.Bureau>(jsonfihtrecord);

                        dt.burs.Add(bru);
                    }

                    Debug.Info("桌子加载成功!");

                    return true;
                }
                catch (Exception e)
                {
                    Debug.Error("加载房间号错误:" + e.ToString());
                    return false;
                }
            };

            bool r = roomlock.LockRun(key, func, 5);
            data.plsDis = new int[data.rule.maxCnt];
            Room.SetSumBurs(data);
            return r;
        }

        //创建房间移除房间修改房间只能又一个程序处理 其他程序只能读数据，不能改数据

        /// <summary>
        /// 创建房间  只负责redis数据
        /// </summary>
        /// <param name="data"></param>
        public static bool CreateRoom(DeskInfo data, ServerNode node)
        {
            //房间号-> 唯一码 - 管理的模块
            //朋友房的房间信息

            //保证数据一致性

            //先写房间号 - 唯一码 - 管理模块

            string roomnum = data.roomNum;
            string weiyima = data.weiyima;

            //不存在才可以改,存在，不能改
            var db = redisManager.GetDataBase();

            string key = Roomkey(roomnum);
            string datakey = RedisDictionary.friendRoomField + data.weiyima;

            var tran = db.CreateTransaction();
            tran.AddCondition(Condition.KeyNotExists(key)); //不存在才能执行事务
            tran.AddCondition(Condition.KeyNotExists(datakey));

            HashEntry[] hes = new HashEntry[2];
            hes[0] = new HashEntry("weiyima", weiyima);
            hes[1] = new HashEntry("server", JsonPack.GetJson(node));
            tran.HashSetAsync(key, hes);

            var datahes = GetDeskInfoHashEntry(data);


            tran.HashSetAsync(datakey, datahes.ToArray()); //保存朋友房数据

            Debug.Info("创建朋友房:" + key + "," + datakey);

            return tran.Execute();
        }

        /// <summary>
        /// 获取桌子信息
        /// </summary>
        private static List<HashEntry> GetDeskInfoHashEntry(DeskInfo data)
        {
            List<HashEntry> datahes = new List<HashEntry>();
            datahes.Add(new HashEntry(roomNumField, data.roomNum));
            DeskRule rule = data.rule;
            if (rule.pwd == null)
                rule.pwd = string.Empty;
            datahes.Add(new HashEntry(pwdField, rule.pwd));
            datahes.Add(new HashEntry(maxCntField, rule.maxCnt));
            datahes.Add(new HashEntry(minCntField, rule.minCnt));
            datahes.Add(new HashEntry(warCntField, rule.warCnt));
            datahes.Add(new HashEntry(nowCntField, data.nowCnt));
            datahes.Add(new HashEntry(overCntField, data.overCnt));
            datahes.Add(new HashEntry(gameidField, rule.game_serid));
            datahes.Add(new HashEntry(serverVerField, data.serverVer));
            datahes.Add(new HashEntry(CreateStyleField, data.creatStyle));
            datahes.Add(new HashEntry(CreateIdField, data.creatUserid));
            datahes.Add(new HashEntry(fangkaField, data.fangka));
            datahes.Add(new HashEntry(seatTagField, JsonPack.GetJson(data.seat)));
            datahes.Add(new HashEntry(roomRuleField, data.rule.roomrule));
            datahes.Add(new HashEntry(CreateTimeField, data.CreateTime.ToString()));
            datahes.Add(new HashEntry(interceptIpField, rule.interceptIp));
            datahes.Add(new HashEntry(interceptWeChatField, rule.interceptWeChat));
            datahes.Add(new HashEntry(isCloseField, data.isClose));
            datahes.Add(new HashEntry(closeTimeField, data.closeTime.ToString()));
            datahes.Add(new HashEntry(exField, JsonPack.GetJson(data.rule.ex)));
            datahes.Add(new HashEntry(ruleexField, data.rule.RuleExStr));
            datahes.Add(new HashEntry("peilv", rule.peilv));
            datahes.Add(new HashEntry("Capping", rule.Capping));
            datahes.Add(new HashEntry("Remarks", rule.Remarks == null ? "" : rule.Remarks.ToString()));
            datahes.Add(new HashEntry(wartimeOutField, data.wartimeOutDis.ToString()));
            datahes.Add(new HashEntry(jointimeOutField, data.jointimeOutDis.ToString()));
            if (data.wayid != null)
                datahes.Add(new HashEntry(wayidField, data.wayid.ToString()));
            return datahes;
        }

        /// <summary>
        /// 重新写入房间
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static bool RenewRoom(DeskInfo data)
        {
            string roomnum = data.roomNum;
            string weiyima = data.weiyima;

            //不存在才可以改,存在，不能改
            var db = redisManager.GetDataBase();
            string key = Roomkey(roomnum);
            string datakey = RedisDictionary.friendRoomField + data.weiyima;

            var datahes = GetDeskInfoHashEntry(data);
            db.HashSetAsync(datakey, datahes.ToArray()); //保存朋友房数据

            return true;
        }

        /// <summary>
        /// 移除房间  ->先删房间主体->删除房间玩家数据->玩家详情
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static bool DeleteRoom(DeskInfo data)
        {
            if (!data.noWar)
            {
                //开战过保存到数据库
                Task.Factory.StartNew(() =>
                {
                    SaveRoomData(data);
                    SaveRoomPlayerData(data);
                });
            }

            var db = redisManager.GetDataBase();

            var tran = db.CreateTransaction();

            //删除玩家的被锁的 房间号-对应的唯一码
            //删除房间号-被锁的唯一码
            //删除房间详细数据
            //删除玩家数据
            //删除每局详情,删除玩家详情

            string key = Roomkey(data.roomNum);
            tran.KeyDeleteAsync(key); //房间号-对应的唯一码

            int len = data.pls.Length;

            for (int i = 0; i < len; i++)
            {
                if (data.pls[i] == null) continue;
                string plkey = GetPlayerNumKey(data.pls[i].userid);
                tran.KeyDeleteAsync(plkey); //清楚玩家所在的房间号以及对应的唯一码
                int index = -1;
                int count = data.seat.Length; //玩家玩家详细数据
                for (int j = 0; j < count; j++)
                {
                    if (data.seat[j] == i)
                    {
                        index = i;
                        break;
                    }
                }

                if (index < 0)
                {
                    Debug.Error("未找到玩家位置!");
                    continue;
                }

                string pldatakey = GetPlayerKey(data.weiyima, index);
                tran.KeyDeleteAsync(pldatakey);
            }

            //删除房间详细数据

            string datakey = RedisDictionary.friendRoomField + data.weiyima;
            tran.KeyDeleteAsync(datakey);

            DelFightData(data.weiyima);
            // string fightdatakey = GetFightDataKey(data.weiyima);
            // tran.KeyDeleteAsync(fightdatakey);

            //Debug.Error("解散游戏数据!" + data.overCnt + "," + fightdatakey);

            for (int i = 0; i < data.overCnt + 1; i++)
            {
                string bureaukey = GetBureauKey(data.weiyima, i);
                tran.KeyDeleteAsync(bureaukey);
            }

            return tran.Execute();
        }

        /// <summary>
        /// 保存房间基本数据
        /// </summary>
        static void SaveRoomData(DeskInfo data)
        {
            DeskRule rule = data.rule;
            var sql = GameDB.Instance.BeginSetProcedureParameter(dbbase.game2018, "SaveRoomData202408");
            GameDB.Instance.AddProdureParameters(sql, "@weiyima", SqlDbType.Char, data.weiyima);
            GameDB.Instance.AddProdureParameters(sql, "@roomnum", SqlDbType.Char, data.roomNum);
            GameDB.Instance.AddProdureParameters(sql, "@maxcnt", SqlDbType.Int, rule.maxCnt);
            GameDB.Instance.AddProdureParameters(sql, "@mincnt", SqlDbType.Int, rule.minCnt);
            GameDB.Instance.AddProdureParameters(sql, "@warcnt", SqlDbType.Int, rule.warCnt);
            GameDB.Instance.AddProdureParameters(sql, "@nowcnt", SqlDbType.Int, data.nowCnt);
            GameDB.Instance.AddProdureParameters(sql, "@overcnt", SqlDbType.Int, data.overCnt);
            GameDB.Instance.AddProdureParameters(sql, "@gameid", SqlDbType.Int, rule.game_serid);
            GameDB.Instance.AddProdureParameters(sql, "@serverVer", SqlDbType.Int, data.serverVer);
            GameDB.Instance.AddProdureParameters(sql, "@createStyle", SqlDbType.Int, data.creatStyle);
            GameDB.Instance.AddProdureParameters(sql, "@createid", SqlDbType.Int, data.creatUserid);
            GameDB.Instance.AddProdureParameters(sql, "@fangka", SqlDbType.Int, data.fangka);
            GameDB.Instance.AddProdureParameters(sql, "@interceptIp", SqlDbType.Int, rule.interceptIp);
            GameDB.Instance.AddProdureParameters(sql, "@interceptWeChat", SqlDbType.Int, rule.interceptWeChat);

            byte[] bts = System.Text.Encoding.UTF8.GetBytes(data.rule.roomrule);
            GameDB.Instance.AddProdureParameters(sql, "@roomrule", SqlDbType.Image, bts); //json的base64数据

            GameDB.Instance.AddProdureParameters(sql, "@createTime", SqlDbType.DateTime, data.CreateTime);
            GameDB.Instance.AddProdureParameters(sql, "@closeTime", SqlDbType.DateTime, data.closeTime);
            GameDB.Instance.AddProdureParameters(sql, "@ex", SqlDbType.Text, JsonPack.GetJson(data.rule.ex));

            GameDB.Instance.AddProdureParameters(sql, "@ruleEx", SqlDbType.Text, data.rule.RuleExStr);

            GameDB.Instance.AddProdureParameters(sql, "@peilv", SqlDbType.Float, rule.peilv);
            GameDB.Instance.AddProdureParameters(sql, "@Capping", SqlDbType.Int, rule.Capping);
            GameDB.Instance.AddProdureParameters(sql, "@Remarks", SqlDbType.VarChar,
                rule.Remarks == null ? "" : rule.Remarks);
            GameDB.Instance.EndAddProdureParameters(sql);
        }

        /// <summary>
        /// 保存玩家数据
        /// </summary>
        static void SaveRoomPlayerData(DeskInfo data)
        {
            int len = data.pls.Length;
            for (int i = 0; i < len; i++)
            {
                if (data.pls[i] == null) continue; //这个位置没人

                var sql = GameDB.Instance.BeginSetProcedureParameter(dbbase.game2018, "SaveRoom_PlayerData2024");
                GameDB.Instance.AddProdureParameters(sql, "@weiyima", SqlDbType.Char, data.weiyima);
                GameDB.Instance.AddProdureParameters(sql, "@playeridx", SqlDbType.Int, i);
                GameDB.Instance.AddProdureParameters(sql, "@userid", SqlDbType.Int, data.pls[i].userid);
                GameDB.Instance.AddProdureParameters(sql, "@nickName", SqlDbType.NChar, data.pls[i].nickName);
                GameDB.Instance.AddProdureParameters(sql, "@sex", SqlDbType.Int, data.pls[i].sex);
                GameDB.Instance.AddProdureParameters(sql, "@clubid", SqlDbType.Int, data.pls[i].ClubId);

                byte[] bts = Encoding.UTF8.GetBytes(data.pls[i].photo);
                GameDB.Instance.AddProdureParameters(sql, "@photo", SqlDbType.Image, bts);
                GameDB.Instance.AddProdureParameters(sql, "@fangzhu", SqlDbType.Int, data.pls[i].fangzhu);

                long allScore = 0;
                foreach (var item in data.burs)
                {
                    allScore += item.playScore[i];
                }

                GameDB.Instance.AddProdureParameters(sql, "@allScore", SqlDbType.Int, allScore);
                GameDB.Instance.AddProdureParameters(sql, "@gameid", SqlDbType.Int, data.rule.game_serid);
                GameDB.Instance.EndAddProdureParameters(sql);
            }
        }

        /// <summary>
        /// 保存战斗数据
        /// </summary>
        /// <param name="deskinfo"></param>
        /// <param name="data"></param>
        /// <param name="style">结束类型</param>
        public static void SaveFightRecord(DeskInfo deskinfo, FightData data, int style = -1)
        {
            //ClearFightRecord(deskinfo.weiyima, deskinfo.burs.Count);
            if (data == null)
                return;
            Debug.Info("保存战斗记录到数据库!");
            //string jsondata = JsonPack.GetJson(data);
            int idx = deskinfo.burs.Count;
            int index = idx - 1;
            if (index < 0)
            {
                Debug.Warning("未开战过,无需保存!");
                return;
            }

            int lx = deskinfo.creatStyle;
            var playScore = deskinfo.burs[index].playScore;
            //string score = JsonPack.GetJson(playScore);
            var seatd = deskinfo.burs[index].seat;
            //string seat = JsonPack.GetJson(seatd);
            string weiyima = deskinfo.weiyima;
            
            if (lx == 5 || lx == 0)
            {
                RoomFightData temp = new RoomFightData { playScore = playScore, seat = seatd, data = data, style = style };
                FightRecordManager.Instance.SaveFightInfo(weiyima, temp, idx);
            }
        }

        /// <summary>
        /// 房间号key 里面保存着，管理房间的模块以及房间号对应的唯一码
        /// </summary>
        /// <param name="roomnum">房间号</param>
        /// <returns>返回值</returns>
        public static string Roomkey(string roomnum)
        {
            return "Game:FriendRoom:RoomNum:" + roomnum;
        }

        public static string GetClubFightKey(int userId)
        {
            return $"ClubFightLock:{userId}";
        }

        /// <summary>
        /// 锁住俱乐部玩家
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="serId"></param>
        public static void LockClubFightPlayer(List<int> userid, int serId)
        {
            try
            {
                var ts = TimeSpan.FromHours(1);
                IBatch batch = redisManager.db.CreateBatch();
                for (int i = 0; i < userid.Count; i++)
                {
                    batch.StringSetAsync(GetClubFightKey(userid[i]), serId, ts);
                }
                batch.Execute();
            }
            catch (Exception e)
            {
                Debug.Error($"LockClubFightPlayer Error:{e.Message}");
            }
        }


    }
}