// 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 Cosmos.System.Graphics;
using CMLeonOS;
using CMLeonOS.Gui.UILib;
using CMLeonOS.Settings;
using CMLeonOS.Utils;
using System;
using System.Drawing;
using System.IO;

namespace CMLeonOS.Gui.Apps
{
    internal class Settings : Process
    {
        internal Settings() : base("Settings", ProcessType.Application) { }

        AppWindow window;

        Window currentCategoryWindow;
        private FileBrowser wallpaperBrowser;

        WindowManager wm = ProcessManager.GetProcess<WindowManager>();

        private static class Icons
        {
            [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Settings.User.bmp")]
            private static byte[] _iconBytes_User;
            internal static Bitmap Icon_User = new Bitmap(_iconBytes_User);

            [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Settings.Admin.bmp")]
            private static byte[] _iconBytes_Admin;
            internal static Bitmap Icon_Admin = new Bitmap(_iconBytes_Admin);

            [IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Settings.Info.bmp")]
            private static byte[] _iconBytes_Info;
            internal static Bitmap Icon_Info = new Bitmap(_iconBytes_Info);
        }

        private void CategorySelected(int index)
        {
            switch (index)
            {
                case 0:
                    ShowAppearanceCategory();
                    break;
                case 1:
                    ShowDisplayCategory();
                    break;
                case 2:
                    ShowDateTimeCategory();
                    break;
                case 3:
                    ShowUsersCategory();
                    break;
                case 4:
                    ShowMouseCategory();
                    break;
                default:
                    return;
            }
        }

        private void LeftStartButtonChanged(bool @checked)
        {
            SettingsManager.GUI_LeftHandStartButton = @checked;
        }

        private void TwelveHourClockChanged(bool @checked)
        {
            SettingsManager.GUI_TwelveHourClock = @checked;
        }

        private void ShowFpsChanged(bool @checked)
        {
            SettingsManager.GUI_ShowFps = @checked;
        }

        private void SkipToGuiChanged(bool @checked)
        {
            SettingsManager.SkipToGui = @checked;
        }

        private void ShowMessage(string title, string text)
        {
            MessageBox messageBox = new MessageBox(this, title, text);
            messageBox.Show();
        }

        private string GetWallpaperLabel()
        {
            string path = SettingsManager.GUI_WallpaperPath;
            if (string.IsNullOrWhiteSpace(path))
            {
                return "Current wallpaper: Default";
            }

            string fileName = Path.GetFileName(path);
            if (string.IsNullOrWhiteSpace(fileName))
            {
                fileName = path;
            }

            return $"Current wallpaper: {fileName}";
        }

        private void ApplyWallpaper(string path)
        {
            string sanitizedPath = string.IsNullOrWhiteSpace(path) ? string.Empty : PathUtil.Sanitize(path.Trim());

            if (!string.IsNullOrWhiteSpace(sanitizedPath))
            {
                if (!File.Exists(sanitizedPath))
                {
                    ShowMessage("Wallpaper", "File not found.");
                    return;
                }

                if (!Path.GetExtension(sanitizedPath).Equals(".bmp", StringComparison.OrdinalIgnoreCase))
                {
                    ShowMessage("Wallpaper", "Only BMP wallpapers are supported.");
                    return;
                }
            }

            if (!wm.ApplyWallpaper(sanitizedPath))
            {
                ShowMessage("Wallpaper", "Failed to apply wallpaper.");
                return;
            }

            SettingsManager.GUI_WallpaperPath = sanitizedPath;
            ShowAppearanceCategory();
        }

        private void OpenWallpaperBrowser()
        {
            wallpaperBrowser = new FileBrowser(this, wm, (string selectedPath) =>
            {
                if (!string.IsNullOrWhiteSpace(selectedPath))
                {
                    ApplyWallpaper(selectedPath);
                }
            }, selectDirectoryOnly: false);
            wallpaperBrowser.Show();
        }

        private void MouseSensitivityChanged(float value)
        {
            SettingsManager.GUI_MouseSensitivity = value;
        }

        private void ThemeChanged(int index, string themeName)
        {
            SettingsManager.GUI_Theme = themeName;
            UITheme.ApplyTheme(themeName);
            UITheme.RefreshOpenWindows(wm);
            ShowAppearanceCategory();
        }

        private void ShowAppearanceCategory()
        {
            if (currentCategoryWindow != null)
            {
                wm.RemoveWindow(currentCategoryWindow);
            }
            Window appearance = new Window(this, window, 128, 0, window.Width - 128, window.Height);
            currentCategoryWindow = appearance;
            appearance.DrawString("Appearance Settings", Color.DarkBlue, 12, 12);
            wm.AddWindow(appearance);

            Switch leftStartButton = new Switch(appearance, 12, 40, 244, 16);
            leftStartButton.Text = "Left-hand start button";
            leftStartButton.Checked = SettingsManager.GUI_LeftHandStartButton;
            leftStartButton.CheckBoxChanged = LeftStartButtonChanged;
            wm.AddWindow(leftStartButton);

            Switch showFps = new Switch(appearance, 12, 68, 244, 16);
            showFps.Text = "Show frames per second";
            showFps.Checked = SettingsManager.GUI_ShowFps;
            showFps.CheckBoxChanged = ShowFpsChanged;
            wm.AddWindow(showFps);

            Switch skipToGui = new Switch(appearance, 12, 96, 244, 16);
            skipToGui.Text = "Skip to GUI on boot";
            skipToGui.Checked = SettingsManager.SkipToGui;
            skipToGui.CheckBoxChanged = SkipToGuiChanged;
            wm.AddWindow(skipToGui);

            appearance.DrawString("Theme", Color.Gray, 12, 126);

            Dropdown themeDropdown = new Dropdown(appearance, 12, 146, 180, 24);
            string[] themes = UITheme.GetThemeNames();
            for (int i = 0; i < themes.Length; i++)
            {
                themeDropdown.Items.Add(themes[i]);
            }
            themeDropdown.RefreshItems();
            for (int i = 0; i < themes.Length; i++)
            {
                if (themes[i] == SettingsManager.GUI_Theme)
                {
                    themeDropdown.SelectedIndex = i;
                    break;
                }
            }
            themeDropdown.SelectionChanged = ThemeChanged;
            wm.AddWindow(themeDropdown);

            appearance.DrawString("Wallpaper", Color.Gray, 12, 184);
            appearance.DrawString(GetWallpaperLabel(), Color.Black, 12, 204);
            appearance.DrawString("Use a BMP file or restore the default wallpaper.", Color.Gray, 12, 222);

            Button chooseWallpaper = new Button(appearance, 12, 244, 132, 24);
            chooseWallpaper.Text = "Choose BMP";
            chooseWallpaper.OnClick = (_, _) => OpenWallpaperBrowser();
            wm.AddWindow(chooseWallpaper);

            Button defaultWallpaper = new Button(appearance, 154, 244, 132, 24);
            defaultWallpaper.Text = "Use Default";
            defaultWallpaper.OnClick = (_, _) => ApplyWallpaper(string.Empty);
            wm.AddWindow(defaultWallpaper);

            wm.Update(window);
        }

        private void ShowDateTimeCategory()
        {
            if (currentCategoryWindow != null)
            {
                wm.RemoveWindow(currentCategoryWindow);
            }
            Window dateTime = new Window(this, window, 128, 0, window.Width - 128, window.Height);
            currentCategoryWindow = dateTime;
            dateTime.DrawString("Date & Time Settings", Color.DarkBlue, 12, 12);
            wm.AddWindow(dateTime);

            Switch twelveHourClock = new Switch(dateTime, 12, 40, 244, 16);
            twelveHourClock.Text = "12-hour clock";
            twelveHourClock.Checked = SettingsManager.GUI_TwelveHourClock;
            twelveHourClock.CheckBoxChanged = TwelveHourClockChanged;
            wm.AddWindow(twelveHourClock);

            AppMetadata calendarApp = AppManager.GetAppMetadata("Calendar");
            Button openCalendar = new Button(dateTime, 12, 68, 160, 20);
            openCalendar.Text = "Open Calendar";
            openCalendar.Image = calendarApp.Icon.Resize(20, 20);
            openCalendar.ImageLocation = Button.ButtonImageLocation.Left;
            openCalendar.OnClick = (int x, int y) =>
            {
                calendarApp.Start(wm);
            };
            wm.AddWindow(openCalendar);

            wm.Update(window);
        }

        private void ShowDisplayCategory()
        {

            if (currentCategoryWindow != null)
            {
                wm.RemoveWindow(currentCategoryWindow);
            }
            Window display = new Window(this, window, 128, 0, window.Width - 128, window.Height);
            currentCategoryWindow = display;
            display.DrawString("Display Settings", Color.DarkBlue, 12, 12);
            wm.AddWindow(display);

            Table resolutionsTable = new Table(display, 12, 40, display.Width - 24, display.Height - 12 - 16 - 12 - 12 - 16 - 12);
            resolutionsTable.AllowDeselection = false;
            for (int i = 0; i < wm.AvailableModes.Count; i++)
            {
                Mode mode = wm.AvailableModes[i];
                resolutionsTable.Cells.Add(new TableCell($"{mode.Width}x{mode.Height}"));
                if (mode.Width == SettingsManager.GUI_ScreenWidth && mode.Height == SettingsManager.GUI_ScreenHeight)
                {
                    resolutionsTable.SelectedCellIndex = i;
                }
            }
            resolutionsTable.Render();
            resolutionsTable.TableCellSelected = (int index) =>
            {
                Mode mode = wm.AvailableModes[index];
                SettingsManager.GUI_ScreenWidth = (int)mode.Width;
                SettingsManager.GUI_ScreenHeight = (int)mode.Height;

                MessageBox messageBox = new MessageBox(this, "Restart Required", "Restart your PC to apply changes.");
                messageBox.Show();
            };
            wm.AddWindow(resolutionsTable);

            display.DrawImageAlpha(Icons.Icon_Info, 12, window.Height - 16 - 12);
            display.DrawString("Select a screen resolution.", Color.Gray, 36, window.Height - 16 - 12);

            wm.AddWindow(display);

            wm.Update(display);
        }

        private void ShowUsersCategory()
        {
            if (currentCategoryWindow != null)
            {
                wm.RemoveWindow(currentCategoryWindow);
            }
            Window users = new Window(this, window, 128, 0, window.Width - 128, window.Height);
            currentCategoryWindow = users;
            users.DrawString("Users", Color.DarkBlue, 12, 12);
            users.DrawImageAlpha(Icons.Icon_Info, 12, window.Height - 16 - 12);
            users.DrawString("Double-click a user for details.", Color.Gray, 36, window.Height - 16 - 12);
            wm.AddWindow(users);

            bool canManageUsers = UserSystem.CurrentLoggedInUser != null && UserSystem.CurrentLoggedInUser.Admin;
            Table usersTable = null;

            if (canManageUsers)
            {
                Button createUser = new Button(users, 12, 40, 108, 22);
                createUser.Text = "Create User";
                createUser.OnClick = (_, _) =>
                {
                    PromptBox promptBox = new PromptBox(this, "Create User", "Enter username and password.\nFormat: username password", "newuser password", (string value) =>
                    {
                        string[] parts = (value ?? string.Empty).Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        if (parts.Length < 2)
                        {
                            ShowMessage("Users", "Use the format: username password");
                            return;
                        }

                        bool created = UserManager.AddUser(parts[0], parts[1], false);
                        if (!created)
                        {
                            ShowMessage("Users", "Failed to create user.");
                            return;
                        }

                        ShowMessage("Users", $"User '{parts[0]}' created.");
                        ShowUsersCategory();
                    });
                    promptBox.Show();
                };
                wm.AddWindow(createUser);

                Button deleteUser = new Button(users, 130, 40, 108, 22);
                deleteUser.Text = "Delete User";
                deleteUser.OnClick = (_, _) =>
                {
                    if (usersTable.SelectedCellIndex == -1)
                    {
                        ShowMessage("Users", "Select a user first.");
                        return;
                    }

                    User selectedUser = (User)usersTable.Cells[usersTable.SelectedCellIndex].Tag;
                    if (selectedUser == null)
                    {
                        ShowMessage("Users", "Select a valid user first.");
                        return;
                    }

                    if (UserSystem.CurrentLoggedInUser != null
                        && selectedUser.Username.Equals(UserSystem.CurrentLoggedInUser.Username, StringComparison.OrdinalIgnoreCase))
                    {
                        ShowMessage("Users", "You cannot delete the current logged in user.");
                        return;
                    }

                    bool deleted = UserManager.RemoveUser(selectedUser.Username);
                    if (!deleted)
                    {
                        ShowMessage("Users", "Failed to delete user.");
                        return;
                    }

                    ShowMessage("Users", $"User '{selectedUser.Username}' deleted.");
                    ShowUsersCategory();
                };
                wm.AddWindow(deleteUser);
            }
            else
            {
                users.DrawString("Only administrators can create or delete users.", Color.Gray, 12, 44);
            }

            int tableY = canManageUsers ? 74 : 40;
            usersTable = new Table(users, 12, tableY, users.Width - 24, users.Height - tableY - 12 - 16 - 12);
            foreach (User user in UserSystem.GetUsers())
            {
                usersTable.Cells.Add(new TableCell(user.Admin ? Icons.Icon_Admin : Icons.Icon_User, user.Username, tag: user));
            }
            usersTable.OnDoubleClick = (int x, int y) =>
            {
                if (usersTable.SelectedCellIndex != -1)
                {
                    User user = (User)usersTable.Cells[usersTable.SelectedCellIndex].Tag;

                    AppWindow userDetail = new AppWindow(this, 256, 256, 256, 192);
                    userDetail.Title = user.Username;
                    wm.AddWindow(userDetail);

                    userDetail.DrawFilledRectangle(0, 0, userDetail.Width, 40, Color.DarkBlue);
                    userDetail.DrawImageAlpha(user.Admin ? Icons.Icon_Admin : Icons.Icon_User, 12, 12);
                    userDetail.DrawString($"User: {user.Username}", Color.White, 36, 12);

                    userDetail.DrawString($"Role: {(user.Admin ? "Admin" : "User")}", Color.Black, 12, 48);
                    userDetail.DrawString($"Unread messages: {user.Messages.Count}", Color.Black, 12, 76);

                    Button ok = new Button(userDetail, userDetail.Width - 80 - 12, userDetail.Height - 20 - 12, 80, 20);
                    ok.Text = "OK";
                    ok.OnClick = (int x, int y) =>
                    {
                        wm.RemoveWindow(userDetail);
                    };
                    wm.AddWindow(ok);

                    wm.Update(userDetail);
                }
            };
            usersTable.Render();
            wm.AddWindow(usersTable);

            wm.Update(window);
        }

        private void ShowMouseCategory()
        {
            if (currentCategoryWindow != null)
            {
                wm.RemoveWindow(currentCategoryWindow);
            }
            Window mouse = new Window(this, window, 128, 0, window.Width - 128, window.Height);
            currentCategoryWindow = mouse;
            mouse.DrawString("Mouse Settings", Color.DarkBlue, 12, 12);
            wm.AddWindow(mouse);

            mouse.DrawString("Mouse sensitivity", Color.Gray, 12, 40);

            RangeSlider mouseSensitivity = new RangeSlider(mouse, 12, 68, 244, 30, min: 0.25f, value: SettingsManager.GUI_MouseSensitivity, max: 2f);
            mouseSensitivity.Changed = MouseSensitivityChanged;
            wm.AddWindow(mouseSensitivity);

            wm.Update(window);
        }

        #region Process
        public override void Start()
        {
            base.Start();
            window = new AppWindow(this, 256, 256, 448, 272);
            window.Closing = () => 
            {
                SettingsManager.FlushSettings();
                TryStop();
            };
            window.Icon = AppManager.GetAppMetadata("Settings").Icon;
            wm.AddWindow(window);

            window.Title = "Settings";

            Table categoryTable = new Table(window, 0, 0, 128, window.Height);

            categoryTable.TextAlignment = Alignment.Middle;

            categoryTable.TableCellSelected = CategorySelected;
            categoryTable.SelectedCellIndex = 0;
            categoryTable.AllowDeselection = false;

            categoryTable.CellHeight = 24;

            /*categoryTable.Border = categoryTable.Background;
            categoryTable.SelectedBorder = categoryTable.SelectedBackground;*/

            categoryTable.Cells.Add(new TableCell("Appearance"));
            categoryTable.Cells.Add(new TableCell("Display"));
            categoryTable.Cells.Add(new TableCell("Date & Time"));
            categoryTable.Cells.Add(new TableCell("Users"));
            categoryTable.Cells.Add(new TableCell("Mouse"));

            categoryTable.Render();

            wm.AddWindow(categoryTable);

            ShowAppearanceCategory();

            wm.Update(window);
        }

        public override void Run()
        {
        }
        #endregion
    }
}
