using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Windows;
using Zerolauncher.Defender;

namespace Zerolauncher.Manager
{
    internal class EngineManager
    {
        private static Dictionary<string, SingleGame> mGame = new Dictionary<string, SingleGame>();

        //运行时才能决定是否执行内联
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        private static string AccToKey(AccountNew account)
        {
            return string.Format("{0}{1}{2}", account.providerId, account.serverId, account.userName);
        }

        public static bool CreateGame(AccountNew account)
        {
            if (UpDateData.is_check == false)
            {
                MessageBox.Show("正在更新游戏数据，请等待1-3秒。\n 请检查网络", "错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                return true;
            }
            //if (UpDateManager.state)
            //{
            //    UpDateManager.DoUpdate();
            //    return true;
            //}
            var key = AccToKey(account);
            if (mGame.ContainsKey(key)) { return false; }
            if (CacheSha.errorCode != 0) {
                switch (CacheSha.errorCode)
                {
                    case 1:
                        MessageBox.Show("发生网络错误==EMS。\n 请检查网络", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        break;
                    case 2:
                        MessageBox.Show("发生游戏服务错误==EMS。\n 请联系管理员", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        break;
                    default:
                        MessageBox.Show("发生未知错误==EMS。\n 请联系管理员", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        break;
                }
                return true; 
            }
            try
            {
                mGame[key] = new SingleGame(account);
            }catch (Exception _ex)
            {
                Trace.WriteLine("lalalala3");
                UpDateManager.DoUpdate();
            }
            return true;
        }

        public static bool CreateGame(int memberId)
        {
            return CreateGame(AccountManager.accountsList[memberId]);
        }

        public static int CheckGameState(AccountNew account)
        {
            var key = AccToKey(account);
            if (mGame.ContainsKey(key)) { return mGame[key].mHandle; }
            return -1;
        }

        public static short TurnGameSizeMini(AccountNew account)
        {
            var key = AccToKey(account);
            if (mGame.ContainsKey(key)) 
            {
                var game = mGame[key];
                if (game.mHandle != 0)
                {
                    game.Send(StaticHandleS.MiniSize);
                    return 2;
                }
                return 1;
            }
            return 0;
        }

        public static short TurnGameSizeNormal(AccountNew account)
        {
            var key = AccToKey(account);
            if (mGame.ContainsKey(key))
            {
                var game = mGame[key];
                if (game.mHandle != 0)
                {
                    game.Send(StaticHandleS.NormalSize);
                    return 2;
                }
                return 1;
            }
            return 0;
        }

        public static bool ExitGame(AccountNew account)
        {
            var key = AccToKey(account);
            if (!mGame.ContainsKey(key)) { return false; }
            mGame[key].Send(StaticHandleS.CloseGame);
            return true;
        }

        public static void OnGameExit(AccountNew account)
        {
            mGame.Remove(AccToKey(account));
        }

        public static bool CheckEmpy()
        {
            return mGame.Count == 0;
        }
    }

    class SingleGame
    {
        Process process;
        string? restartUrl;
        public int mHandle;
        public AccountNew? account;
        string gameMode;

        public SingleGame(AccountNew? acc, string mod = StaticHandleA.GameMode) 
        {
            restartUrl = null;
            account = acc;
            gameMode = mod;
            mHandle = 0;
            process = EngineShell.CheckEngineSafe(gameMode);
            process.OutputDataReceived += Handle;
            process.ErrorDataReceived += Handle;
            process.Exited += Process_Exited;
            
            process.Start();

            process.BeginOutputReadLine(); // 开始异步读取
        }

        private void CreateProcess()
        {
            process = EngineShell.CheckEngineSafe(gameMode);
            process.OutputDataReceived += Handle;
            process.Exited += Process_Exited;
            process.Start();
            process.BeginOutputReadLine(); // 开始异步读取
        }

        private void Process_Exited(object? sender, EventArgs e)
        {
            Trace.WriteLine(
                $"Exit time    : {process.ExitTime}\n" +
                $"Exit code    : {process.ExitCode}\n" +
                $"Elapsed time : {Math.Round((process.ExitTime - process.StartTime).TotalMilliseconds)}");
            Trace.WriteLine($"进程已退出:{account.nickName}");
            if (gameMode != StaticHandleA.GameMode) return;
            if ( restartUrl == null) 
            { 
                EngineManager.OnGameExit(account);
                return;
            }
            CreateProcess();
        }

        private void Handle(object sender, DataReceivedEventArgs e)
        {
            var lines = e.Data == null? [""] : e.Data.Split(" ", 2); // 切成两半
            switch (lines[0])
            {
                case StaticHandleC.LoadDone:
                    if (gameMode == StaticHandleA.UpdateMode)
                    {
                        UpDateManager.DoUpdate1();
                        return;
                    }
                    Send($"{StaticHandleS.ShowWindow} {ServicesStaticInfo.ServicesName[account.providerId]}-{account.nickName}");
                    break;
                case StaticHandleC.StartDone:
                    if (gameMode == StaticHandleA.UpdateMode)
                    {
                        UpDateManager.DoUpdate2();
                        return;
                    }
                    if (restartUrl == null)
                    {
                        Task.Run(async delegate
                        {
                            if (lines[1] == "True") await Task.Delay(5000);
                            LoginManager.DoLogin(this);
                        });
                    }
                    else
                    {
                        Send($"{StaticHandleS.GameSa} {restartUrl}");
                        restartUrl = null;
                    }
                    break;
                case StaticHandleC.GameDone:
                    mHandle = int.Parse(lines[1]);
                    break;
                case StaticHandleC.BrowserDone:
                    Trace.WriteLine($"尝试让游戏退出:{account.nickName}");
                    restartUrl = lines[1];
                    Send(StaticHandleS.CloseGame);
                    break;
                case StaticHandleC.Version:
                    mHandle = int.Parse(lines[1]);
                    break;
                case StaticHandleC.DownloadDone:
                    UpDateManager.OnDownLoadDone(lines[1]);
                    break;
                case StaticHandleC.TakeVerify:
                    var args = lines[1].Split(' ');
					_ = LoginManager.DoVerify(this, args[0], args[1]);
					break;
                default:
                    Trace.WriteLine($"from client:{e.Data}");
                    break;
            }
        }

        public bool Send(string msg)
        {
            if(process.HasExited) { return false; }
            process.StandardInput.WriteLine(msg);
            return true;
        }

    }

    public class FileReadException : Exception
    {
        public FileReadException(string message) : base(message)
        {
        }
    }

    class EngineShell
    {
        static bool needShowTis = true;
        static bool is_check = false;
        const string engine_file = @"ZeroEngine.exe";
        public static Process CheckEngineSafe(string mod)
        {
            bool is_first_luancher = EngineManager.CheckEmpy();
            #region 检测代码
            //if (mod == StaticHandleA.UpdateMode)
            //{
            //    if (DataStream.dataStream.ecs.Length > 10)
            //    {
            //        string? now_bit;
            //        using (SHA256 sha256 = SHA256.Create())
            //        {
            //            using (FileStream fileStream = File.OpenRead(engine_file))
            //            {
            //                byte[] hashBytes = sha256.ComputeHash(fileStream);
            //                now_bit = BitConverter.ToString(hashBytes).Replace("-", string.Empty);
            //            }
            //        }
            //        if (DataStream.dataStream.ecs != now_bit)
            //        {
            //            Trace.WriteLine("lalalala" + DataStream.dataStream.ecs);
            //            throw new FileReadException("error esu1!");
            //        }
            //    }
            //}
            //else if (!is_check && is_first_luancher)
            //{
            //    string? now_bit;
            //    using (SHA256 sha256 = SHA256.Create())
            //    {
            //        using (FileStream fileStream = File.OpenRead(engine_file))
            //        {
            //            byte[] hashBytes = sha256.ComputeHash(fileStream);
            //            now_bit = BitConverter.ToString(hashBytes).Replace("-", string.Empty);
            //        }
            //    }
            //    if (CacheSha.GetE() != now_bit)
            //    {
            //        Trace.WriteLine("lalalala1");
            //        throw new FileReadException("error esu0!");
            //    }
            //    if (DataStream.dataStream.ecs != now_bit) { DataStream.dataStream.ecs = now_bit; DataStream.write(); }
            //    is_check = true;
            //}
            #endregion

            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = engine_file,
                    Arguments = $"{StaticHandleA.GameMode} {needShowTis}",
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
					RedirectStandardError = true
		        },
                EnableRaisingEvents = true
            };
            if (needShowTis) needShowTis = false;
            return process;
        }
    }
}
