// 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 System;
using Sys = Cosmos.System;
using Cosmos.HAL;
using Cosmos.Core;
using System.Threading;
using System.IO;

namespace CMLeonOS
{
    public enum BootMenuAction
    {
        NormalBoot,
        GuiBoot,
        Reboot,
        Shutdown
    }

    internal static class BootMenu
    {
        private const int MinPanelWidth = 58;
        private const int MaxPanelWidth = 86;

        private static bool UserDatExists()
        {
            return File.Exists(@"0:\system\user.dat");
        }

        private static string FitText(string text, int width)
        {
            if (string.IsNullOrEmpty(text))
            {
                return string.Empty.PadRight(width);
            }

            if (text.Length > width)
            {
                if (width <= 3)
                {
                    return text.Substring(0, width);
                }
                return text.Substring(0, width - 3) + "...";
            }

            return text.PadRight(width);
        }

        private static void WriteAt(int x, int y, string text, ConsoleColor fg, ConsoleColor bg)
        {
            if (y < 0 || y >= Console.WindowHeight)
            {
                return;
            }

            Console.SetCursorPosition(Math.Max(0, x), y);
            Console.ForegroundColor = fg;
            Console.BackgroundColor = bg;
            Console.Write(text);
        }

        private static void DrawPanelLine(int left, int top, int width, int row, string content, ConsoleColor contentFg, ConsoleColor contentBg)
        {
            int innerWidth = width - 2;
            int y = top + row;

            // Keep borders in a consistent theme color.
            WriteAt(left, y, "|", ConsoleColor.Cyan, ConsoleColor.Black);
            WriteAt(left + 1, y, FitText(content, innerWidth), contentFg, contentBg);
            WriteAt(left + width - 1, y, "|", ConsoleColor.Cyan, ConsoleColor.Black);
        }

        private static void DrawHorizontalBorder(int left, int y, int width, bool topBorder, ConsoleColor fg, ConsoleColor bg)
        {
            string mid = new string('-', width - 2);
            string line = topBorder ? ("+" + mid + "+") : ("+" + mid + "+");
            WriteAt(left, y, line, fg, bg);
        }

        private static void Render(int selIdx, int remainingTime)
        {
            Console.BackgroundColor = ConsoleColor.Black;
            Console.ForegroundColor = ConsoleColor.White;

            bool userDatExists = UserDatExists();
            string[] options = userDatExists
                ? new[] { "CMLeonOS Shell", "CMLeonOS Desktop", "Reboot", "Shutdown" }
                : new[] { "CMLeonOS Shell", "Reboot", "Shutdown" };

            int width = Console.WindowWidth;
            int height = Console.WindowHeight;
            int panelWidth = Math.Min(MaxPanelWidth, Math.Max(MinPanelWidth, width - 8));
            int panelLeft = Math.Max(0, (width - panelWidth) / 2);
            int contentLineCount = 8 + options.Length;
            int panelHeight = contentLineCount + 2;
            int panelTop = Math.Max(0, (height - panelHeight) / 2);

            DrawHorizontalBorder(panelLeft, panelTop, panelWidth, true, ConsoleColor.Cyan, ConsoleColor.Black);
            DrawPanelLine(panelLeft, panelTop, panelWidth, 1, " CMLeonOS Boot Manager ", ConsoleColor.Black, ConsoleColor.Cyan);
            DrawPanelLine(panelLeft, panelTop, panelWidth, 2, string.Empty, ConsoleColor.White, ConsoleColor.Black);

            uint mem = CPU.GetAmountOfRAM();
            DrawPanelLine(panelLeft, panelTop, panelWidth, 3, $" Version : {Version.DisplayVersion}", ConsoleColor.Gray, ConsoleColor.Black);
            DrawPanelLine(panelLeft, panelTop, panelWidth, 4, $" Memory  : {mem} MB", ConsoleColor.Gray, ConsoleColor.Black);
            DrawPanelLine(panelLeft, panelTop, panelWidth, 5, $" Build   : {GetBuildTime()}", ConsoleColor.DarkGray, ConsoleColor.Black);
            DrawPanelLine(panelLeft, panelTop, panelWidth, 6, string.Empty, ConsoleColor.White, ConsoleColor.Black);
            DrawPanelLine(panelLeft, panelTop, panelWidth, 7, $" Auto boot in {remainingTime}s", ConsoleColor.Yellow, ConsoleColor.Black);
            DrawPanelLine(panelLeft, panelTop, panelWidth, 8, " Use Up/Down to select, Enter to boot", ConsoleColor.DarkGray, ConsoleColor.Black);

            for (int i = 0; i < options.Length; i++)
            {
                bool selected = i == selIdx;
                string prefix = selected ? " > " : "   ";
                string text = prefix + options[i];
                DrawPanelLine(
                    panelLeft,
                    panelTop,
                    panelWidth,
                    9 + i,
                    text,
                    selected ? ConsoleColor.Black : ConsoleColor.White,
                    selected ? ConsoleColor.White : ConsoleColor.Black
                );
            }

            DrawHorizontalBorder(panelLeft, panelTop + panelHeight - 1, panelWidth, false, ConsoleColor.Cyan, ConsoleColor.Black);
            Console.ResetColor();
        }

