using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using MrWu;
using System.Threading.Tasks;
using MrWu.Debug;
using Newtonsoft.Json;
using Server.Core;

namespace Server
{
    /// <summary>
    /// 位置胜率，胜率最高者，胜率最低者，金额最高者，金额最低者
    /// </summary>
    public class FriendRoomStatistics : SingleInstance<FriendRoomStatistics>
    {
        private readonly object lockObj = new object();

        /// <summary>
        /// 上一天的统计数据
        /// </summary>
        private Dictionary<string, WayStatics> LastDayWayStaticsList = new Dictionary<string, WayStatics>();

        /// <summary>
        /// 玩法数据统计
        /// </summary>
        private Dictionary<string, WayStatics> WayStaticsMap = new Dictionary<string, WayStatics>();

        private Timer _timer;

        /// <summary>
        /// 下次发送通知的时间
        /// </summary>
        private long NextSendNotice;

        private string gameName;

        public FriendRoomStatistics()
        {
            LoadData();
            GameDispatcher.Instance.AddListener(GameMsgId.DayChange, OnDayChange);
            _timer = new Timer(OnTimer, null, 1000, 60 * 1000);
            SetNextNotice();
        }

        public void Start()
        {
            gameName = ServerConfigManager.Instance.GameName;
        }

        private void OnTimer(object state)
        {
            if (TimeInfo.Instance.FrameTime > NextSendNotice)
            {
                SetNextNotice();
                SendNotice();
            }
        }

        private void SetNextNotice()
        {
            int hour = 9;
            if (DateTime.Now >= DateTime.Today.AddHours(hour))
            {
                hour += 24;
            }

            NextSendNotice = TimeInfo.Instance.TransitionLocationDateTime(DateTime.Today.AddHours(hour));
        }

        private const float Median = 0.5f;

