using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using WpfColor = System.Windows.Media.Color;

namespace Noctalk.UI.Components.Button;

public sealed class Noctalk_button : System.Windows.Controls.Button
{
    private static readonly CornerRadius Corner_radius_none = new(0);
    private static readonly CornerRadius Corner_radius_rounded = new(3);
    private static readonly Brush Background_normal = new SolidColorBrush(WpfColor.FromRgb(8, 26, 42));
    private static readonly Brush Background_hover = new SolidColorBrush(WpfColor.FromRgb(10, 42, 68));
    private static readonly Brush Background_down = new SolidColorBrush(WpfColor.FromRgb(4, 20, 34));
    private static readonly Brush Background_red_normal = new SolidColorBrush(WpfColor.FromRgb(54, 10, 18));
    private static readonly Brush Background_red_hover = new SolidColorBrush(WpfColor.FromRgb(84, 17, 28));
    private static readonly Brush Background_red_down = new SolidColorBrush(WpfColor.FromRgb(42, 6, 14));
    private static readonly Brush Border_normal = new SolidColorBrush(WpfColor.FromRgb(20, 107, 147));
    private static readonly Brush Border_red = new SolidColorBrush(WpfColor.FromRgb(178, 50, 72));
    private static readonly Brush Fill_blue_normal = new SolidColorBrush(WpfColor.FromRgb(20, 107, 147));
    private static readonly Brush Fill_blue_hover = new SolidColorBrush(WpfColor.FromRgb(39, 145, 190));
    private static readonly Brush Fill_blue_down = new SolidColorBrush(WpfColor.FromRgb(11, 76, 113));
    private static readonly Brush Fill_blue_border_normal = new SolidColorBrush(WpfColor.FromRgb(11, 76, 113));
    private static readonly Brush Fill_blue_border_hover = new SolidColorBrush(WpfColor.FromRgb(20, 107, 147));
    private static readonly Brush Fill_blue_border_down = new SolidColorBrush(WpfColor.FromRgb(4, 50, 82));
    private static readonly Brush Fill_red_normal = new SolidColorBrush(WpfColor.FromRgb(178, 50, 72));
    private static readonly Brush Fill_red_hover = new SolidColorBrush(WpfColor.FromRgb(216, 78, 99));
    private static readonly Brush Fill_red_down = new SolidColorBrush(WpfColor.FromRgb(125, 27, 45));
    private static readonly Brush Fill_red_border_normal = new SolidColorBrush(WpfColor.FromRgb(125, 27, 45));
    private static readonly Brush Fill_red_border_hover = new SolidColorBrush(WpfColor.FromRgb(178, 50, 72));
    private static readonly Brush Fill_red_border_down = new SolidColorBrush(WpfColor.FromRgb(80, 14, 28));
    private static readonly Brush Fill_grey_normal = new SolidColorBrush(WpfColor.FromRgb(88, 101, 112));
    private static readonly Brush Fill_grey_hover = new SolidColorBrush(WpfColor.FromRgb(112, 128, 140));
    private static readonly Brush Fill_grey_down = new SolidColorBrush(WpfColor.FromRgb(62, 73, 82));
    private static readonly Brush Fill_grey_border_normal = new SolidColorBrush(WpfColor.FromRgb(54, 65, 74));
    private static readonly Brush Fill_grey_border_hover = new SolidColorBrush(WpfColor.FromRgb(88, 101, 112));
    private static readonly Brush Fill_grey_border_down = new SolidColorBrush(WpfColor.FromRgb(39, 48, 56));
    private static readonly Brush Text_light = Brushes.White;
    private static readonly Brush Text_dark = Brushes.Black;
    private static readonly Brush Text_disabled = new SolidColorBrush(WpfColor.FromRgb(72, 102, 118));
    private object? originalContent;
    private bool applyingContent;
    private bool isBlinking;
    private bool flag__auto_icon_width_applied;

    public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(
        nameof(Color),
        typeof(Noctalk_button_color),
        typeof(Noctalk_button),
        new PropertyMetadata(Noctalk_button_color.Blue_O__Blue_O, UI__button__visual_property_changed));

