using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Sonex.Client.Controls;
using Sonex.Client.Dialogs;
using Sonex.Data.Database;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Windows.Graphics;
using Windows.System;
using Windows.UI;
using WinRT.Interop;
using Logger = Sonex.Client.Helpers.Logger;

namespace Sonex.Client.AppWindows
{
    public sealed partial class LoginWindow : Window
    {
        private const double TargetWidthDip = 680;
        private const double TargetHeightDip = 420;

        private const int WM_DPICHANGED = 0x02E0;
        private const int GWL_WNDPROC = -4;

        private const int SW_HIDE = 0;
        private const int SW_SHOW = 5;

        private const string AutoThemeName = "Auto";
        private const string DefaultThemeName = "Default";

        private IntPtr _hwnd;
        private WndProcDelegate? _newWndProc;
        private IntPtr _oldWndProc;

        private bool _windowInitialized = false;
        private bool _startupInitialized = false;
        private bool _inLogin = false;
        private int _loginAttempts = 0;

        private readonly Dictionary<string, ThemeDefinition> _themes = new(StringComparer.OrdinalIgnoreCase);

        public LoginWindow()
        {
            Debug.WriteLine(Config._filePath);
            InitializeComponent();
            Closed += LoginWindow_Closed;
        }

        /// <summary>
        /// Wywołaj przed Activate().
        /// </summary>
        public void PrepareBeforeShow()
        {
            if (_windowInitialized)
                return;

            _windowInitialized = true;

            _hwnd = WindowNative.GetWindowHandle(this);
            HookWndProc();

            ExtendsContentIntoTitleBar = true;
            SetTitleBar(_TitleBar);

            ConfigureWindowChrome();
            ApplyFixedSizeDip(center: true);
            ApplyWindowIcon();

            _VersionInfo.Text = $"Version {AppInfo.InformationalVersion.Trim()}";

            string userName = Config.GetStringValue("USER_NAME", "");
            bool keepLogIn = Config.GetBoolValue("KEEP_LOG_IN", false);

            _UserName.Text = userName;
            _KeepLogIn.IsChecked = keepLogIn;

            LoadThemes();
            BuildThemeMenu();

            RootGrid.ActualThemeChanged += RootGrid_ActualThemeChanged;

            string themeLight = Config.GetStringValue("THEME_LIGHT", AutoThemeName);
            string themeName = Config.GetStringValue("THEME_NAME", AutoThemeName);

            SetThemeLight(themeLight);
            SetThemeMode(themeName, reloadBackground: false);

            RootGrid.Opacity = 0;

            _BackgroundAnimation.Loaded += BackgroundAnimation_Loaded;
        }

        public void HideNative()
        {
            if (_hwnd != IntPtr.Zero)
                ShowWindow(_hwnd, SW_HIDE);
        }

        public void ShowNative()
        {
            if (_hwnd != IntPtr.Zero)
                ShowWindow(_hwnd, SW_SHOW);
        }

        private void ConfigureWindowChrome()
        {
            if (AppWindow.Presenter is OverlappedPresenter presenter)
            {
                presenter.IsMaximizable = false;
                presenter.IsResizable = false;
                presenter.IsMinimizable = true;
                presenter.SetBorderAndTitleBar(true, true);
            }

            AppWindow.Changed += AppWindow_Changed;
        }

        private void ApplyWindowIcon()
        {
            string iconPath = Path.Combine(AppContext.BaseDirectory, "Assets", "AppIcon.ico");
            if (File.Exists(iconPath))
                AppWindow.SetIcon(iconPath);
        }

        private async void BackgroundAnimation_Loaded(object sender, RoutedEventArgs e)
        {
            if (_startupInitialized)
                return;

            _startupInitialized = true;
            _BackgroundAnimation.Loaded -= BackgroundAnimation_Loaded;

            try
            {
                await Task.Yield();
            }
            catch (Exception ex)
            {
                Logger.Error(
                    ex,
                    source: nameof(LoginWindow),
                    operation: "BackgroundAnimation_Loaded");
            }
            finally
            {
                RootGrid.Opacity = 1;
                ShowNative();
                AppWindowsHelper.BringToFront(this);

                if (!string.IsNullOrEmpty(_UserName.Text))
                    _Password.Focus(FocusState.Programmatic);
            }
        }

        private void _Login_Click(object sender, RoutedEventArgs e)
        {
            LoginAsync();
        }