        /// <summary>
        /// 发送上一天的通知
        /// </summary>
        private void SendNotice()
        {
            StringBuilder stringBuilder = null;
            List<string> lines = new List<string>();
            lock (lockObj)
            {
                if (LastDayWayStaticsList.Count <= 0)
                {
                    return;
                }

                stringBuilder = new StringBuilder();

                //统计座位
                foreach (var kv in LastDayWayStaticsList)
                {
                    if (kv.Value.PlayerStaticsMap.Count <= 0)
                    {
                        continue;
                    }

                    stringBuilder.Clear();
                    stringBuilder.AppendLine($"{gameName}统计报告:");
                    stringBuilder.AppendLine();
                    stringBuilder.AppendLine($"{kv.Value.WayId} 倍率:{kv.Value.BeiLv}");
                    foreach (var seatKv in kv.Value.SeatStaticsMap)
                    {
                        if (seatKv.Value.TotalCnt <= 0)
                        {
                            continue;
                        }

                        float WinningRate = (float)seatKv.Value.WinCnt / seatKv.Value.TotalCnt;
                        stringBuilder.AppendLine($"座位{seatKv.Value.Seat} 胜率:%{(WinningRate * 100):f2}");
                    }

                    stringBuilder.AppendLine($"玩家人数:{kv.Value.PlayerStaticsMap.Count}");

                    //最高胜率
                    PlayerStatics maxWinningRatePlayerStatics = null;
                    float maxWinningRate = 0f;
                    PlayerStatics minWinningRatePlayerStatics = null;
                    //最低胜率
                    float minWinningRate = 1f;

                    //最高场次胜率
                    PlayerStatics maxSessionWinningRatePlayerStatics = null;
                    float maxSessionWinningRate = 0f;
                    //最低场次胜率
                    PlayerStatics minSessionWinningRatePlayerStatics = null;
                    float minSessionWinningRate = 1f;

                    //最高分
                    PlayerStatics maxScorePlayerStatics = null;
                    int maxScore = 0;
                    //最低分
                    PlayerStatics minScorePlayerStatics = null;
                    int minScore = int.MaxValue;

                    foreach (var playerKv in kv.Value.PlayerStaticsMap)
                    {
                        if (playerKv.Value.TotalCnt > 20) //大于20局才统计
                        {
                            float winningRate = (float)playerKv.Value.WinCnt / playerKv.Value.TotalCnt;
                            if (winningRate > maxWinningRate)
                            {
                                maxWinningRate = winningRate;
                                maxWinningRatePlayerStatics = playerKv.Value;
                            }

                            if (winningRate < Median && winningRate < minWinningRate)
                            {
                                minWinningRate = winningRate;
                                minWinningRatePlayerStatics = playerKv.Value;
                            }
                        }

                        if (playerKv.Value.TotalSessionCnt > 10) //大于10局才统计
                        {
                            float winningRate = (float)playerKv.Value.WinSessionCnt / playerKv.Value.TotalSessionCnt;
                            if (winningRate > Median && winningRate > maxSessionWinningRate)
                            {
                                maxSessionWinningRate = winningRate;
                                maxSessionWinningRatePlayerStatics = playerKv.Value;
                            }

                            if (winningRate < Median && winningRate < minSessionWinningRate)
                            {
                                minSessionWinningRate = winningRate;
                                minSessionWinningRatePlayerStatics = playerKv.Value;
                            }
                        }

                        if (playerKv.Value.TotalSessionScore > maxScore)
                        {
                            maxScore = (int)playerKv.Value.TotalSessionScore;
                            maxScorePlayerStatics = playerKv.Value;
                        }

                        if (playerKv.Value.TotalSessionScore < minScore)
                        {
                            minScore = (int)playerKv.Value.TotalSessionScore;
                            minScorePlayerStatics = playerKv.Value;
                        }
                    }

                    //最高胜率
                    if (maxWinningRatePlayerStatics != null)
                    {
                        stringBuilder.AppendLine(
                            $"最高胜率:%{(maxWinningRate * 100):f2}");
                        stringBuilder.AppendLine(
                            $"  玩家:{maxWinningRatePlayerStatics.UserId} 局数:{maxWinningRatePlayerStatics.TotalCnt} 幸运次数:{maxWinningRatePlayerStatics.LuckCnt} 霉运次数:{maxWinningRatePlayerStatics.BadLuckCnt}");
                    }

                    if (minWinningRatePlayerStatics != null)
                    {
                        stringBuilder.AppendLine(
                            $"最低胜率:%{(minWinningRate * 100):f2}");
                        stringBuilder.AppendLine(
                            $"  玩家:{minWinningRatePlayerStatics.UserId} 局数:{minWinningRatePlayerStatics.TotalCnt} 幸运次数:{minWinningRatePlayerStatics.LuckCnt} 霉运次数:{minWinningRatePlayerStatics.BadLuckCnt}");
                    }

                    if (maxSessionWinningRatePlayerStatics != null)
                    {
                        stringBuilder.AppendLine(
                            $"场次最高胜率:%{(maxSessionWinningRate * 100):f2}");
                        stringBuilder.AppendLine(
                            $"  玩家:{maxSessionWinningRatePlayerStatics.UserId} 场次:{maxSessionWinningRatePlayerStatics.TotalSessionCnt} 幸运次数:{maxSessionWinningRatePlayerStatics.LuckCnt} 霉运次数:{maxSessionWinningRatePlayerStatics.BadLuckCnt}");
                    }

                    if (minSessionWinningRatePlayerStatics != null)
                    {
                        stringBuilder.AppendLine(
                            $"场次最低胜率:%{(minSessionWinningRate * 100):f2}");
                        stringBuilder.AppendLine(
                            $"  玩家:{minSessionWinningRatePlayerStatics.UserId} 场次:{minSessionWinningRatePlayerStatics.TotalSessionCnt} 幸运次数:{minSessionWinningRatePlayerStatics.LuckCnt} 霉运次数:{minSessionWinningRatePlayerStatics.BadLuckCnt}");
                    }

                    if (maxScorePlayerStatics != null)
                    {
                        stringBuilder.AppendLine($"最高分:{maxScore}");
                        stringBuilder.AppendLine(
                            $"  玩家:{maxScorePlayerStatics.UserId} 幸运次数:{maxScorePlayerStatics.LuckCnt} 霉运次数:{maxScorePlayerStatics.BadLuckCnt}");
                    }

                    if (minScorePlayerStatics != null)
                    {
                        stringBuilder.AppendLine($"最低分:{minScore}");
                        stringBuilder.AppendLine(
                            $"  玩家:{minScorePlayerStatics.UserId} 幸运次数:{minScorePlayerStatics.LuckCnt} 霉运次数:{minScorePlayerStatics.BadLuckCnt}");
                    }
                    
                    lines.Add(stringBuilder.ToString());
                }
            }

            foreach (var line in lines)
            {
                if (!string.IsNullOrEmpty(line))
                {
                    WeChatRobotManager.Instance.SendMsg(line, WeChatRobotManager.RobotType.StatisticsReport);
                }
            }
        }

