using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Composition.SystemBackdrops;
using Windows.UI;

namespace YMhut.Box.WinUI;

public static class ThemeService
{
    public static void ApplyTheme(Window? window, string theme, string windowBackdrop = "mica")
    {
        ModernUi.SetPalette(string.Equals(theme, "Dark", StringComparison.OrdinalIgnoreCase));

        FrameworkElement? root;
        try
        {
            root = window?.Content as FrameworkElement;
        }
        catch (System.Runtime.InteropServices.COMException exception)
        {
            if (!IsClosedWindowException(exception))
            {
                CrashLog.Write(exception);
            }
            return;
        }

        if (root is null)
        {
            return;
        }

        root.RequestedTheme = theme switch
        {
            "Light" => ElementTheme.Light,
            "Dark" => ElementTheme.Dark,
            _ => ElementTheme.Default,
        };

        ApplyWindowBackdrop(window, windowBackdrop);
    }

    public static void ApplyWindowBackdrop(Window? window, string windowBackdrop)
    {
        if (window is null)
        {
            return;
        }

        try
        {
            window.SystemBackdrop = windowBackdrop.Trim().ToLowerInvariant() switch
            {
                "micaalt" or "mica_alt" or "mica-alt" => new MicaBackdrop { Kind = MicaKind.BaseAlt },
                "acrylic" or "desktopacrylic" or "desktop_acrylic" => new DesktopAcrylicBackdrop(),
                "none" or "solid" => null,
                _ => new MicaBackdrop { Kind = MicaKind.Base }
            };
        }
        catch (Exception exception)
        {
            if (!IsClosedWindowException(exception))
            {
                CrashLog.Write(exception);
            }
            try
            {
                window.SystemBackdrop = null;
            }
            catch
            {
            }
        }
    }

    public static Brush CreateTopBarBrush(string? material, bool dark, string? fallbackMaterial = null)
    {
        var normalized = NormalizeMaterial(material);
        if (normalized == "inherit")
        {
            normalized = NormalizeMaterial(fallbackMaterial);
            if (normalized == "inherit")
            {
                normalized = "solid";
            }
        }

        return CreateMaterialBrush(normalized, dark, topBar: true);
    }

    public static Brush CreateContentBrush(string? material, bool dark)
    {
        return CreateMaterialBrush(NormalizeMaterial(material), dark, topBar: false);
    }

    public static Brush CreateShellBrush(string? windowBackdrop, bool dark, double darkAlpha = 255, double lightAlpha = 255)
    {
        var transparent = NormalizeBackdrop(windowBackdrop) is not "solid";
        if (transparent)
        {
            return new SolidColorBrush(Color.FromArgb(
                dark ? (byte)Math.Clamp(darkAlpha, 0, 255) : (byte)Math.Clamp(lightAlpha, 0, 255),
                dark ? (byte)31 : (byte)245,
                dark ? (byte)36 : (byte)246,
                dark ? (byte)38 : (byte)247));
        }

        return ModernUi.AppBackground;
    }

    private static Brush CreateMaterialBrush(string material, bool dark, bool topBar)
    {
        try
        {
            return material switch
            {
                "acrylic" => new AcrylicBrush
                {
                    TintColor = dark ? Color.FromArgb(255, 31, 36, 38) : Color.FromArgb(255, 245, 246, 247),
                    TintOpacity = topBar ? 0.76 : 0.72,
                    TintLuminosityOpacity = 0.82,
                    FallbackColor = dark ? Color.FromArgb(255, 36, 41, 43) : Color.FromArgb(255, 245, 246, 247)
                },
                "glass" => new AcrylicBrush
                {
                    TintColor = dark ? Color.FromArgb(255, 31, 36, 38) : Color.FromArgb(255, 255, 255, 255),
                    TintOpacity = topBar ? 0.62 : 0.58,
                    TintLuminosityOpacity = 0.76,
                    FallbackColor = dark ? Color.FromArgb(255, 42, 48, 50) : Color.FromArgb(255, 250, 251, 252)
                },
                "mica" => new SolidColorBrush(Color.FromArgb(dark ? (byte)218 : (byte)224, dark ? (byte)31 : (byte)250, dark ? (byte)36 : (byte)251, dark ? (byte)38 : (byte)252)),
                _ => dark ? ModernUi.Surface : ModernUi.Surface
            };
        }
        catch (Exception exception)
        {
            CrashLog.Write(exception);
            return ModernUi.Surface;
        }
    }

    private static string NormalizeMaterial(string? value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "solid" or "none" => "solid",
            "mica" => "mica",
            "acrylic" => "acrylic",
            "glass" or "frosted" or "frosted_glass" => "glass",
            _ => "inherit"
        };
    }

    private static string NormalizeBackdrop(string? value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "solid" or "none" => "solid",
            "micaalt" or "mica_alt" or "mica-alt" => "micaAlt",
            "acrylic" or "desktopacrylic" or "desktop_acrylic" => "acrylic",
            _ => "mica"
        };
    }

    private static bool IsClosedWindowException(Exception exception)
    {
        return exception.HResult == unchecked((int)0x800710DD) ||
            exception.Message.Contains("already been closed", StringComparison.OrdinalIgnoreCase) ||
            exception.Message.Contains("已经关闭", StringComparison.OrdinalIgnoreCase);
    }

    public static void ApplyFontScale(double scale)
    {
        var normalized = Math.Clamp(scale, 0.85, 1.35);
        var body = 14d * normalized;
        var title = 20d * normalized;
        Application.Current.Resources["BodyTextBlockFontSize"] = body;
        Application.Current.Resources["SubtitleTextBlockFontSize"] = 16d * normalized;
        Application.Current.Resources["TitleTextBlockFontSize"] = title;
        Application.Current.Resources["ControlContentThemeFontSize"] = body;
        Application.Current.Resources["TextControlThemeFontSize"] = body;
    }
}