        private void _TextBox_KeyDown(object sender, KeyRoutedEventArgs e)
        {
            if (e.Key == VirtualKey.Enter)
                LoginAsync();
        }

        private async void LoginAsync()
        {
            if (_inLogin)
                return;

            _inLogin = true;
            _loginAttempts++;

            string username = _UserName.Text ?? "";
            string password = _Password.Password ?? "";
            bool keepLogIn = _KeepLogIn.IsChecked ?? false;

            Config.SetValue("USER_NAME", username);
            Config.SetValue("KEEP_LOG_IN", keepLogIn);

            string dbHost = Config.GetStringValue("DB_HOST", "X-WEB-TEXT");
            int dbPort = Config.GetIntValue("DB_PORT", 5432);
            string dbDataBase = Config.GetStringValue("DB_DATA_BASE", "sonex");
            int timeout = Config.GetIntValue("DB_TIMEOUT", 15);
            int commandTimeout = Config.GetIntValue("DB_COMMAND_TIMEOUT", 30);
            bool pooling = Config.GetBoolValue("DB_POOLING", true);
            int minPoolSize = Config.GetIntValue("DB_MIN_POOL_SIZE", 0);
            int maxPoolSize = Config.GetIntValue("DB_MAXPOOLSIZE", 100);
            bool includeErrorDetail = Config.GetBoolValue("DB_INCLUDE_ERROR_DETAIL", false);

            bool success = false;

            try
            {
                await Task.Run(() =>
                {
                    DB.InitPostgreSQL(
                        host: dbHost,
                        port: dbPort,
                        database: dbDataBase,
                        username: username,
                        password: password,
                        applicationName: DB.ClientSessionInfo?.BuildDatabaseApplicationName(),
                        timeout: timeout,
                        commandTimeout: commandTimeout,
                        pooling: pooling,
                        minPoolSize: minPoolSize,
                        maxPoolSize: maxPoolSize,
                        includeErrorDetail: includeErrorDetail);

                    using var connection = DB.Open();
                });
                success = true;
            }
            catch (Exception ex)
            {
                if (Logger.IsBusinessDatabaseException(ex))
                {
                    await this.ShowMessageAsync("Error", ex.Message);
                }
                else
                {
                    string errorId = Logger.Error(
                        ex,
                        source: nameof(LoginWindow),
                        operation: nameof(LoginAsync),
                        context: new Dictionary<string, string?>
                        {
                            ["DbHost"] = dbHost,
                            ["DbDatabase"] = dbDataBase,
                            ["LoginAttempt"] = _loginAttempts.ToString()
                        });
                    
                    await this.ShowMessageAsync("Login Error", ex?.Message?? "Unknown error");
                }
            }
            finally
            {
                _inLogin = false;
            }

            if (success)
                OpenMainWindow();
        }

        public void OpenMainWindow()
        {
            if (Application.Current is App app)
                app.OpenMainWindow();
        }

        private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
        {
            if (sender.Presenter is OverlappedPresenter presenter)
            {
                if (presenter.State == OverlappedPresenterState.Maximized)
                    presenter.Restore();
            }
        }

        private void ApplyFixedSizeDip(bool center)
        {
            if (_hwnd == IntPtr.Zero)
                return;

            uint dpi = GetDpiForWindow(_hwnd);

            int pxW = DipToPx(TargetWidthDip, dpi);
            int pxH = DipToPx(TargetHeightDip, dpi);

            AppWindow.Resize(new SizeInt32(pxW, pxH));

            if (center)
                AppWindowsHelper.CenterWindow(this, pxW, pxH);
        }

        private static int DipToPx(double dip, uint dpi)
            => (int)Math.Round(dip * dpi / 96.0);

        private void HookWndProc()
        {
            if (_hwnd == IntPtr.Zero)
                return;

            _newWndProc = WndProc;
            _oldWndProc = SetWindowLongPtr(_hwnd, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(_newWndProc));
        }

        private void UnhookWndProc()
        {
            if (_hwnd == IntPtr.Zero || _oldWndProc == IntPtr.Zero)
                return;

            SetWindowLongPtr(_hwnd, GWL_WNDPROC, _oldWndProc);
            _oldWndProc = IntPtr.Zero;
            _newWndProc = null;
        }

        private IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam)
        {
            if (msg == WM_DPICHANGED)
                ApplyFixedSizeDip(center: false);

            return CallWindowProc(_oldWndProc, hWnd, msg, wParam, lParam);
        }

