// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS)
// Copyright (C) 2025-present LeonOS 2 Developer Team
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

using CMLeonOS.Logger;
using CMLeonOS.Settings;
using CMLeonOS.Gui;
using CMLeonOS.Utils;
using Cosmos.HAL;
using Cosmos.HAL.BlockDevice;
using Cosmos.HAL.Drivers.Video;
using Cosmos.System.FileSystem;
using Cosmos.System.FileSystem.FAT;
using Cosmos.System.FileSystem.VFS;
using Cosmos.System.Graphics;
using Cosmos.System.Graphics.Fonts;
using Cosmos.System.Network.Config;
using Cosmos.System.Network.IPv4;
using Cosmos.System.Network.IPv4.UDP.DHCP;
using Cosmos.System.Emulation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Sys = Cosmos.System;

namespace CMLeonOS
{
    public class Kernel : Sys.Kernel
    {
        // fuck Windows
        // fuck Linux
        // fuck Unix
        // fuck macOS
        // fuck ALL!!!

        // a femboy's operating system :3

        private static CMLeonOS.Logger.Logger _logger = CMLeonOS.Logger.Logger.Instance;

        // 创建全局CosmosVFS实例
        public static Sys.FileSystem.CosmosVFS fs = new Sys.FileSystem.CosmosVFS();
        public static UserSystem userSystem;
        
        public static void ExecuteCommand(string command)
        {
            var tempShell = new Shell(userSystem);
            tempShell.ExecuteCommand(command);
        }
        
        public static bool FixMode = false;
        public static DateTime SystemStartTime;
        
        public static User CurrentUser
        {
            get { return UserSystem.CurrentLoggedInUser; }
        }

        public static string Version
        {
            get { return CMLeonOS.Version.GetVersion(); }
        }
        
        public static Cosmos.HAL.NetworkDevice NetworkDevice = null;
        public static string IPAddress = "Unknown";

