using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Threading;
using Cloud.Alibaba.Oss;
using GameData;
using MrWu.Debug;
using ObjectModel.Game;
using Server.Core;

namespace Server
{
    public class FightRecordManager : SingleInstance<FightRecordManager>
    {
        private Thread thread;

        private bool IsDispose = false;

        private const string dirPath = "RoomFightPath";

        private ConcurrentQueue<FightRecordCommand> CommandQueue = new ConcurrentQueue<FightRecordCommand>();

        private UpLoadTask Current;

        /// <summary>
        /// 等待处理的文件
        /// </summary>
        private HashSet<string> waitDeal = new HashSet<string>();

        private ConcurrentQueue<UpLoadTask> _upLoadTasks = new ConcurrentQueue<UpLoadTask>();

        private long nextUploadOss;

        /// <summary>
        /// 10 秒钟检查一次上传
        /// </summary>
        private const long checkInterval = 10 * 1000;

        private int GameId;

        /// <summary>
        /// 最大只允许上传10M文件
        /// </summary>
        private const int MaxFileSize = 1024 * 1024 * 10;

        /// <summary>
        /// 当前的存储的回放版本数据
        /// </summary>
        private const int FightRecordVer = 2;

        public void Init(int gameId)
        {
            this.GameId = gameId;
        }

        public FightRecordManager()
        {
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            thread = new Thread(Run);
            thread.Start();
        }

        /// <summary>
        /// 保存房间信息
        /// </summary>
        /// <param name="weiyima"></param>
        /// <param name="info"></param>
        public void SaveRoomInfo(string weiyima, FriendRoomFightFileInfo info)
        {
            CommandQueue.Enqueue(FightRecordCommand.Create(Command.SaveRoomInfo, weiyima, info));
        }

        /// <summary>
        /// 保存战绩回放信息
        /// </summary>
        public void SaveFightInfo(string weiyima, RoomFightData info, int index)
        {
            CommandQueue.Enqueue(FightRecordCommand.Create(Command.SaveFightInfo, weiyima, info, index));
        }