        private void LoginWindow_Closed(object sender, WindowEventArgs args)
        {
            try
            {
                AppWindow.Changed -= AppWindow_Changed;
            }
            catch
            {
            }

            try
            {
                _BackgroundAnimation.Loaded -= BackgroundAnimation_Loaded;
            }
            catch
            {
            }

            try
            {
                RootGrid.ActualThemeChanged -= RootGrid_ActualThemeChanged;
            }
            catch
            {
            }

            UnhookWndProc();
        }

        private delegate IntPtr WndProcDelegate(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr newProc);

        [DllImport("user32.dll")]
        private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern uint GetDpiForWindow(IntPtr hwnd);

        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        private static string NormalizeThemeLight(string themeLight)
        {
            return themeLight switch
            {
                "Auto" => "Auto",
                "Dark" => "Dark",
                "Light" => "Light",
                _ => "Auto"
            };
        }

        private void _ThemeLight_Change(object sender, RoutedEventArgs e)
        {
            if (sender is not RadioMenuFlyoutItem button)
                return;

            string text = NormalizeThemeLight(button.Text);
            Config.SetValue("THEME_LIGHT", text);
            SetThemeLight(text);
        }

        private void SetThemeLight(string themeLight)
        {
            themeLight = NormalizeThemeLight(themeLight);

            RootGrid.RequestedTheme = themeLight switch
            {
                "Auto" => ElementTheme.Default,
                "Dark" => ElementTheme.Dark,
                "Light" => ElementTheme.Light,
                _ => ElementTheme.Default
            };

            ApplyTitleBarTheme(this, RootGrid.ActualTheme == ElementTheme.Dark);
            SelectRadioMenuItem("Color mode", themeLight, useTag: false);

            RootGrid.UpdateLayout();

            string themeName = Config.GetStringValue("THEME_NAME", AutoThemeName);
            SetThemeMode(themeName, reloadBackground: false);
        }

        private void RootGrid_ActualThemeChanged(FrameworkElement sender, object args)
        {
            ApplyTitleBarTheme(this, RootGrid.ActualTheme == ElementTheme.Dark);

            string themeName = Config.GetStringValue("THEME_NAME", AutoThemeName);
            SetThemeMode(themeName, reloadBackground: true);
        }

        private void _ThemeMode_Change(object sender, RoutedEventArgs e)
        {
            if (sender is not RadioMenuFlyoutItem button)
                return;

            string themeName = button.Tag?.ToString() ?? button.Text;
            Config.SetValue("THEME_NAME", themeName);
            SetThemeMode(themeName, reloadBackground: true);
        }

        private void SetThemeMode(string requestedThemeName, bool reloadBackground)
        {
            requestedThemeName = string.IsNullOrWhiteSpace(requestedThemeName)
                ? AutoThemeName
                : requestedThemeName.Trim();

            string actualThemeName = ResolveThemeName(requestedThemeName);
            ApplyTheme(actualThemeName, reloadBackground);

            string menuSelection = requestedThemeName;
            if (!string.Equals(menuSelection, AutoThemeName, StringComparison.OrdinalIgnoreCase) &&
                !_themes.ContainsKey(menuSelection))
            {
                menuSelection = GetFallbackThemeName();
            }

            SelectRadioMenuItem("Theme", menuSelection, useTag: true);
        }

        private void LoadThemes()
        {
            _themes.Clear();

            AddTheme("Default", "Default", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Default", theme),
                IconUris = GenerateStrings("Assets/Themes/Default/icon", ".png", 32),
                FillNodes = true,
                DrawEdges = true,
                IconScale = 0.5,
                BoundsRight = -300,
                BoundsBottom = -50,
                NodesOpacity = 0.95,
                MaxNodes = 22,
                ScrollSpeed = 16,
                IconMinDiameter = 28,
                NodeSpawnRate = 2
            });