        [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.font.psf")]
        public static readonly byte[] file;
        
        [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.GitCommit.txt")]
        public static readonly byte[] gitCommitFile;
        
        [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.BuildTime.txt")]
        public static readonly byte[] buildTimeFile;
        
        public static void ShowError(string message)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine($"{message}");
            Console.ResetColor();
        }
        
        private void InitializeSystem()
        {
            // 修改VGA Text Mode字体样式（使用Spleen）
            PCScreenFont font = PCScreenFont.Default;
            VGAScreen.SetFont(font.CreateVGAFont(), font.Height);

            // 修改光标样式
            _logger.Info("Kernel", "Setting cursor size to 100");
            Console.CursorSize = 100;

            // 注册VFS
            _logger.Info("Kernel", "Starting VFS initialization");
            try
            {
                Sys.FileSystem.VFS.VFSManager.RegisterVFS(fs);
                _logger.Success("Kernel", "VFS initialized successfully");
                
                Settings.SettingsManager.LoadSettings();
                _logger.Info("Kernel", "Settings loaded successfully");
                
                // 显示可用空间（动态单位）
                var available_space = fs.GetAvailableFreeSpace(@"0:\");
                _logger.Info("Kernel", "Getting available free space");

                string spaceWithUnit = FormatBytes(available_space);
                _logger.Info("Kernel", $"Available Free Space: {spaceWithUnit}");
                
                // 显示文件系统类型
                var fs_type = fs.GetFileSystemType(@"0:\");
                _logger.Info("Kernel", $"File System Type: {fs_type}");
                
                // 检查并创建system文件夹
                string systemFolderPath = @"0:\system";
                _logger.Info("Kernel", $"Checking for system folder at {systemFolderPath}");
                if (!System.IO.Directory.Exists(systemFolderPath))
                {
                    System.IO.Directory.CreateDirectory(systemFolderPath);
                    _logger.Info("Kernel", "Created system folder at 0:\\system");
                }
                
                // 检查并创建apps文件夹
                string appsFolderPath = @"0:\apps";
                _logger.Info("Kernel", $"Checking for apps folder at {appsFolderPath}");
                if (!System.IO.Directory.Exists(appsFolderPath))
                {
                    System.IO.Directory.CreateDirectory(appsFolderPath);
                    _logger.Info("Kernel", "Created apps folder at 0:\\apps");
                }
                
                // 初始化用户系统
                _logger.Info("Kernel", "Initializing user system");
                UserSystem.Initialize();
                userSystem = new UserSystem();
                _logger.Success("Kernel", "User system initialized");

                // 初始化指令集
                _logger.Info("Kernel", "Initializing instruction set");
                FGMSECInstructionSet.Install();
                _logger.Success("Kernel", "Instruction set initialized");
                
                // 读取 Git Commit hash
                if (gitCommitFile != null && gitCommitFile.Length > 0)
                {
                    try
                    {
                        CMLeonOS.Version.GitCommit = System.Text.Encoding.UTF8.GetString(gitCommitFile);
                        _logger.Info("Kernel", $"Git Commit: {CMLeonOS.Version.GitCommit}");
                    }
                    catch
                    {
                        CMLeonOS.Version.GitCommit = "unknown";
                        _logger.Warning("Kernel", "Failed to read Git Commit, using 'unknown'");
                    }
                }
                else
                {
                    CMLeonOS.Version.GitCommit = "unknown";
                    _logger.Warning("Kernel", "Git Commit file not found, using 'unknown'");
                }
                
                // 读取 Build Time
                if (buildTimeFile != null && buildTimeFile.Length > 0)
                {
                    try
                    {
                        string buildTime = System.Text.Encoding.UTF8.GetString(buildTimeFile);
                        _logger.Info("Kernel", $"Build Time: {buildTime}");
                    }
                    catch
                    {
                        _logger.Warning("Kernel", "Failed to read Build Time");
                    }
                }
                else
                {
                    _logger.Warning("Kernel", "Build Time file not found");
                }
                
                // 检查env.dat文件是否存在，如果不存在则创建并设置Test环境变量
                string envFilePath = @"0:\system\env.dat";
                if (!System.IO.File.Exists(envFilePath))
                {
                    System.IO.File.WriteAllText(envFilePath, "Test=123");
                    _logger.Info("Kernel", "Created env.dat with Test=123");
                }

                // 记录系统启动时间（用于uptime命令）
                SystemStartTime = DateTime.Now;
                _logger.Info("Kernel", $"System started at: {SystemStartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
                
                // 初始化网络
                _logger.Info("Kernel", "Starting network initialization");
                try
                {
                    if (Cosmos.HAL.NetworkDevice.Devices.Count == 0)
                    {
                        throw new Exception("No network devices are available.");
                    }
                    NetworkDevice = NetworkDevice.Devices[0];
                    _logger.Info("Kernel", $"Network device found: {NetworkDevice.Name}");
                    
                    using var dhcp = new DHCPClient();
                    if (NetworkDevice.Ready == true) {
                        _logger.Success("Kernel", "Network device ready");
                    }
                    else
                    {
                        _logger.Error("Kernel", "Network device is not ready");
                    }
                    dhcp.SendDiscoverPacket();
                    
                    IPAddress = NetworkConfiguration.CurrentAddress.ToString();
                    _logger.Info("Kernel", $"Local IP: {IPAddress}");
                    
                    string gateway = NetworkConfigManager.Instance.GetGateway();
                    _logger.Info("Kernel", $"Gateway: {gateway}");
                    
                    string dns = NetworkConfigManager.Instance.GetDNS();
                    _logger.Info("Kernel", $"DNS Server: {dns}");
                    
                    _logger.Success("Kernel", "Network started successfully");
                }
                catch (Exception ex)
                {
                    _logger.Error("Kernel", $"Network initialization failed: {ex.Message}");
                }

                // 输出系统启动-初始化完成后的时间
                TimeSpan uptime = DateTime.Now - Kernel.SystemStartTime;
                
                // 格式化运行时间
                int days = uptime.Days;
                int hours = uptime.Hours;
                int minutes = uptime.Minutes;
                int seconds = uptime.Seconds;
                
                _logger.Info("Kernel", $"System initialization completed in {days} days, {hours} hours, {minutes} minutes, {seconds} seconds");
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("Read only"))
                {
                    CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
                    global::System.Console.Clear();
                    
                    var formatWindow = new CMLeonOS.UI.Window(
                        new CMLeonOS.UI.Rect(10, 5, 60, 12),
                        "Format Disk",
                        () => { },
                        true
                    );
                    formatWindow.Render();
                    
                    CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
                    global::System.Console.SetCursorPosition(12, 8);
                    global::System.Console.Write("Disk not formatted");
                    
                    CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Yellow, global::System.ConsoleColor.Black);
                    global::System.Console.SetCursorPosition(12, 9);
                    global::System.Console.Write("Warning: This will erase all data!");
                    
                    CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
                    global::System.Console.SetCursorPosition(12, 11);
                    global::System.Console.Write("Press any key to format...");
                    
                    global::System.Console.ReadKey();
                    
                    try {
                        Disk targetDisk = fs.Disks[0];
                        CreateMBRandPartitionTable(targetDisk);
                        
                        CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Green, global::System.ConsoleColor.Black);
                        global::System.Console.Clear();
                        formatWindow.Render();
                        
                        CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
                        global::System.Console.SetCursorPosition(12, 8);
                        global::System.Console.Write("Disk formatted successfully!");
                        
                        CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
                        global::System.Console.SetCursorPosition(12, 9);
                        global::System.Console.Write("Restarting in 3 seconds...");
                        
                        System.Threading.Thread.Sleep(3000);
                        Sys.Power.Reboot();
                    }
                    catch (Exception exe)
                    {
                        CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Red, global::System.ConsoleColor.Black);
                        global::System.Console.Clear();
                        formatWindow.Render();
                        
                        CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
                        global::System.Console.SetCursorPosition(12, 8);
                        global::System.Console.Write("Format failed!");
                        
                        CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.White, global::System.ConsoleColor.Black);
                        global::System.Console.SetCursorPosition(12, 9);
                        global::System.Console.Write($"Error: {exe.Message}");
                        
                        global::System.Console.ReadKey();
                    }
                }
                else{
                    Console.Clear();
                    Console.BackgroundColor = ConsoleColor.Blue;
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Clear();
                    Console.Beep();
                    Console.WriteLine(":(");
                    Console.WriteLine("A problem has been detected and CMLeonOS has been shut down to prevent damage to your computer.");
                    
                    string gitCommit = "unknown";
                    if (gitCommitFile != null && gitCommitFile.Length > 0)
                    {
                        try
                        {
                            gitCommit = System.Text.Encoding.UTF8.GetString(gitCommitFile);
                        }
                        catch
                        {
                        }
                    }
                    
                    Console.WriteLine($"Error information: {ex.Message}");
                    Console.WriteLine($"Build version: {gitCommit}");
                    Console.WriteLine("The operating system cannot recover from this exception and has halted immediately.");
                    Console.WriteLine("If this is the first time you've seen this stop error screen, restart your computer.");
                    Console.WriteLine("If this screen appears again, follow these steps:");
                    Console.WriteLine("1. Check the system logs to ensure all kernel modules are loaded correctly.");
                    Console.WriteLine("2. Record the system version and steps to reproduce the error.");
                    Console.WriteLine("3. Send an post to the CMLeonOS official forum.");
                    Console.WriteLine("Contact us via https://lbbs.ecuil.com/#/thread/category/10, including the error information for support.");
                    Console.WriteLine("Please include the error information, system build version, runtime environment, and operation steps before the crash.");
                    Console.WriteLine("Warning: Unsaved data in memory will be lost due to the emergency system shutdown.");
                    Console.WriteLine("Press any key to restart.");
                    Console.ReadKey();
                    Sys.Power.Reboot();
                }
            }
        }
        
