using Microsoft.UI;
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Windows.UI.Text;

namespace YMhut.Box.WinUI;

internal static class ModernUi
{
    internal static SolidColorBrush AppBackground { get; } = Brush("#F7F7F7");
    internal static SolidColorBrush SidebarBackground { get; } = Brush("#F9F9F9");
    internal static SolidColorBrush Surface { get; } = Brush("#FFFFFF");
    internal static SolidColorBrush SurfaceAlt { get; } = Brush("#F3F3F3");
    internal static SolidColorBrush Stroke { get; } = Brush("#E5E5E5");
    internal static SolidColorBrush StrokeStrong { get; } = Brush("#C8C8C8");
    internal static SolidColorBrush TextPrimary { get; } = Brush("#1A1A1A");
    internal static SolidColorBrush TextSecondary { get; } = Brush("#5E5E5E");
    internal static SolidColorBrush Accent { get; } = Brush("#0067C0");
    internal static SolidColorBrush AccentSoft { get; } = Brush("#EAF4FF");
    internal static SolidColorBrush Success { get; } = Brush("#107C10");
    internal static SolidColorBrush Bronze { get; } = Brush("#CA5010");
    internal static SolidColorBrush Danger { get; } = Brush("#C42B1C");
    internal static SolidColorBrush Info { get; } = Brush("#0078D4");

    internal static void SetPalette(bool dark)
    {
        SetBrush(AppBackground, dark ? "#202020" : "#F7F7F7");
        SetBrush(SidebarBackground, dark ? "#242424" : "#F9F9F9");
        SetBrush(Surface, dark ? "#2B2B2B" : "#FFFFFF");
        SetBrush(SurfaceAlt, dark ? "#323232" : "#F3F3F3");
        SetBrush(Stroke, dark ? "#454545" : "#E5E5E5");
        SetBrush(StrokeStrong, dark ? "#5C5C5C" : "#C8C8C8");
        SetBrush(TextPrimary, dark ? "#F3F3F3" : "#1A1A1A");
        SetBrush(TextSecondary, dark ? "#C7C7C7" : "#5E5E5E");
        SetBrush(Accent, dark ? "#60CDFF" : "#0067C0");
        SetBrush(AccentSoft, dark ? "#073B5F" : "#EAF4FF");
        SetBrush(Success, dark ? "#6CCB5F" : "#107C10");
        SetBrush(Bronze, dark ? "#F7B189" : "#CA5010");
        SetBrush(Danger, dark ? "#F1707B" : "#C42B1C");
        SetBrush(Info, dark ? "#60CDFF" : "#0078D4");
    }

    internal static SolidColorBrush Brush(string hex)
    {
        return new SolidColorBrush(ColorFromHex(hex));
    }

    private static void SetBrush(SolidColorBrush brush, string hex)
    {
        brush.Color = ColorFromHex(hex);
    }

    private static Windows.UI.Color ColorFromHex(string hex)
    {
        var normalized = hex.Trim().TrimStart('#');
        if (normalized.Length == 6)
        {
            normalized = "FF" + normalized;
        }

        return ColorHelper.FromArgb(
            Convert.ToByte(normalized[..2], 16),
            Convert.ToByte(normalized.Substring(2, 2), 16),
            Convert.ToByte(normalized.Substring(4, 2), 16),
            Convert.ToByte(normalized.Substring(6, 2), 16));
    }

    internal static TextBlock Text(
        string text,
        double size = 16,
        FontWeight? weight = null,
        Brush? foreground = null,
        int maxLines = 0)
    {
        var block = new TextBlock
        {
            Text = text,
            FontSize = size,
            FontWeight = weight ?? FontWeights.Normal,
            Foreground = foreground ?? TextPrimary,
            TextWrapping = TextWrapping.Wrap,
            TextTrimming = TextTrimming.CharacterEllipsis,
            LineHeight = Math.Max(size * 1.35, size + 6)
        };
        if (maxLines > 0)
        {
            block.MaxLines = maxLines;
        }

        return block;
    }

    internal static Border Card(
        UIElement child,
        Thickness? padding = null,
        Thickness? margin = null,
        double radius = 8,
        Brush? background = null)
    {
        return new Border
        {
            Padding = padding ?? new Thickness(20),
            Margin = margin ?? new Thickness(0),
            CornerRadius = new CornerRadius(radius),
            Background = background ?? Surface,
            BorderBrush = Stroke,
            BorderThickness = new Thickness(1),
            Child = child
        };
    }