        private void LoadData()
        {
            try
            {
                //加载昨天和今天的数据
                LoadData(DateTime.Now.AddDays(-1), LastDayWayStaticsList);
                LoadData(DateTime.Now, WayStaticsMap);
            }
            catch (Exception e)
            {
                Debug.Error($"加载失败！ {e.Message}");
            }
        }

        public void AddBalance(string wayId, int luckUserId, int badLuckUserId)
        {
            if (luckUserId <= 0 && badLuckUserId <= 0)
            {
                return;
            }

            WayStatics wayStatics = GetWayStatics(wayId);
            if (luckUserId > 0 &&
                wayStatics.PlayerStaticsMap.TryGetValue(luckUserId, out PlayerStatics luckPlayerStatics))
            {
                luckPlayerStatics.LuckCnt++;
            }

            if (badLuckUserId > 0 &&
                wayStatics.PlayerStaticsMap.TryGetValue(badLuckUserId, out PlayerStatics badLuckplayerStatics))
            {
                badLuckplayerStatics.BadLuckCnt++;
            }
        }

        private void LoadData(DateTime dateTime, Dictionary<string, WayStatics> staticsMap)
        {
            string filename = GetFileName(dateTime);
            if (File.Exists(filename))
            {
                string jsonData = File.ReadAllText(filename);
                List<WayStatics> staticsList = JsonConvert.DeserializeObject<List<WayStatics>>(jsonData);

                Debug.Info($"加载的数据:{filename}");
                for (int i = 0; i < staticsList.Count; i++)
                {
                    WayStatics wayStatics = staticsList[i];
                    staticsMap[staticsList[i].WayId] = wayStatics;

                    Debug.Info($"玩家人数:{wayStatics.PlayerStaticsList.Count}");
                    for (int j = 0; j < wayStatics.PlayerStaticsList.Count; j++)
                    {
                        wayStatics.PlayerStaticsMap[wayStatics.PlayerStaticsList[j].UserId] =
                            wayStatics.PlayerStaticsList[j];
                    }

                    for (int j = 0; j < wayStatics.SeatStaticsList.Count; j++)
                    {
                        wayStatics.SeatStaticsMap[wayStatics.SeatStaticsList[j].Seat] = wayStatics.SeatStaticsList[j];
                    }
                }
            }
        }

        public void Dispose()
        {
            List<WayStatics> wayStaticsList = new List<WayStatics>(WayStaticsMap.Values);
            SaveData(DateTime.Now, wayStaticsList);
            _timer?.Dispose();
            _timer = null;
        }

        private void OnDayChange(object data)
        {
            lock (lockObj)
            {
                LastDayWayStaticsList = WayStaticsMap;
            }

            WayStaticsMap = new Dictionary<string, WayStatics>();
            //保存昨天的数据
            SaveLastDayDataAsync();
        }

        /// <summary>
        /// 保存昨天的统计数据
        /// </summary>
        private void SaveLastDayDataAsync()
        {
            Task.Run(() =>
            {
                lock (lockObj)
                {
                    List<WayStatics> wayStaticsList = new List<WayStatics>(LastDayWayStaticsList.Values);
                    SaveData(DateTime.Now.AddDays(-1), wayStaticsList);
                }
            });
        }

        private void SaveData(DateTime dateTime, List<WayStatics> staticsList)
        {
            if (staticsList.Count <= 0)
            {
                return;
            }

            try
            {
                //Debug.Info($"保存的长度：{staticsList.Count}");
                for (int i = 0; i < staticsList.Count; i++)
                {
                    WayStatics wayStatics = staticsList[i];
                    wayStatics.PlayerStaticsList = new List<PlayerStatics>(wayStatics.PlayerStaticsMap.Values);
                    wayStatics.SeatStaticsList = new List<SeatStatics>(wayStatics.SeatStaticsMap.Values);

                    //Debug.Info($"转换数据:{wayStatics.PlayerStaticsMap.Count} {wayStatics.SeatStaticsMap.Count}");
                }

                string jsonData = JsonConvert.SerializeObject(staticsList);
                string fileName = GetFileName(dateTime);
                File.WriteAllText(fileName, jsonData);
            }
            catch (Exception e)
            {
                Debug.Error($"保存失败:{e.Message}");
            }
        }

        private WayStatics GetWayStatics(string wayId)
        {
            if (!WayStaticsMap.TryGetValue(wayId, out WayStatics statics))
            {
                statics = new WayStatics()
                {
                    WayId = wayId
                };
                WayStaticsMap[wayId] = statics;
            }

            return statics;
        }

        private string dirPath = "statistics";