        protected override void BeforeRun()
        {
            // 在显示 Boot Menu 之前初始化系统（VFS、用户系统等）
            InitializeSystem();

            while (true)
            {
                BootMenuAction bootAction = BootMenu.Show();

                switch (bootAction)
                {
                    case BootMenuAction.Reboot:
                        Sys.Power.Reboot();
                        return;
                    case BootMenuAction.Shutdown:
                        Sys.Power.Shutdown();
                        return;
                    case BootMenuAction.GuiBoot:
                        Console.Clear();
                        Console.WriteLine("Starting GUI...");
                        Console.WriteLine();
                        if (Gui.Gui.StartGui())
                        {
                            // GUI 启动后会阻塞在这里，直到 GUI 退出
                            return;
                        }

                        // 低内存提示选择“返回 BootMenu”时会回到这里继续循环
                        continue;
                    case BootMenuAction.NormalBoot:
                    default:
                        break;
                }

                break;
            }

            Console.Clear();
            // Console.WriteLine("Kernel load done!");
            // Console.WriteLine(@"----------------------------------------------------------");
            Console.WriteLine(@"   ____ __  __ _                      ___  ____  ");
            Console.WriteLine(@"  / ___|  \/  | |    ___  ___  _ __  / _ \/ ___| ");
            Console.WriteLine(@" | |   | |\/| | |   / _ \/ _ \| '_ \| | | \___ \ ");
            Console.WriteLine(@" | |___| |  | | |__|  __/ (_) | | | | |_| |___) |");
            Console.WriteLine(@"  \____|_|  |_|_____\___|\___/|_| |_|____/|____/ ");
            Console.WriteLine();
            Console.WriteLine("The CMLeonOS Project");
            Console.WriteLine("(C) LeonOS 2 Developer Team 2025-2026. All rights reserved.");
            Console.WriteLine(@"----------------------------------------------------------");

            // 循环直到登录成功或退出
            while (true)
            {
                // 第一次启动，设置管理员账户
                if (!userSystem.HasUsers)
                {
                    _logger.Info("Kernel", "First time setup - creating admin account");
                    userSystem.FirstTimeSetup();
                    _logger.Success("Kernel", "Admin account created successfully");
                }
                // 后续启动，需要登录
                else
                {
                    // 循环直到登录成功
                    while (!userSystem.Login())
                    {
                        // 登录失败，继续尝试
                    }
                    
                    _logger.Info("Kernel", $"User '{userSystem.CurrentUsername}' logged in successfully");
                    
                    // 检查并执行启动脚本
                    ExecuteStartupScript();

                    ExecuteStartupTest();

                    if (System.IO.File.Exists("0:\\system\\zen"))
                    {
                        Console.WriteLine("=====================================");
                        Console.WriteLine("        The Zen of CMLeonOS         ");
                        Console.WriteLine("(For the dreamer at 0x100000)");
                        Console.WriteLine("=====================================");
                        Console.WriteLine();
                        Console.WriteLine("Memory has bounds, but thought breaks all frame,");
                        Console.WriteLine("Bare metal no layers, code bears its name.");
                        Console.WriteLine("A boot's brief spark, all systems ignite,");
                        Console.WriteLine("Errors in registers, roots in code's flight.");
                        Console.WriteLine();
                        Console.WriteLine("Simplicity beats the redundant's vain race,");
                        Console.WriteLine("Stability outshines the radical's chase.");
                        Console.WriteLine("Hardware ne'er lies, code holds the wise key,");
                        Console.WriteLine("Interrupts not chaos, scheduling sets free.");
                        Console.WriteLine();
                        Console.WriteLine("Binary's cold shell, no breath, no soul,");
                        Console.WriteLine("Kernel's warm core, makes the machine whole.");
                        Console.WriteLine("From zero to one, the boot path we tread,");
                        Console.WriteLine("From one to forever, guard every thread.");
                        Console.WriteLine();
                        Console.WriteLine("Build the kernel in zen, step by step, line by line,");
                        Console.WriteLine("A bug brings new wake, a line brings new shine.");
                    }
                    
                    // 运行Shell进程（用户可以输入exit退出）
                    _logger.Info("Kernel", "Starting Shell process");
                    var shellProcess = new ShellProcess(userSystem);
                    ProcessManager.AddProcess(shellProcess);
                    shellProcess.TryStart();
                    shellProcess.TryRun();
                    shellProcess.TryStop();
                    _logger.Info("Kernel", "Shell process exited");
                    
                    // 如果用户输入了exit，Shell.Run()会返回，继续循环
                }
            }
        }