    public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
        nameof(Icon),
        typeof(Noctalk_button_icon),
        typeof(Noctalk_button),
        new PropertyMetadata(Noctalk_button_icon.None, UI__button__visual_property_changed));

    public static readonly DependencyProperty WidthModeProperty = DependencyProperty.Register(
        nameof(WidthMode),
        typeof(Noctalk_button_width_mode),
        typeof(Noctalk_button),
        new PropertyMetadata(Noctalk_button_width_mode.Custom, UI__button__width_mode_changed));

    public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
        nameof(Size),
        typeof(Noctalk_button_size),
        typeof(Noctalk_button),
        new PropertyMetadata(Noctalk_button_size.Standard, UI__button__size_changed));

    public static readonly DependencyProperty bRounded_cornersProperty = DependencyProperty.Register(
        nameof(bRounded_corners),
        typeof(bool),
        typeof(Noctalk_button),
        new PropertyMetadata(false, UI__button__rounded_corners_changed));

    private static readonly DependencyProperty Button_corner_radiusProperty = DependencyProperty.Register(
        nameof(Button_corner_radius),
        typeof(CornerRadius),
        typeof(Noctalk_button),
        new PropertyMetadata(Corner_radius_none));

    public Noctalk_button_color Color
    {
        get => (Noctalk_button_color)GetValue(ColorProperty);
        set => SetValue(ColorProperty, value);
    }

    public Noctalk_button_icon Icon
    {
        get => (Noctalk_button_icon)GetValue(IconProperty);
        set => SetValue(IconProperty, value);
    }

    public Noctalk_button_width_mode WidthMode
    {
        get => (Noctalk_button_width_mode)GetValue(WidthModeProperty);
        set => SetValue(WidthModeProperty, value);
    }

    public Noctalk_button_size Size
    {
        get => (Noctalk_button_size)GetValue(SizeProperty);
        set => SetValue(SizeProperty, value);
    }

    public bool bRounded_corners
    {
        get => (bool)GetValue(bRounded_cornersProperty);
        set => SetValue(bRounded_cornersProperty, value);
    }

    private CornerRadius Button_corner_radius
    {
        get => (CornerRadius)GetValue(Button_corner_radiusProperty);
        set => SetValue(Button_corner_radiusProperty, value);
    }

    public Noctalk_button()
    {
        Height = 34;
        MinHeight = 34;
        BorderThickness = new Thickness(1);
        Padding = new Thickness(10, 7, 10, 7);
        Margin = new Thickness(6);
        FontWeight = FontWeights.SemiBold;
        HorizontalContentAlignment = HorizontalAlignment.Center;
        VerticalContentAlignment = VerticalAlignment.Center;
        Cursor = System.Windows.Input.Cursors.Hand;
        OverridesDefaultStyle = true;
        Template = UI__button__create_template();
        UI__button__apply_corner_radius();

        Loaded += (_, _) => UI__button__apply_visual_state(false, false);
        IsEnabledChanged += (_, _) => UI__button__apply_visual_state(false, false);
        MouseEnter += (_, _) => UI__button__apply_visual_state(true, false);
        MouseLeave += (_, _) => UI__button__apply_visual_state(false, false);
        PreviewMouseDown += (_, _) => UI__button__apply_visual_state(true, true);
        PreviewMouseUp += (_, _) => UI__button__apply_visual_state(IsMouseOver, false);
    }

    public async void Make_button_blink_for_1_second()
    {
        if (isBlinking)
        {
            return;
        }

        isBlinking = true;

        try
        {
            Button_visual_spec blinkSpec = UI__button__get_visual_spec(true);
            for (int index = 0; index < 3; index++)
            {
                Background = blinkSpec.Background_hover;
                BorderBrush = blinkSpec.Border_hover;
                Foreground = UI__button__foreground_for_background(blinkSpec.Background_hover);
                await Task.Delay(83);
                Background = blinkSpec.Background_down;
                BorderBrush = blinkSpec.Border_down;
                Foreground = UI__button__foreground_for_background(blinkSpec.Background_down);
                await Task.Delay(83);
            }
        }
        finally
        {
            isBlinking = false;
            UI__button__apply_visual_state_core(IsMouseOver, false);
        }
    }

    protected override void OnContentChanged(object oldContent, object newContent)
    {
        base.OnContentChanged(oldContent, newContent);

        if (applyingContent)
        {
            return;
        }

        originalContent = newContent;
        UI__button__apply_content();
    }

    private static void UI__button__visual_property_changed(DependencyObject Dependency_object, DependencyPropertyChangedEventArgs Event_args)
    {
        Noctalk_button button = (Noctalk_button)Dependency_object;
        button.UI__button__apply_visual_state(button.IsMouseOver, false);
        button.UI__button__apply_content();
    }

    private static void UI__button__width_mode_changed(DependencyObject Dependency_object, DependencyPropertyChangedEventArgs Event_args)
    {
        Noctalk_button button = (Noctalk_button)Dependency_object;

        if (button.WidthMode == Noctalk_button_width_mode.Content)
        {
            button.Width = double.NaN;
            button.HorizontalAlignment = HorizontalAlignment.Center;
            return;
        }

        if (button.WidthMode == Noctalk_button_width_mode.Stretch)
        {
            button.Width = double.NaN;
            button.HorizontalAlignment = HorizontalAlignment.Stretch;
        }
    }

    private static void UI__button__size_changed(DependencyObject Dependency_object, DependencyPropertyChangedEventArgs Event_args)
    {
        Noctalk_button button = (Noctalk_button)Dependency_object;
        button.UI__button__apply_size();
        button.UI__button__apply_content();
    }

    private static void UI__button__rounded_corners_changed(DependencyObject Dependency_object, DependencyPropertyChangedEventArgs Event_args)
    {
        Noctalk_button button = (Noctalk_button)Dependency_object;
        button.UI__button__apply_corner_radius();
    }

    private void UI__button__apply_corner_radius()
    {
        Button_corner_radius = bRounded_corners ? Corner_radius_rounded : Corner_radius_none;
    }

    private void UI__button__apply_size()
    {
        if (Size == Noctalk_button_size.Grid)
        {
            Height = 22;
            MinHeight = 0;
            Padding = new Thickness(2);
            VerticalAlignment = VerticalAlignment.Center;
            return;
        }

        if (Size == Noctalk_button_size.Custom)
        {
            MinHeight = 0;
            VerticalAlignment = VerticalAlignment.Center;
            return;
        }

        Height = 34;
        MinHeight = 34;
        Padding = new Thickness(10, 7, 10, 7);
        VerticalAlignment = VerticalAlignment.Stretch;
    }

    private static ControlTemplate UI__button__create_template()
    {
        FrameworkElementFactory border = new(typeof(Border));
        border.SetValue(Border.BackgroundProperty, new TemplateBindingExtension(BackgroundProperty));
        border.SetValue(Border.BorderBrushProperty, new TemplateBindingExtension(BorderBrushProperty));
        border.SetValue(Border.BorderThicknessProperty, new TemplateBindingExtension(BorderThicknessProperty));
        border.SetValue(Border.CornerRadiusProperty, new TemplateBindingExtension(Button_corner_radiusProperty));

        FrameworkElementFactory contentPresenter = new(typeof(ContentPresenter));
        contentPresenter.SetValue(ContentPresenter.MarginProperty, new TemplateBindingExtension(PaddingProperty));
        contentPresenter.SetValue(ContentPresenter.HorizontalAlignmentProperty, new TemplateBindingExtension(HorizontalContentAlignmentProperty));
        contentPresenter.SetValue(ContentPresenter.VerticalAlignmentProperty, new TemplateBindingExtension(VerticalContentAlignmentProperty));
        contentPresenter.SetValue(ContentPresenter.RecognizesAccessKeyProperty, true);
        border.AppendChild(contentPresenter);

        return new ControlTemplate(typeof(System.Windows.Controls.Button)) { VisualTree = border };
    }

    private void UI__button__apply_visual_state(bool Is_mouse_over, bool Is_mouse_down)
    {
        if (isBlinking)
        {
            return;
        }

        UI__button__apply_visual_state_core(Is_mouse_over, Is_mouse_down);
    }

    private void UI__button__apply_visual_state_core(bool Is_mouse_over, bool Is_mouse_down)
    {
        if (!IsEnabled)
        {
            Button_visual_spec disabledSpec = UI__button__get_visual_spec(false);
            Background = disabledSpec.Background_normal;
            BorderBrush = disabledSpec.Border_normal;
            Foreground = Text_disabled;
            UI__button__apply_content();
            return;
        }

        Button_visual_spec visualSpec = UI__button__get_visual_spec(Is_mouse_over || Is_mouse_down);
        Background = Is_mouse_down ? visualSpec.Background_down : Is_mouse_over ? visualSpec.Background_hover : visualSpec.Background_normal;
        BorderBrush = Is_mouse_down ? visualSpec.Border_down : Is_mouse_over ? visualSpec.Border_hover : visualSpec.Border_normal;
        Foreground = UI__button__foreground_for_background((Brush)Background);
        UI__button__apply_content();
    }

    private Button_visual_spec UI__button__get_visual_spec(bool Use_hover_part)
    {
        Button_color_part colorPart = Color switch
        {
            Noctalk_button_color.Red_O__Red_O => Button_color_part.Red_O,
            Noctalk_button_color.Blue_R__Blue_R => Button_color_part.Blue_R,
            Noctalk_button_color.Red_R__Red_R => Button_color_part.Red_R,
            Noctalk_button_color.Grey_R__Grey_R => Button_color_part.Grey_R,
            Noctalk_button_color.Blue_O__Red_O when Use_hover_part => Button_color_part.Red_O,
            Noctalk_button_color.Blue_O__Blue_R when Use_hover_part => Button_color_part.Blue_R,
            _ => Button_color_part.Blue_O
        };

        return colorPart switch
        {
            Button_color_part.Red_O => new Button_visual_spec(Background_red_normal, Background_red_hover, Background_red_down, Border_red, Border_red, Border_red),
            Button_color_part.Blue_R => new Button_visual_spec(Fill_blue_normal, Fill_blue_hover, Fill_blue_down, Fill_blue_border_normal, Fill_blue_border_hover, Fill_blue_border_down),
            Button_color_part.Red_R => new Button_visual_spec(Fill_red_normal, Fill_red_hover, Fill_red_down, Fill_red_border_normal, Fill_red_border_hover, Fill_red_border_down),
            Button_color_part.Grey_R => new Button_visual_spec(Fill_grey_normal, Fill_grey_hover, Fill_grey_down, Fill_grey_border_normal, Fill_grey_border_hover, Fill_grey_border_down),
            _ => new Button_visual_spec(Background_normal, Background_hover, Background_down, Border_normal, Border_normal, Border_normal)
        };
    }

    private static Brush UI__button__foreground_for_background(Brush The_background)
    {
        if (The_background is not SolidColorBrush solidColorBrush)
        {
            return Text_light;
        }

        WpfColor color = solidColorBrush.Color;
        double brightness = 0.299 * color.R + 0.587 * color.G + 0.114 * color.B;
        return brightness < 128 ? Text_light : Text_dark;
    }

    private void UI__button__apply_content()
    {
        if (Icon == Noctalk_button_icon.None)
        {
            return;
        }

        object? textContent = originalContent;
        bool hasText = textContent is not null && !string.IsNullOrWhiteSpace(textContent.ToString());
        FrameworkElement iconElement = UI__button__create_icon(Icon);

        applyingContent = true;
        try
        {
            if (!hasText)
            {
                if (double.IsNaN(Width) || flag__auto_icon_width_applied)
                {
                    Width = Size switch
                    {
                        Noctalk_button_size.Grid => 22,
                        Noctalk_button_size.Custom => double.IsNaN(Height) ? 34 : Height,
                        _ => 46
                    };
                    flag__auto_icon_width_applied = true;
                }

                Content = iconElement;
                return;
            }

            if (flag__auto_icon_width_applied)
            {
                Width = double.NaN;
                flag__auto_icon_width_applied = false;
            }

            StackPanel panel = new() { Orientation = Orientation.Horizontal, VerticalAlignment = VerticalAlignment.Center, IsHitTestVisible = false };
            panel.Children.Add(iconElement);
            panel.Children.Add(new TextBlock
            {
                Text = textContent?.ToString() ?? string.Empty,
                Margin = new Thickness(8, 0, 0, 0),
                VerticalAlignment = VerticalAlignment.Center,
                Foreground = Foreground,
                FontWeight = FontWeight,
                IsHitTestVisible = false
            });
            Content = panel;
        }
        finally
        {
            applyingContent = false;
        }
    }

    private FrameworkElement UI__button__create_icon(Noctalk_button_icon The_icon)
    {
        double buttonHeight = double.IsNaN(Height) ? Size == Noctalk_button_size.Grid ? 22 : 34 : Height;
        double iconSize = Size == Noctalk_button_size.Grid
            ? 16
            : Math.Clamp(buttonHeight - Padding.Top - Padding.Bottom - 2, 12, 20);
        Canvas canvas = new()
        {
            Width = 20,
            Height = 20,
            IsHitTestVisible = false
        };
        Brush brush = !IsEnabled ? Text_disabled : Foreground;

        switch (The_icon)
        {
            case Noctalk_button_icon.Copy:
                canvas.Children.Add(UI__button__rectangle(4, 3, 9, 11, brush));
                canvas.Children.Add(UI__button__rectangle(8, 7, 9, 11, brush));
                break;
            case Noctalk_button_icon.New:
                canvas.Children.Add(new Ellipse { Width = 16, Height = 16, Margin = new Thickness(2), Stroke = brush, StrokeThickness = 2, IsHitTestVisible = false });
                canvas.Children.Add(UI__button__line(10, 6, 10, 14, brush));
                canvas.Children.Add(UI__button__line(6, 10, 14, 10, brush));
                break;
            case Noctalk_button_icon.Clear:
                canvas.Children.Add(new Rectangle { Width = 12, Height = 2.5, Margin = new Thickness(4, 5, 0, 0), Fill = brush, IsHitTestVisible = false });
                canvas.Children.Add(UI__button__rectangle(5, 8, 10, 8, brush));
                canvas.Children.Add(UI__button__line(8, 10, 8, 14, brush));
                canvas.Children.Add(UI__button__line(12, 10, 12, 14, brush));
                break;
            case Noctalk_button_icon.Menu:
                canvas.Children.Add(UI__button__dot(4, 8, brush));
                canvas.Children.Add(UI__button__dot(9, 8, brush));
                canvas.Children.Add(UI__button__dot(14, 8, brush));
                break;
            case Noctalk_button_icon.Delete:
                canvas.Children.Add(UI__button__line(5, 5, 15, 15, brush));
                canvas.Children.Add(UI__button__line(15, 5, 5, 15, brush));
                break;
            case Noctalk_button_icon.Save:
                canvas.Children.Add(UI__button__rectangle(4, 3, 12, 14, brush));
                canvas.Children.Add(new Rectangle { Width = 7, Height = 4, Margin = new Thickness(7, 3, 0, 0), Fill = brush, IsHitTestVisible = false });
                canvas.Children.Add(new Rectangle { Width = 7, Height = 5, Margin = new Thickness(7, 11, 0, 0), Stroke = brush, StrokeThickness = 2, IsHitTestVisible = false });
                break;
            case Noctalk_button_icon.Refresh:
                canvas.Children.Add(UI__button__line(14, 4, 17, 4, brush));
                canvas.Children.Add(UI__button__line(17, 4, 17, 7, brush));
                canvas.Children.Add(UI__button__line(6, 16, 3, 16, brush));
                canvas.Children.Add(UI__button__line(3, 16, 3, 13, brush));
                canvas.Children.Add(UI__button__arc_path("M 16 7 A 7 7 0 0 0 5 5", brush));
                canvas.Children.Add(UI__button__arc_path("M 4 13 A 7 7 0 0 0 15 15", brush));
                break;
            case Noctalk_button_icon.Trash:
                canvas.Children.Add(new Rectangle { Width = 10, Height = 2, Margin = new Thickness(5, 4, 0, 0), Fill = brush, IsHitTestVisible = false });
                canvas.Children.Add(UI__button__line(8, 3, 12, 3, brush));
                canvas.Children.Add(UI__button__rectangle(6, 7, 8, 10, brush));
                canvas.Children.Add(UI__button__line(8, 9, 8, 15, brush));
                canvas.Children.Add(UI__button__line(12, 9, 12, 15, brush));
                break;
            case Noctalk_button_icon.Open_dropdown:
                canvas.Children.Add(new Polygon
                {
                    Points = new PointCollection { new(3, 6), new(17, 6), new(10, 15) },
                    Fill = brush,
                    IsHitTestVisible = false
                });
                break;
        }

        return new Viewbox
        {
            Width = iconSize,
            Height = iconSize,
            Stretch = Stretch.Uniform,
            IsHitTestVisible = false,
            Child = canvas
        };
    }

    private static Rectangle UI__button__rectangle(double X, double Y, double Width, double Height, Brush Brush)
    {
        return new Rectangle { Width = Width, Height = Height, Margin = new Thickness(X, Y, 0, 0), Stroke = Brush, StrokeThickness = 2, IsHitTestVisible = false };
    }

    private static Line UI__button__line(double X1, double Y1, double X2, double Y2, Brush Brush)
    {
        return new Line { X1 = X1, Y1 = Y1, X2 = X2, Y2 = Y2, Stroke = Brush, StrokeThickness = 2, StrokeStartLineCap = PenLineCap.Round, StrokeEndLineCap = PenLineCap.Round, IsHitTestVisible = false };
    }

    private static System.Windows.Shapes.Path UI__button__arc_path(string The_path_data, Brush Brush)
    {
        return new System.Windows.Shapes.Path { Data = Geometry.Parse(The_path_data), Stroke = Brush, StrokeThickness = 2, StrokeStartLineCap = PenLineCap.Round, StrokeEndLineCap = PenLineCap.Round, Fill = Brushes.Transparent, IsHitTestVisible = false };
    }

    private static Ellipse UI__button__dot(double X, double Y, Brush Brush)
    {
        return new Ellipse { Width = 4, Height = 4, Margin = new Thickness(X, Y, 0, 0), Fill = Brush, IsHitTestVisible = false };
    }

    private enum Button_color_part
    {
        Blue_O,
        Red_O,
        Blue_R,
        Red_R,
        Grey_R
    }

    private readonly record struct Button_visual_spec(Brush Background_normal, Brush Background_hover, Brush Background_down, Brush Border_normal, Brush Border_hover, Brush Border_down);
}