        private void Run()
        {
            #if DEBUG
            uint threadId = ThreadHelper.GetOSThreadId();
            Debug.Info($"ThreadStart FightRecordManager {threadId}");
            #endif
            
            while (true)
            {
                if (CommandQueue.TryDequeue(out FightRecordCommand command))
                {
                    try
                    {
                        switch (command.Command)
                        {
                            case Command.SaveFightInfo:
                            {
                                string fileName = $"{dirPath}/{GetOssPath.GetFileName(command.WeiYiMa, command.Index)}";
                                string content = JsonPack.GetJson(command.Data);
                                File.WriteAllText(fileName, content);
                            }
                                break;
                            case Command.SaveRoomInfo:
                            {
                                string fileName = $"{dirPath}/FriendRoomFightFileInfo_{command.WeiYiMa}.txt";
                                string content = JsonPack.GetJson(command.Data);
                                File.WriteAllText(fileName, content);

                                nextUploadOss = TimeInfo.Instance.FrameTime; //下一帧开始上传，保证SaveFightInfo全部先保存
                            }
                                break;
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.Error($"执行保存回放数据指令报错:{command.Command} {command.WeiYiMa} {e.Message}");
                    }

                    ReferencePool.Recycle(command);
                }
                else if (IsDispose)
                {
                    break;
                }

                if (TimeInfo.Instance.FrameTime > nextUploadOss)
                {
                    try
                    {
                        //检查上传Oss
                        string[] files = Directory.GetFiles(dirPath, "FriendRoomFightFileInfo_*.txt");
                        for (int i = 0; i < files.Length; i++)
                        {
                            if (waitDeal.Contains(files[i]))
                                continue;

                            UpLoadTask loadTask = UpLoadTask.Create(files[i]);
                            if (loadTask == null)
                            {
                                Debug.Error($"这个文件有问题:{files[i]}");
                                File.Delete(files[i]);
                            }
                            else
                            {
                                waitDeal.Add(files[i]);
                                _upLoadTasks.Enqueue(loadTask);
                                Debug.Info("添加到上传任务!");
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.Error($"处理出错:{e.Message}");
                    }

                    nextUploadOss = TimeInfo.Instance.FrameTime + checkInterval;
                }

                while (Current == null && _upLoadTasks.TryDequeue(out UpLoadTask loadTask))
                {
                    Current = loadTask;
                }

                if (Current != null && TimeInfo.Instance.FrameTime > Current.NextTryTime)
                {
                    try
                    {
                        //执行文件上传
                        string filePath =
                            $"{dirPath}/{GetOssPath.GetFileName(Current.RoomInfo.weiyima, Current.Current)}";

                        if (!File.Exists(filePath))
                        {
                            Debug.Error($"未找打要上传的文件:{filePath}");
                            Current.Current++;
                        }
                        else
                        {
                            // if (!ServerConst.IsTest)
                            // {
                                Debug.Info("开始上传!");
                                var ossPath = GetOssPath.GetKey(Path.GetFileName(filePath), GameId,
                                    Current.RoomInfo.endTime);
                                FileInfo fileInfo = new FileInfo(filePath);
                                bool isUpLoad = false;
                                if (fileInfo.Length > MaxFileSize)
                                {
                                    isUpLoad = true;
                                    Debug.Fatal($"上传的文件超10M 不合理:{fileInfo.FullName}");
                                }
                            
                                var b = isUpLoad || OSSHelper.PutObject(Bucket.B8880666s,ossPath, File.ReadAllText(filePath));
                                if (!b)
                                {
                                    Debug.Error($"上传文件到OSS失败:{filePath},等待重试!");
                                    Current.TryCnt++;
                                    Current.NextTryTime = TimeInfo.Instance.FrameTime + Current.TryCnt * 1000;
                                }
                                else
                                {
                                    Debug.Info($"上传成功:{filePath}");
                                    Current.Current++;
                                }
                            // }
                            // else
                            // {
                            //     Current.Current++;
                            // }
                        }

                        if (Current.Current > Current.AllCount)
                        {
                            //全部上传完毕,删除文件
                            for (int i = 1; i <= Current.AllCount; i++)
                            {
                                string delPath = $"{dirPath}/{GetOssPath.GetFileName(Current.RoomInfo.weiyima, i)}";
                                File.Delete(delPath);
                                Debug.Info($"删除文件:{delPath}");
                            }

                            File.Delete(Current.filaName);
                            waitDeal.Remove(Current.filaName);
                            Current.Dispose();
                            Current = null;
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.Error($"执行上传任务报错:{e.Message}");
                    }
                }

                Thread.Sleep(1);
            }
        }

        public void Dispose()
        {
            IsDispose = true;
            thread.Join();
        }

        /// <summary>
        /// 上传任务
        /// </summary>
        public class UpLoadTask : Reference
        {
            public string filaName;
            public FriendRoomFightFileInfo RoomInfo;

            /// <summary>
            /// 当前在处理那一个
            /// </summary>
            public int Current;

            /// <summary>
            /// 总共几个
            /// </summary>
            public int AllCount;

            /// <summary>
            /// 下次尝试时间
            /// </summary>
            public long NextTryTime;

            /// <summary>
            /// 尝试次数 最多重试10次
            /// </summary>
            public long TryCnt;

            public static UpLoadTask Create(string fileName)
            {
                if (!File.Exists(fileName))
                {
                    Debug.Error($"没找到要上传的战斗文件信息:{fileName}");
                    return null;
                }

                string jsonData = File.ReadAllText(fileName);
                if (string.IsNullOrEmpty(jsonData))
                {
                    return null;
                }

                UpLoadTask task = ReferencePool.Fetch<UpLoadTask>();
                task.RoomInfo = JsonPack.GetData<FriendRoomFightFileInfo>(jsonData);
                if (task.RoomInfo == null || task.RoomInfo.overCnt <= 0)
                {
                    return null;
                }

                task.filaName = fileName;
                task.NextTryTime = 0;
                task.TryCnt = 0;
                task.Current = 1;
                task.AllCount = task.RoomInfo.overCnt;
                return task;
            }

            public override void Dispose()
            {
                RoomInfo = null;
                filaName = null;
                ReferencePool.Recycle(this);
            }
        }

        public class FightRecordCommand : Reference
        {
            public string WeiYiMa;
            public int Index;
            public object Data;
            public Command Command;

            public static FightRecordCommand Create(Command command, string weiyima, object data, int index = 0)
            {
                FightRecordCommand fightRecordCommand = ReferencePool.Fetch<FightRecordCommand>();
                fightRecordCommand.WeiYiMa = weiyima;
                fightRecordCommand.Data = data;
                fightRecordCommand.Command = command;
                fightRecordCommand.Index = index;
                return fightRecordCommand;
            }

            public override void Dispose()
            {
                WeiYiMa = null;
                Data = null;
                ReferencePool.Recycle(this);
            }
        }

        public enum Command
        {
            /// <summary>
            /// 保存房间信息
            /// </summary>
            SaveRoomInfo,

            /// <summary>
            /// 保存战绩信息
            /// </summary>
            SaveFightInfo,
        }
    }
}