// 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.UILib.Animations;
using System.Drawing;

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

        internal static StartMenu CurrentStartMenu
        {
            get
            {
                StartMenu startMenu = ProcessManager.GetProcess<StartMenu>();
                if (startMenu == null && ProcessManager.GetProcess<Taskbar>() != null)
                {
                    startMenu = (StartMenu)ProcessManager.AddProcess(ProcessManager.GetProcess<WindowManager>(), new StartMenu());
                    startMenu.Start();
                }
                return startMenu;
            }
        }

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

        Window window;

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

        SettingsService settingsService = ProcessManager.GetProcess<SettingsService>();

        private Button shutdownButton;
        private Button rebootButton;
        private Button allAppsButton;

        private const int buttonsPadding = 12;
        private const int buttonsWidth = 96;
        private const int buttonsHeight = 20;
        private const int userHeight = 56;
        private const int userPadding = 12;
        private const int searchWidth = 128;

        private bool isOpen = false;

        internal void ShowStartMenu(bool focusSearch = false)
        {
            isOpen = true;

            bool leftHandStartButton = settingsService.LeftHandStartButton;

            window = new Window(this, leftHandStartButton ? 0 : (int)(wm.ScreenWidth / 2 - 408 / 2), 24, 408, 222);

            window.Clear(Color.FromArgb(56, 56, 71));

            window.DrawString($"Start", Color.White, 12, 12);

            Rectangle userRect = new Rectangle(userPadding, window.Height - userHeight + userPadding, window.Width - (userPadding * 2), userHeight - (userPadding * 2));
            window.DrawImageAlpha(Icons.Icon_User, userRect.X, (int)(userRect.Y + (userRect.Height / 2) - (Icons.Icon_User.Height / 2)));
            window.DrawString(UserSystem.CurrentLoggedInUser.Username, Color.White, (int)(userRect.X + Icons.Icon_User.Width + userPadding), (int)(userRect.Y + (userRect.Height / 2) - (16 / 2)));

            wm.AddWindow(window);

            int x = 12;
            int y = 44;
            for (int i = 0; i < 4; i++)
            {
                AppMetadata app = AppManager.AppMetadatas[i];

                Button appButton = new Button(window, x, y, 90, 90);

                appButton.Background = app.ThemeColor;
                appButton.Foreground = app.ThemeColor.GetForegroundColour();

                appButton.Text = app.Name;
                appButton.Image = app.Icon;

                appButton.OnClick = (x, y) =>
                {
                    app.Start(this);
                    HideStartMenu();
                };

                wm.AddWindow(appButton);

                x += appButton.Width + 8;
                if (x > window.Width - 90)
                {
                    x = 12;
                    y += 90 + 8;
                }
            }

            shutdownButton = new Button(window, window.Width - buttonsWidth - buttonsPadding, window.Height - buttonsHeight - ((userHeight / 2) - (buttonsHeight / 2)), buttonsWidth, buttonsHeight);
            shutdownButton.Text = "Shut down";
            shutdownButton.OnClick = ShutdownClicked;
            wm.AddWindow(shutdownButton);

            rebootButton = new Button(window, window.Width - (buttonsPadding * 2 + buttonsWidth * 2), window.Height - buttonsHeight - ((userHeight / 2) - (buttonsHeight / 2)), buttonsWidth, buttonsHeight);
            rebootButton.Text = "Restart";
            rebootButton.OnClick = RebootClicked;
            wm.AddWindow(rebootButton);

            allAppsButton = new Button(window, window.Width - buttonsWidth - buttonsPadding, window.Height - buttonsHeight - userHeight, buttonsWidth, buttonsHeight);
            allAppsButton.Text = "All apps >";
            allAppsButton.OnClick = AllAppsClicked;
            wm.AddWindow(allAppsButton);

            Table searchResults = null;
            TextBox searchBox = new TextBox(window, (window.Width / 2) - (searchWidth / 2), 12, searchWidth, 20);
            if (focusSearch)
            {
                wm.Focus = searchBox;
            }
            searchBox.PlaceholderText = "Search";
            searchBox.Changed = () =>
            {
                if (searchResults == null)
                {
                    searchResults = new Table(searchBox, 0, searchBox.Height, searchBox.Width, 0);

                    searchResults.CellHeight = 24;

                    searchResults.TableCellSelected = (int index) =>
                    {
                        if (index != -1)
                        {
                            ((AppMetadata)searchResults.Cells[index].Tag).Start(this);
                            HideStartMenu();
                        }
                    };
                }

                searchResults.Cells.Clear();

                if (searchBox.Text.Trim().Length > 0)
                {
                    foreach (AppMetadata app in AppManager.AppMetadatas)
                    {
                        if (app.Name.ToLower().StartsWith(searchBox.Text.ToLower()))
                        {
                            string name = app.Name;
                            if (name.Length > 8)
                            {
                                name = name.Substring(0, 8).Trim() + "...";
                            }
                            searchResults.Cells.Add(new TableCell(app.Icon.Resize(20, 20), name, tag: app));
                        }
                    }
                }

                if (searchResults.Cells.Count > 0)
                {
                    searchResults.Resize(searchResults.Width, searchResults.Cells.Count * searchResults.CellHeight);
                    searchResults.Render();

                    wm.AddWindow(searchResults);

                    wm.Update(searchResults);
                }
                else
                {
                    wm.RemoveWindow(searchResults);
                }
            };
            searchBox.Submitted = () =>
            {
                searchBox.Text = string.Empty;
                wm.Update(searchBox);

                if (searchResults != null && searchResults.Cells.Count > 0)
                {
                    ((AppMetadata)searchResults.Cells[0].Tag).Start(this);
                    HideStartMenu();
                }
            };
            searchBox.OnUnfocused = () =>
            {
                if (searchResults != null)
                {
                    wm.RemoveWindow(searchResults);
                    searchResults = null;

                    searchBox.Text = string.Empty;
                    wm.Update(searchBox);
                }
            };
            wm.AddWindow(searchBox);

            wm.Update(window);
        }

        private void ShutdownClicked(int x, int y)
        {
            Power.Shutdown(reboot: false);
        }

        private void RebootClicked(int x, int y)
        {
            Power.Shutdown(reboot: true);
        }

        private void AllAppsClicked(int x, int y)
        {
            Table allAppsTable = new Table(window, 0, 0, window.Width, window.Height);

            allAppsTable.CellHeight = 32;

            allAppsTable.Background = Color.FromArgb(56, 56, 71);
            allAppsTable.Foreground = Color.White;
            allAppsTable.Border = Color.FromArgb(36, 36, 51);

            foreach (AppMetadata app in AppManager.AppMetadatas)
            {
                TableCell cell = new TableCell(app.Icon.Resize(20, 20), app.Name);
                /*cell.BackgroundColourOverride = app.ThemeColor;
                cell.ForegroundColourOverride = app.ThemeColor.GetForegroundColour();*/
                allAppsTable.Cells.Add(cell);
            }
            allAppsTable.Render();

            allAppsTable.TableCellSelected = (int index) =>
            {
                if (index != -1)
                {
                    AppManager.AppMetadatas[index].Start(this);
                    HideStartMenu();
                }
            };

            wm.AddWindow(allAppsTable);

            MovementAnimation animation = new MovementAnimation(allAppsTable)
            {
                From = new Rectangle(allAppsTable.X, allAppsTable.Y, allAppsTable.Width, allAppsTable.Height),
                To = new Rectangle(allAppsTable.X, allAppsTable.Y, allAppsTable.Width, allAppsTable.Height + 64),
                Duration = 5
            };
            animation.Start();

            wm.Update(allAppsTable);
        }

        internal void HideStartMenu()
        {
            isOpen = false;
            wm.RemoveWindow(window);
        }

        internal void ToggleStartMenu(bool focusSearch = false)
        {
            if (isOpen)
            {
                HideStartMenu();
            }
            else
            {
                ShowStartMenu(focusSearch);
            }
        }

        public override void Start()
        {
            base.Start();
        }

        public override void Run()
        {
        }
    }
}