    internal static Border IconTile(
        string glyph,
        double size = 40,
        Brush? background = null,
        Brush? foreground = null,
        double iconSize = 18)
    {
        return new Border
        {
            Width = size,
            Height = size,
            CornerRadius = new CornerRadius(Math.Min(8, size / 4)),
            Background = background ?? SurfaceAlt,
            BorderBrush = Stroke,
            BorderThickness = new Thickness(1),
            Child = new FontIcon
            {
                Glyph = glyph,
                FontSize = iconSize,
                Foreground = foreground ?? Accent,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            }
        };
    }

    internal static Button IconButton(string glyph, string tooltip, Action? click = null)
    {
        var button = new Button
        {
            Width = 40,
            Height = 36,
            Padding = new Thickness(0),
            CornerRadius = new CornerRadius(6),
            Background = Brush("#00FFFFFF"),
            BorderBrush = Brush("#00FFFFFF"),
            Content = new FontIcon
            {
                Glyph = glyph,
                FontSize = 16,
                Foreground = TextSecondary
            }
        };
        ToolTipService.SetToolTip(button, tooltip);
        AutomationProperties.SetName(button, tooltip);
        if (click is not null)
        {
            button.Click += (_, _) => click();
        }

        return button;
    }

    internal static Button PillButton(string text, string glyph, Action? click = null, bool primary = false)
    {
        var panel = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 8,
            HorizontalAlignment = HorizontalAlignment.Center,
            VerticalAlignment = VerticalAlignment.Center,
            Children =
            {
                new FontIcon { Glyph = glyph, FontSize = 15 },
                Text(text, 14, FontWeights.SemiBold, primary ? Brush("#FFFFFFFF") : TextPrimary)
            }
        };

        var button = new Button
        {
            Padding = new Thickness(14, 8, 14, 8),
            CornerRadius = new CornerRadius(6),
            Background = primary ? Accent : Brush("#00FFFFFF"),
            Foreground = primary ? Brush("#FFFFFFFF") : TextPrimary,
            BorderBrush = primary ? Accent : Stroke,
            BorderThickness = new Thickness(1),
            Content = panel
        };
        ToolTipService.SetToolTip(button, text);
        AutomationProperties.SetName(button, text);
        if (click is not null)
        {
            button.Click += (_, _) => click();
        }