            AddTheme("Dodenherdenking", "Dodenherdenking", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Dodenherdenking", theme),
                FillNodes = false,
                DrawEdges = false,
                DrawIcons = false,
                MaxNodes = 0,
            });
            AddTheme("Aprilgrap", "Aprilgrap", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Aprilgrap", theme),
                FillNodes = false,
                DrawEdges = false,
                DrawIcons = false,
                MaxNodes = 0,
            });
            AddTheme("Autumn", "Autumn", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Autumn", theme),
                IconUris = GenerateStrings("Assets/Themes/Autumn/icon", ".png", 28),
                ScrollSpeed = 35,
                NodeSpawnRate = 5,
                MaxNodes = 10,
                MinNodeRadius = 12,
                MaxNodeRadius = 32,
                MaxNodeSpeed = 45,
                CollisionPadding = 42,
                CollisionIterations = 50,
                IconMinDiameter = 4,
                IconScale = 1.0,
                MinLinksPerNode = 1,
                MaxLinksPerNode = 1,
                NodesOpacity = 1,
                Direction = AnimatedBackgroundDirection.Left,
                BlendMode = AnimatedBackgroundBlendMode.Multiply
            });

            AddTheme("Christmas", "Christmas", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Christmas", theme),
                IconUris = GenerateStrings("Assets/Themes/Christmas/icon", ".png", 4),
                ScrollSpeed = 35,
                MaxNodes = 70,
                MaxNodeSpeed = 120,
                MinNodeRadius = 4,
                MaxNodeRadius = 14,
                IconMinDiameter = 1,
                CollisionPadding = 20,
                BoundsTop = -200,
                BoundsLeft = -30,
                BoundsRight = -30,
                Direction = AnimatedBackgroundDirection.Down,
                BlendMode = AnimatedBackgroundBlendMode.Overlay
            });

            AddTheme("Easter", "Easter", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Easter", theme),
                IconUris = GenerateStrings("Assets/Themes/Easter/icon", ".png", 1),
                ScrollSpeed = 20,
                MaxNodeRadius = 14,
                MinNodeRadius = 8,
                MaxNodes = 6,
                IconScale = 1,
                BoundsBottom = 5,
                BoundsTop = 200,
                Direction = AnimatedBackgroundDirection.Left,
                PulseIconWidth = true,
                PulseIconWidthAmplitude = 0.2,
                PulseIconWidthFrequency = 5,
                NodeSpawnRate = 2
            });

            AddTheme("Halloween", "Halloween", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Halloween", theme),
                IconUris = GenerateStrings("Assets/Themes/Halloween/icon", ".png", 12),
                NodeSpawnRate = 1,
                ScrollSpeed = 16,
                MaxLinksPerNode = 2,
                MaxNodeRadius = 28,
                MinNodeRadius = 26,
                CollisionPadding = 70,
                MaxNodes = 10,
                IconScale = 1,
                NodesOpacity = 0.5,
                Direction = AnimatedBackgroundDirection.Left,
                BlendMode = AnimatedBackgroundBlendMode.SourceOver
            });

            AddTheme("Koningsdag", "Koningsdag", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Koningsdag", theme),
                IconUris = GenerateStrings("Assets/Themes/Koningsdag/icon", ".png", 5),
                ScrollSpeed = 60,
                NodeSpawnRate = 20,
                MaxLinksPerNode = 1,
                MaxNodeRadius = 6,
                MinNodeRadius = 2,
                MaxNodes = 200,
                CollisionPadding = 10,
                IconScale = 1,
                Direction = AnimatedBackgroundDirection.Down,
                BoundsTop = -100,
                PulseIconWidth = true,
                PulseIconWidthAmplitude = 1,
                PulseIconWidthFrequency = 0.1
            });

            AddTheme("NewYear", "New Year", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("NewYear", theme),
                FireworksColors = new[]
                {
                    "#DEEBF7", "#C6DBEF", "#9ECAE1", "#6BAED6", "#4292C6", "#2171B5", "#084594",
                    "#E5F5F9", "#CCECE6", "#99D8C9", "#66C2A4", "#41AE76", "#238B45", "#005824",
                    "#FEE0D2", "#FCBBA1", "#FC9272", "#FB6A4A", "#EF3B2C", "#CB181D", "#99000D",
                    "#FEE391", "#FEC44F", "#FE9929", "#EC7014", "#CC4C02", "#8C2D04",
                    "#D53E4F", "#F46D43", "#FDAE61", "#FEE08B", "#E6F598", "#C51B7D", "#DE77AE", "#F1B6DA"
                },
                DrawIcons = false,
                DrawEdges = false,
                FireworksRocketSize = 1.5,
                MaxNodes = 0,
                FireworksEnabled = true
            });

            AddTheme("Products", "Products", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Products", theme),
                IconUris = GenerateStrings("Assets/Themes/Products/icon", ".png", 61),
                FillNodes = true,
                DrawEdges = false,
                DrawIcons = true,
                MinNodeRadius = 30,
                MaxNodeRadius = 40,
                MaxNodes = 15,
                NodeSpawnRate = 1,
                BoundsRight = -100,
                BoundsBottom = -300,
                Direction = AnimatedBackgroundDirection.Up,
                IconScale = 0.7
            });

            AddTheme("Spring", "Spring", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Spring", theme),
                IconUris = GenerateStrings("Assets/Themes/Spring/icon", ".png", 4),
                ScrollSpeed = 25,
                MaxLinksPerNode = 5,
                MaxNodeRadius = 14,
                MinNodeRadius = 8,
                MaxNodes = 16,
                CollisionPadding = 32,
                BoundsBottom = -50,
                BoundsRight = -50,
                Direction = AnimatedBackgroundDirection.Left,
                PulseIconWidth = true,
                PulseIconWidthAmplitude = 0.2,
                PulseIconWidthFrequency = 5
            });

            AddTheme("Summer", "Summer", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Summer", theme),
                IconUris = GenerateStrings("Assets/Themes/Summer/icon", ".png", 4),
                ScrollSpeed = 28,
                MaxLinksPerNode = 2,
                MaxNodeRadius = 14,
                MinNodeRadius = 8,
                MaxNodes = 16,
                CollisionPadding = 50,
                BoundsBottom = -50,
                BoundsRight = -100,
                Direction = AnimatedBackgroundDirection.Left,
                PulseIconWidth = true,
                PulseIconWidthAmplitude = 0.2,
                PulseIconWidthFrequency = 5
            });

            AddTheme("Valentine", "Valentine", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Valentine", theme),
                IconUris = GenerateStrings("Assets/Themes/Valentine/icon", ".png", 8),
                ScrollSpeed = 14,
                MaxLinksPerNode = 2,
                MaxNodeRadius = 60,
                MinNodeRadius = 8,
                MaxNodes = 6,
                CollisionPadding = 50,
                BoundsBottom = -50,
                BoundsRight = -100,
                NodesOpacity = 0.7,
                Direction = AnimatedBackgroundDirection.Left,
                BlendMode = AnimatedBackgroundBlendMode.Lighter
            });

            AddTheme("Winter", "Winter", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Winter", theme),
                IconUris = GenerateStrings("Assets/Themes/Winter/icon", ".png", 4),
                ScrollSpeed = 35,
                MaxNodes = 70,
                MaxNodeSpeed = 120,
                MinNodeRadius = 4,
                MaxNodeRadius = 14,
                IconMinDiameter = 1,
                CollisionPadding = 20,
                BoundsTop = -200,
                BoundsLeft = -30,
                BoundsRight = -30,
                Direction = AnimatedBackgroundDirection.Down,
                BlendMode = AnimatedBackgroundBlendMode.Screen
            });

            AddTheme("Xenos", "Xenos", theme => new AnimatedBackgroundAnimationSettings
            {
                BackgroundImageUrl = GetThemeBackgroundPath("Xenos", theme),
                DrawIcons = false,
                FillNodes = true,
                DrawEdges = false,
                MinNodeRadius = 25,
                MaxNodeRadius = 25,
                BoundsBottom = -200,
                BoundsLeft = -100,
                BoundsRight = -100,
                MaxNodes = 16,
                ScrollSpeed = 16,
                IconMinDiameter = 28,
                NodeSpawnRate = 1,
                Direction = AnimatedBackgroundDirection.Up,
                NodeColors = new[] { "#FDCC1E", "#393330" }
            });
        }

        private void AddTheme(string name, string displayName, Func<ElementTheme, AnimatedBackgroundAnimationSettings> factory)
        {
            _themes[name] = new ThemeDefinition
            {
                Name = name,
                DisplayName = displayName,
                Factory = factory
            };
        }

        private void BuildThemeMenu()
        {
            MenuFlyoutSubItem? themeMenu = FindMenuSubItem("Theme");
            if (themeMenu is null)
                return;

            themeMenu.Items.Clear();

            var autoItem = new RadioMenuFlyoutItem
            {
                Text = AutoThemeName,
                Tag = AutoThemeName,
                GroupName = "ThemeMode"
            };
            autoItem.Click += _ThemeMode_Change;
            themeMenu.Items.Add(autoItem);

            foreach (ThemeDefinition theme in _themes.Values
                         .OrderBy(x => string.Equals(x.Name, DefaultThemeName, StringComparison.OrdinalIgnoreCase) ? 0 : 1)
                         .ThenBy(x => x.DisplayName, StringComparer.OrdinalIgnoreCase))
            {
                var item = new RadioMenuFlyoutItem
                {
                    Text = theme.DisplayName,
                    Tag = theme.Name,
                    GroupName = "ThemeMode"
                };
                item.Click += _ThemeMode_Change;
                themeMenu.Items.Add(item);
            }
        }

        private MenuFlyoutSubItem? FindMenuSubItem(string text)
        {
            if (_SettingButton.Flyout is not MenuFlyout flyout)
                return null;

            foreach (var item in flyout.Items)
            {
                if (item is MenuFlyoutSubItem subItem &&
                    string.Equals(subItem.Text, text, StringComparison.OrdinalIgnoreCase))
                {
                    return subItem;
                }
            }

            return null;
        }

        private bool SelectRadioMenuItem(string subMenuText, string itemValue, bool useTag)
        {
            MenuFlyoutSubItem? subMenu = FindMenuSubItem(subMenuText);
            if (subMenu is null)
                return false;

            foreach (var item in subMenu.Items)
            {
                if (item is not RadioMenuFlyoutItem radio)
                    continue;

                string? compareValue = useTag ? radio.Tag?.ToString() : radio.Text;

                if (string.Equals(compareValue, itemValue, StringComparison.OrdinalIgnoreCase))
                {
                    radio.IsChecked = true;
                    return true;
                }
            }

            return false;
        }

        private string ResolveThemeName(string requestedThemeName)
        {
            if (string.Equals(requestedThemeName, AutoThemeName, StringComparison.OrdinalIgnoreCase))
                return ResolveAutoThemeName();

            if (_themes.ContainsKey(requestedThemeName))
                return requestedThemeName;

            return GetFallbackThemeName();
        }

        private string ResolveAutoThemeName()
        {
            var today = DateTime.Today;
            int year = today.Year;

            static bool InRange(DateTime d, DateTime from, DateTime to) => d >= from && d <= to;

            var easter = GetEasterSunday(year);

            if (HasTheme("Dodenherdenking"))
            {
                var dodenherdenking = new DateTime(year, 5, 4);
                if (today.Date == dodenherdenking.Date)
                    return "Dodenherdenking";
            }

            if (HasTheme("NewYear"))
            {
                var newYearStart = new DateTime(year, 12, 27);
                var newYearEnd = new DateTime(year, 12, 31);

                if (InRange(today, newYearStart, newYearEnd))
                    return "NewYear";
            }

            if (HasTheme("NewYear"))
            {
                var newYearStart = new DateTime(year, 1, 1);
                var newYearEnd = new DateTime(year, 1, 4);

                if (InRange(today, newYearStart, newYearEnd))
                    return "NewYear";
            }

            if (HasTheme("Valentine"))
            {
                var valentine = new DateTime(year, 2, 14);
                if (InRange(today, valentine.AddDays(-7), valentine))
                    return "Valentine";
            }

            if (HasTheme("Easter"))
            {
                if (InRange(today, easter.AddDays(-7), easter.AddDays(1)))
                    return "Easter";
            }

            if (HasTheme("Koningsdag"))
            {
                var koningsdag = new DateTime(year, 4, 27);
                if (koningsdag.DayOfWeek == DayOfWeek.Sunday)
                    koningsdag = koningsdag.AddDays(-1);

                if (InRange(today, koningsdag.AddDays(-7), koningsdag))
                    return "Koningsdag";
            }



            if (HasTheme("Halloween"))
            {
                var halloween = new DateTime(year, 10, 31);
                if (InRange(today, halloween.AddDays(-7), halloween))
                    return "Halloween";
            }

            if (HasTheme("Christmas"))
            {
                var christmasStart = new DateTime(year, 12, 18);
                var christmasEnd = new DateTime(year, 12, 26);

                if (InRange(today, christmasStart, christmasEnd))
                    return "Christmas";
            }

            if (today.Month == 12 && today.Day <= 14 && HasTheme("Winter"))
                return "Winter";

            if (today.Month == 3 && today.Day <= 7 && HasTheme("Spring"))
                return "Spring";

            if (today.Month == 6 && today.Day <= 7 && HasTheme("Summer"))
                return "Summer";

            if (today.Month == 9 && today.Day <= 7 && HasTheme("Autumn"))
                return "Autumn";

            return GetFallbackThemeName();
        }

        private bool HasTheme(string name) => _themes.ContainsKey(name);

        private string GetFallbackThemeName()
        {
            if (_themes.ContainsKey(DefaultThemeName))
                return DefaultThemeName;

            return _themes.Keys.FirstOrDefault() ?? DefaultThemeName;
        }

        private void ApplyTheme(string themeName, bool reloadBackground)
        {
            if (_themes.Count == 0)
                return;

            if (!_themes.TryGetValue(themeName, out ThemeDefinition? theme))
            {
                string fallback = GetFallbackThemeName();
                if (!_themes.TryGetValue(fallback, out theme))
                    return;
            }

            var actualTheme = RootGrid.ActualTheme == ElementTheme.Dark
                ? ElementTheme.Dark
                : ElementTheme.Light;

            _BackgroundAnimation.Animation = theme.Factory(actualTheme);
        }

        private static string GetThemeBackgroundPath(string themeFolderName, ElementTheme theme)
        {
            string fileName = theme == ElementTheme.Dark
                ? "BackgroundDark.png"
                : "BackgroundLight.png";

            return AssetPath($"Assets/Themes/{themeFolderName}/{fileName}");
        }

        private static string AssetPath(string relativePath)
            => $"{relativePath}".Replace("\\", "/");

        private static string[] GenerateStrings(string start, string end, int count)
        {
            if (count < 0)
                throw new ArgumentOutOfRangeException(nameof(count));

            var result = new string[count];

            for (int i = 0; i < count; i++)
                result[i] = $"{start}{i + 1}{end}";

            return result;
        }

        public static void ApplyTitleBarTheme(Window window, bool dark)
        {
            var hwnd = WindowNative.GetWindowHandle(window);
            var id = Win32Interop.GetWindowIdFromWindow(hwnd);
            var appWindow = AppWindow.GetFromWindowId(id);

            if (appWindow.TitleBar is null)
                return;

            if (dark)
            {
                appWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
                appWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
                appWindow.TitleBar.ButtonForegroundColor = Colors.White;
                appWindow.TitleBar.ButtonInactiveForegroundColor = Color.FromArgb(255, 180, 180, 180);
                appWindow.TitleBar.ButtonHoverBackgroundColor = Color.FromArgb(255, 45, 45, 45);
                appWindow.TitleBar.ButtonHoverForegroundColor = Colors.White;
                appWindow.TitleBar.ButtonPressedBackgroundColor = Color.FromArgb(255, 30, 30, 30);
                appWindow.TitleBar.ButtonPressedForegroundColor = Colors.White;
            }
            else
            {
                appWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
                appWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
                appWindow.TitleBar.ButtonForegroundColor = Colors.Black;
                appWindow.TitleBar.ButtonInactiveForegroundColor = Color.FromArgb(255, 120, 120, 120);
                appWindow.TitleBar.ButtonHoverBackgroundColor = Color.FromArgb(255, 230, 230, 230);
                appWindow.TitleBar.ButtonHoverForegroundColor = Colors.Black;
                appWindow.TitleBar.ButtonPressedBackgroundColor = Color.FromArgb(255, 210, 210, 210);
                appWindow.TitleBar.ButtonPressedForegroundColor = Colors.Black;
            }
        }

        private void _About_Click(object sender, RoutedEventArgs e)
        {
            var window = new AboutWindow();
            window.Activate();
        }

        public static DateTime GetEasterSunday(int year)
        {
            int a = year % 19;
            int b = year / 100;
            int c = year % 100;
            int d = b / 4;
            int e = b % 4;
            int f = (b + 8) / 25;
            int g = (b - f + 1) / 3;
            int h = (19 * a + b - d - g + 15) % 30;
            int i = c / 4;
            int k = c % 4;
            int l = (32 + 2 * e + 2 * i - h - k) % 7;
            int m = (a + 11 * h + 22 * l) / 451;

            int month = (h + l - 7 * m + 114) / 31;
            int day = ((h + l - 7 * m + 114) % 31) + 1;

            return new DateTime(year, month, day);
        }

        private sealed class ThemeDefinition
        {
            public string Name { get; set; } = "";
            public string DisplayName { get; set; } = "";
            public Func<ElementTheme, AnimatedBackgroundAnimationSettings> Factory { get; set; } = _ => new AnimatedBackgroundAnimationSettings();
        }
    }
}