        private static BootMenuAction Confirm(int selIdx)
        {
            Console.BackgroundColor = ConsoleColor.Black;
            Console.ForegroundColor = ConsoleColor.White;

            Console.Clear();

            Console.SetCursorPosition(0, 0);

            Console.CursorVisible = true;

            bool userDatExists = UserDatExists();
            int optionIndex = 0;

            if (selIdx == optionIndex++)
            {
                return BootMenuAction.NormalBoot;
            }
            if (userDatExists && selIdx == optionIndex++)
            {
                return BootMenuAction.GuiBoot;
            }
            if (selIdx == optionIndex++)
            {
                Sys.Power.Reboot();
                return BootMenuAction.Reboot;
            }
            if (selIdx == optionIndex++)
            {
                Sys.Power.Shutdown();
                return BootMenuAction.Shutdown;
            }

            return BootMenuAction.NormalBoot;
        }

        public static BootMenuAction Show()
        {
            if (Settings.SettingsManager.SkipToGui && UserDatExists())
            {
                return BootMenuAction.GuiBoot;
            }
            
            Console.BackgroundColor = ConsoleColor.Black;
            Console.ForegroundColor = ConsoleColor.White;

            Console.Clear();

            Console.CursorVisible = false;

            int selIdx = 0;
            int remainingTime = 10;
            int counter = 0;

            while (true)
            {
                Render(selIdx, remainingTime);

                if (Sys.KeyboardManager.TryReadKey(out var key))
                {
                    if (key.Key == Sys.ConsoleKeyEx.Enter)
                    {
                        return Confirm(selIdx);
                    }
                    else if (key.Key == Sys.ConsoleKeyEx.DownArrow)
                    {
                        selIdx++;
                        remainingTime = 10;
                        counter = 0;
                    }
                    else if (key.Key == Sys.ConsoleKeyEx.UpArrow)
                    {
                        selIdx--;
                        remainingTime = 10;
                        counter = 0;
                    }
                }
                else
                {
                    Thread.Sleep(100);
                    counter++;

                    if (counter >= 10)
                    {
                        remainingTime--;
                        counter = 0;

                        if (remainingTime <= 0)
                        {
                            return Confirm(selIdx);
                        }
                    }
                }

                int maxOptionIndex = UserDatExists() ? 3 : 2;

                if (selIdx < 0)
                {
                    selIdx = maxOptionIndex;
                }

                if (selIdx > maxOptionIndex)
                {
                    selIdx = 0;
                }
            }
        }

        private static string GetBuildTime()
        {
            try
            {
                if (Kernel.buildTimeFile != null && Kernel.buildTimeFile.Length > 0)
                {
                    return System.Text.Encoding.UTF8.GetString(Kernel.buildTimeFile);
                }
            }
            catch
            {
            }
            return "Unknown";
        }
    }
}
