using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Noctalk.UI.Components.Input;

public sealed class Noctalk_numeric_up_down : Grid
{
    private static readonly Brush Background_normal = new SolidColorBrush(Color.FromRgb(8, 16, 29));
    private static readonly Brush Background_hover = new SolidColorBrush(Color.FromRgb(10, 42, 68));
    private static readonly Brush Border_normal = new SolidColorBrush(Color.FromRgb(20, 107, 147));
    private static readonly Brush Text_normal = new SolidColorBrush(Color.FromRgb(185, 243, 255));
    private static readonly Brush Accent = new SolidColorBrush(Color.FromRgb(73, 217, 255));
    private readonly Border outerBorder = new();
    private readonly TextBox textBox = new();
    private readonly StackPanel buttonPanel = new();

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
        nameof(Value),
        typeof(int),
        typeof(Noctalk_numeric_up_down),
        new PropertyMetadata(0, UI__numeric__value_changed));

    public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
        nameof(Minimum),
        typeof(int),
        typeof(Noctalk_numeric_up_down),
        new PropertyMetadata(0));

    public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
        nameof(Maximum),
        typeof(int),
        typeof(Noctalk_numeric_up_down),
        new PropertyMetadata(100));

    public int Value
    {
        get => (int)GetValue(ValueProperty);
        set => SetValue(ValueProperty, Math.Clamp(value, Minimum, Maximum));
    }

    public int Minimum
    {
        get => (int)GetValue(MinimumProperty);
        set => SetValue(MinimumProperty, value);
    }

    public int Maximum
    {
        get => (int)GetValue(MaximumProperty);
        set => SetValue(MaximumProperty, value);
    }

    public Noctalk_numeric_up_down()
    {
        Height = 34;
        MinHeight = 34;
        MinWidth = 92;
        Margin = new Thickness(4);
        Cursor = System.Windows.Input.Cursors.IBeam;

        outerBorder.Background = Background_normal;
        outerBorder.BorderBrush = Border_normal;
        outerBorder.BorderThickness = new Thickness(1);

        Grid contentGrid = new();
        contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star), MinWidth = 34 });
        contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(54) });

        textBox.Height = 32;
        textBox.MinHeight = 32;
        textBox.MinWidth = 34;
        textBox.Margin = new Thickness(0);
        textBox.Padding = new Thickness(8, 5, 8, 5);
        textBox.Background = Brushes.Transparent;
        textBox.Foreground = Text_normal;
        textBox.CaretBrush = Accent;
        textBox.BorderThickness = new Thickness(0);
        textBox.VerticalContentAlignment = VerticalAlignment.Center;
        textBox.PreviewTextInput += (_, args) => args.Handled = !args.Text.All(char.IsDigit);
        textBox.TextChanged += (_, _) => UI__numeric__commit_text();
        textBox.GotKeyboardFocus += (_, _) => UI__numeric__show_buttons(true);
        textBox.LostKeyboardFocus += (_, _) => UI__numeric__show_buttons(IsMouseOver);

        buttonPanel.Orientation = Orientation.Horizontal;
        buttonPanel.Margin = new Thickness(0, 0, 2, 0);
        buttonPanel.Width = 52;
        buttonPanel.VerticalAlignment = VerticalAlignment.Center;
        buttonPanel.Visibility = Visibility.Collapsed;

        buttonPanel.Children.Add(UI__numeric__create_inner_button("-", -1));
        buttonPanel.Children.Add(UI__numeric__create_inner_button("+", 1));

        Grid.SetColumn(textBox, 0);
        Grid.SetColumn(buttonPanel, 1);
        contentGrid.Children.Add(textBox);
        contentGrid.Children.Add(buttonPanel);
        outerBorder.Child = contentGrid;
        Children.Add(outerBorder);

        MouseEnter += (_, _) => UI__numeric__show_buttons(true);
        MouseLeave += (_, _) => UI__numeric__show_buttons(textBox.IsKeyboardFocusWithin);
        UI__numeric__sync_text();
    }

    private System.Windows.Controls.Button UI__numeric__create_inner_button(string The_text, int The_delta)
    {
        System.Windows.Controls.Button button = new()
        {
            Content = The_text,
            Width = 25,
            Height = 25,
            Margin = new Thickness(1, 0, 0, 0),
            Padding = new Thickness(0),
            Background = Background_normal,
            Foreground = Accent,
            BorderBrush = Border_normal,
            BorderThickness = new Thickness(1),
            FontSize = 17,
            FontWeight = FontWeights.Bold,
            Cursor = System.Windows.Input.Cursors.Hand,
            Template = UI__numeric__button_template()
        };
        button.Click += (_, _) => Value += The_delta;
        return button;
    }

    private static ControlTemplate UI__numeric__button_template()
    {
        FrameworkElementFactory border = new(typeof(Border));
        border.Name = "ButtonBorder";
        border.SetValue(Border.BackgroundProperty, new TemplateBindingExtension(Control.BackgroundProperty));
        border.SetValue(Border.BorderBrushProperty, new TemplateBindingExtension(Control.BorderBrushProperty));
        border.SetValue(Border.BorderThicknessProperty, new TemplateBindingExtension(Control.BorderThicknessProperty));

        FrameworkElementFactory content = new(typeof(ContentPresenter));
        content.SetValue(ContentPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
        content.SetValue(ContentPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);
        border.AppendChild(content);

        ControlTemplate template = new(typeof(System.Windows.Controls.Button)) { VisualTree = border };
        Trigger hoverTrigger = new() { Property = UIElement.IsMouseOverProperty, Value = true };
        hoverTrigger.Setters.Add(new Setter(Control.BackgroundProperty, Background_hover));
        template.Triggers.Add(hoverTrigger);
        return template;
    }

    private static void UI__numeric__value_changed(DependencyObject Dependency_object, DependencyPropertyChangedEventArgs Event_args)
    {
        ((Noctalk_numeric_up_down)Dependency_object).UI__numeric__sync_text();
    }

    private void UI__numeric__commit_text()
    {
        if (int.TryParse(textBox.Text.Trim(), out int parsedValue))
        {
            int clampedValue = Math.Clamp(parsedValue, Minimum, Maximum);
            if (clampedValue != Value)
            {
                Value = clampedValue;
            }
        }
    }

    private void UI__numeric__sync_text()
    {
        string valueText = Value.ToString();
        if (textBox.Text != valueText)
        {
            textBox.Text = valueText;
        }
    }

    private void UI__numeric__show_buttons(bool Flag__show)
    {
        buttonPanel.Visibility = Flag__show ? Visibility.Visible : Visibility.Collapsed;
        outerBorder.Background = Flag__show ? Background_hover : Background_normal;
    }
}