        private string GetFileName(DateTime dateTime)
        {
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            string fileName = $"{dirPath}/{dateTime.ToString("yyyyMMdd")}";
            return fileName;
        }

        /// <summary>
        /// 一次战斗
        /// </summary>
        /// <param name="wayId"></param>
        /// <param name="seat"></param>
        /// <param name="userid"></param>
        /// <param name="score"></param>
        public void AddOnceFight(string wayId, int seat, int userid, int score)
        {
            WayStatics wayStatics = GetWayStatics(wayId);

            if (!wayStatics.SeatStaticsMap.TryGetValue(seat, out SeatStatics seatStatics))
            {
                seatStatics = new SeatStatics()
                {
                    Seat = seat
                };
                wayStatics.SeatStaticsMap[seat] = seatStatics;
            }

            seatStatics.TotalCnt++;
            seatStatics.Score += score;
            if (score >= 0)
            {
                seatStatics.WinCnt++;
            }

            if (!wayStatics.PlayerStaticsMap.TryGetValue(userid, out PlayerStatics playerStatics))
            {
                playerStatics = new PlayerStatics()
                {
                    UserId = userid,
                };
                wayStatics.PlayerStaticsMap[userid] = playerStatics;
            }

            playerStatics.TotalCnt++;
            playerStatics.TotalScore += score;
            if (score >= 0)
            {
                playerStatics.WinCnt++;
            }

            //Debug.Info($"保存一局数据！{wayStatics.PlayerStaticsMap.Count} {Thread.CurrentThread.ManagedThreadId}");
        }

        /// <summary>
        /// 一场战斗
        /// </summary>
        public void AddSessionFight(string wayId, float beilv, int userid, int score)
        {
            WayStatics wayStatics = GetWayStatics(wayId);
            if (wayStatics.BeiLv <= 0.0001f)
            {
                wayStatics.BeiLv = beilv;
            }

            if (!wayStatics.PlayerStaticsMap.TryGetValue(userid, out PlayerStatics playerStatics))
            {
                playerStatics = new PlayerStatics()
                {
                    UserId = userid
                };
            }

            playerStatics.TotalSessionCnt++;
            playerStatics.TotalSessionScore += score;
            if (score >= 0)
                playerStatics.WinSessionCnt++;

            //Debug.Info($"保存一大局数据: {wayStatics.PlayerStaticsMap.Count} {Thread.CurrentThread.ManagedThreadId}");
        }

        /// <summary>
        /// 玩法统计
        /// </summary>
        public class WayStatics
        {
            /// <summary>
            /// 玩法Id
            /// </summary>
            public string WayId;

            /// <summary>
            /// 倍率
            /// </summary>
            public float BeiLv;

            /// <summary>
            /// 位置统计
            /// </summary>
            public List<SeatStatics> SeatStaticsList = null;

            /// <summary>
            /// 玩家统计
            /// </summary>
            public List<PlayerStatics> PlayerStaticsList = null;

            /// <summary>
            /// 座位统计
            /// </summary>
            [JsonIgnore] public Dictionary<int, SeatStatics> SeatStaticsMap = new Dictionary<int, SeatStatics>();

            /// <summary>
            /// 玩家统计
            /// </summary>
            [JsonIgnore] public Dictionary<int, PlayerStatics> PlayerStaticsMap = new Dictionary<int, PlayerStatics>();
        }

        /// <summary>
        /// 座位统计
        /// </summary>
        public class SeatStatics
        {
            /// <summary>
            /// 座位
            /// </summary>
            public int Seat;

            /// <summary>
            /// 赢的次数
            /// </summary>
            public int WinCnt;

            /// <summary>
            /// 总的次数
            /// </summary>
            public int TotalCnt;

            /// <summary>
            /// 总得分
            /// </summary>
            public int Score;
        }

        /// <summary>
        /// 玩家统计
        /// </summary>
        public class PlayerStatics
        {
            /// <summary>
            /// 玩家Id
            /// </summary>
            public int UserId;

            /// <summary>
            /// 总得分
            /// </summary>
            public double TotalScore;

            /// <summary>
            /// 赢的数量
            /// </summary>
            public int WinCnt;

            /// <summary>
            /// 总数量
            /// </summary>
            public int TotalCnt;

            /// <summary>
            /// 赢的场次
            /// </summary>
            public int WinSessionCnt;

            /// <summary>
            /// 总的场次
            /// </summary>
            public int TotalSessionCnt;

            public int TotalSessionScore;

            public int LuckCnt;

            public int BadLuckCnt;
        }
    }
}