        return button;
    }

    internal static Border Chip(string title, string value, string glyph, bool selected = false)
    {
        var panel = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 10, VerticalAlignment = VerticalAlignment.Center };
        panel.Children.Add(IconTile(glyph, 34, selected ? AccentSoft : SurfaceAlt, selected ? Accent : TextSecondary, 15));
        panel.Children.Add(new StackPanel
        {
            Spacing = 0,
            Children =
            {
                Text(title, 12, FontWeights.SemiBold, TextSecondary),
                Text(value, 15, FontWeights.SemiBold, selected ? Accent : TextPrimary)
            }
        });

        return new Border
        {
            Padding = new Thickness(12, 8, 12, 8),
            CornerRadius = new CornerRadius(8),
            Background = selected ? AccentSoft : Surface,
            BorderBrush = selected ? Accent : Stroke,
            BorderThickness = new Thickness(1),
            Child = panel
        };
    }

    internal static Border SmallBadge(string text, Brush? foreground = null, Brush? background = null)
        => Badge(text, foreground, background);

    internal static Border Badge(
        string text,
        Brush? foreground = null,
        Brush? background = null,
        double maxWidth = 132)
    {
        var label = new TextBlock
        {
            Text = string.IsNullOrWhiteSpace(text) ? "-" : text.Trim(),
            FontSize = 12,
            FontWeight = FontWeights.SemiBold,
            Foreground = foreground ?? TextSecondary,
            TextWrapping = TextWrapping.NoWrap,
            TextTrimming = TextTrimming.CharacterEllipsis,
            MaxLines = 1,
            MaxWidth = maxWidth,
            VerticalAlignment = VerticalAlignment.Center
        };

        return new Border
        {
            MinHeight = 24,
            Padding = new Thickness(8, 2, 8, 3),
            CornerRadius = new CornerRadius(6),
            Background = background ?? SurfaceAlt,
            BorderBrush = Stroke,
            BorderThickness = new Thickness(1),
            Child = label
        };
    }

    internal static VariableSizedWrapGrid BadgeRow(
        IEnumerable<UIElement> badges,
        double itemWidth = 118,
        double itemHeight = 28,
        double maxHeight = 60)
    {
        var row = new VariableSizedWrapGrid
        {
            Orientation = Orientation.Horizontal,
            ItemWidth = itemWidth,
            ItemHeight = itemHeight,
            MaxHeight = maxHeight,
            HorizontalAlignment = HorizontalAlignment.Stretch
        };

        foreach (var badge in badges)
        {
            row.Children.Add(badge);
        }

        return row;
    }

    internal static VariableSizedWrapGrid BadgeRow(params UIElement[] badges)
        => BadgeRow((IEnumerable<UIElement>)badges);

    internal static ScrollViewer GutterScroll(UIElement content, double maxHeight, double rightGutter = 16)
    {
        return new ScrollViewer
        {
            MaxHeight = maxHeight,
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
            HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
            Padding = new Thickness(0, 0, 4, 0),
            Content = new Border
            {
                Padding = new Thickness(0, 0, rightGutter, 0),
                Child = content
            }
        };
    }

    internal static StackPanel RichText(string text, string? meta = null)
    {
        var panel = new StackPanel { Spacing = 10 };
        if (!string.IsNullOrWhiteSpace(meta))
        {
            panel.Children.Add(SmallBadge(meta, Accent, AccentSoft));
        }

        var paragraph = new List<string>();
        void FlushParagraph()
        {
            if (paragraph.Count == 0)
            {
                return;
            }

            panel.Children.Add(Text(string.Join(Environment.NewLine, paragraph), 14, foreground: TextSecondary));
            paragraph.Clear();
        }

        foreach (var rawLine in (text ?? string.Empty).Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n'))
        {
            var line = rawLine.Trim();
            if (string.IsNullOrWhiteSpace(line))
            {
                FlushParagraph();
                continue;
            }

            if (line.StartsWith('#'))
            {
                FlushParagraph();
                var heading = line.TrimStart('#').Trim();
                if (!string.IsNullOrWhiteSpace(heading))
                {
                    panel.Children.Add(Text(heading, 17, FontWeights.SemiBold, TextPrimary));
                }
                continue;
            }

            if (IsBulletLine(line, out var bulletText, out var marker))
            {
                FlushParagraph();
                panel.Children.Add(BulletRow(marker, bulletText));
                continue;
            }

            paragraph.Add(line);
        }

        FlushParagraph();
        if (panel.Children.Count == 0)
        {
            panel.Children.Add(Text(AppLocalizer.T("暂无内容。", "No content."), 14, foreground: TextSecondary));
        }

        return panel;
    }

    private static bool IsBulletLine(string line, out string text, out string marker)
    {
        text = line;
        marker = "•";
        if (line.StartsWith("- ", StringComparison.Ordinal) || line.StartsWith("* ", StringComparison.Ordinal))
        {
            text = line[2..].Trim();
            return true;
        }

        var dotIndex = line.IndexOf('.', StringComparison.Ordinal);
        if (dotIndex > 0 && dotIndex <= 3 && line[..dotIndex].All(char.IsDigit))
        {
            marker = line[..(dotIndex + 1)];
            text = line[(dotIndex + 1)..].Trim();
            return true;
        }

        return false;
    }

    private static UIElement BulletRow(string marker, string text)
    {
        var grid = new Grid { ColumnSpacing = 10 };
        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        grid.ColumnDefinitions.Add(new ColumnDefinition());
        grid.Children.Add(Text(marker, 13, FontWeights.SemiBold, Accent, maxLines: 1));
        var block = Text(text, 14, foreground: TextSecondary);
        Grid.SetColumn(block, 1);
        grid.Children.Add(block);
        return grid;
    }

    internal static string Ellipsize(string text, int max)
    {
        if (string.IsNullOrWhiteSpace(text) || text.Length <= max)
        {
            return text;
        }

        return text[..Math.Max(0, max - 1)] + "...";
    }
}