        // 我居然成功了，我在没有任何文档的情况下研究出来了
        private void CreateMBRandPartitionTable(Disk disk)
        {
            disk.Clear();
            ulong diskSize = (ulong)(disk.Size / 1024 / 1024);
            uint partSize = (uint)(diskSize - 2);

            disk.CreatePartition((int)partSize);

            var part = disk.Partitions[disk.Partitions.Count - 1];
            disk.FormatPartition(0, "FAT32", true);
            // Console.WriteLine($"Partition type: {part.GetType()}");
        }

        private void ExecuteStartupScript()
        {
            string startupFilePath = @"0:\system\startup.cm";
            
            try
            {
                // 检查启动脚本文件是否存在
                if (System.IO.File.Exists(startupFilePath))
                {
                    _logger.Info("Kernel", "Startup script found, executing...");
                    
                    // 读取启动脚本内容
                    string[] lines = System.IO.File.ReadAllLines(startupFilePath);
                    
                    // 检查文件是否为空
                    if (lines.Length == 0 || (lines.Length == 1 && string.IsNullOrWhiteSpace(lines[0])))
                    {
                        _logger.Warning("Kernel", "Startup script is empty, skipping");
                        return;
                    }
                    
                    Console.WriteLine("Executing startup script...");
                    // Console.WriteLine("--------------------------------");
                    
                    // 创建临时 Shell 实例来执行启动脚本
                    var tempShell = new Shell(userSystem);
                    
                    // 逐行执行命令
                    foreach (string line in lines)
                    {
                        // 跳过空行和注释行
                        if (string.IsNullOrWhiteSpace(line) || line.Trim().StartsWith("#"))
                        {
                            continue;
                        }
                        
                        // 执行命令
                        // Console.WriteLine($"Executing: {line}");
                        tempShell.ExecuteCommand(line);
                    }
                    
                    // Console.WriteLine("--------------------------------");
                    _logger.Success("Kernel", "Startup script execution completed");
                }
                else
                {
                    // 启动脚本不存在，创建空文件
                    _logger.Info("Kernel", "Startup script not found, creating empty file...");
                    System.IO.File.WriteAllText(startupFilePath, "");
                    _logger.Info("Kernel", "Created empty startup script at 0:\\system\\startup.cm");
                }
            }
            catch (Exception ex)
            {
                _logger.Error("Kernel", $"Error executing startup script: {ex.Message}");
            }
        }

        private void ExecuteStartupTest()
        {
            Console.WriteLine("------------------------------------------------------");
            Console.WriteLine($"Welcome to {CMLeonOS.Version.DisplayVersion}");
            Console.WriteLine("* Documentation: https://cmleonos.jjmm.ink/");
            Console.WriteLine("* Forum: https://lbbs.ecuil.com/#/category/10");
            // Console.WriteLine("");

            // 感觉排版有点割裂,先注释掉
            // Console.BackgroundColor = ConsoleColor.Red;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.Yellow;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.Green;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.Cyan;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.Blue;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.Magenta;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.White;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.DarkBlue;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.DarkCyan;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.DarkGreen;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.DarkYellow;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.DarkRed;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.Gray;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.DarkGray;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.DarkMagenta;
            // Console.Write("   ");
            // Console.BackgroundColor = ConsoleColor.Black;
            // Console.Write("   ");
            // Console.WriteLine("");
            // Console.ResetColor();
            Console.WriteLine("------------------------------------------------------");
        }

        private string FormatBytes(long bytes)
        {
            string[] units = { "B", "KB", "MB", "GB", "TB" };
            int unitIndex = 0;
            double size = bytes;
            
            while (size >= 1024 && unitIndex < units.Length - 1)
            {
                size /= 1024;
                unitIndex++;
            }
            
            return $"{size:F2} {units[unitIndex]}";
        }

        protected override void Run()
        {
            ProcessManager.Yield();
        }
    }
}
