using Noctalk.UI.Components.Confirmation;
using System.Collections.Specialized;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Noctalk.UI.Components.Chat;

public sealed class Chat__send_message__area : Grid
{
    private const int Max__message__characters = 50000;
    private static readonly Brush Text_normal = new SolidColorBrush(Color.FromRgb(185, 243, 255));
    private static readonly Brush Placeholder_text = new SolidColorBrush(Color.FromRgb(125, 152, 168));
    private static readonly Brush Caret = new SolidColorBrush(Color.FromRgb(73, 217, 255));
    private static readonly Brush Selection = new SolidColorBrush(Color.FromRgb(20, 90, 119));
    private static readonly Brush Scrollbar_track = new SolidColorBrush(Color.FromRgb(5, 9, 18));
    private static readonly Brush Scrollbar_thumb = new SolidColorBrush(Color.FromRgb(20, 107, 147));
    private static readonly Brush Scrollbar_thumb_hover = new SolidColorBrush(Color.FromRgb(73, 217, 255));
    private static readonly Brush Send_background_normal = new SolidColorBrush(Color.FromRgb(14, 101, 138));
    private static readonly Brush Send_background_hover = new SolidColorBrush(Color.FromRgb(22, 132, 176));
    private static readonly Brush Send_background_down = new SolidColorBrush(Color.FromRgb(9, 76, 108));
    private static readonly Brush Send_background_disabled = new SolidColorBrush(Color.FromRgb(8, 26, 42));
    private static readonly Brush Send_border = new SolidColorBrush(Color.FromRgb(7, 45, 66));
    private static readonly Brush Send_border_disabled = new SolidColorBrush(Color.FromRgb(4, 28, 42));
    private static readonly Brush Send_text = new SolidColorBrush(Color.FromRgb(225, 252, 255));
    private static readonly Brush Send_text_disabled = new SolidColorBrush(Color.FromRgb(72, 102, 118));
    private readonly TextBox textBox = new();
    private readonly TextBlock placeholder = new();
    private readonly System.Windows.Controls.Button sendButton = new();
    private readonly Grid inputHost = new();
    private readonly WrapPanel previewPanel = new();
    private readonly ScrollViewer previewScrollViewer = new();
    private readonly List<BitmapSource> pendingImages = [];
    private bool isTrimmingText;

    public event EventHandler? Send_requested;

    public string Text
    {
        get => textBox.Text;
        set
        {
            textBox.Text = value;
            UI__chat_send_area__sync_state();
        }
    }

    public bool Has_pending_image => pendingImages.Count > 0;

    public Chat__send_message__area()
    {
        HorizontalAlignment = HorizontalAlignment.Stretch;
        VerticalAlignment = VerticalAlignment.Center;

        ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
        ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

        RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });

        inputHost.VerticalAlignment = VerticalAlignment.Center;

        placeholder.Text = "Write a message";
        placeholder.Foreground = Placeholder_text;
        placeholder.VerticalAlignment = VerticalAlignment.Center;
        placeholder.Margin = new Thickness(11, 0, 8, 0);
        placeholder.IsHitTestVisible = false;

        textBox.AcceptsReturn = true;
        textBox.TextWrapping = TextWrapping.Wrap;
        textBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
        textBox.MinHeight = 34;
        textBox.MaxHeight = 174;
        textBox.Margin = new Thickness(0);
        textBox.Padding = new Thickness(8, 6, 8, 6);
        textBox.Background = Brushes.Transparent;
        textBox.Foreground = Text_normal;
        textBox.CaretBrush = Caret;
        textBox.SelectionBrush = Selection;
        textBox.BorderThickness = new Thickness(0);
        textBox.VerticalContentAlignment = VerticalAlignment.Top;
        textBox.Resources.Add(typeof(ScrollBar), UI__chat_send_area__scrollbar_style());
        textBox.TextChanged += (_, _) => UI__chat_send_area__text_changed();
        textBox.PreviewKeyDown += Textbox__preview_key_down;
        textBox.CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, Textbox__paste_executed));

        previewPanel.Orientation = Orientation.Horizontal;
        previewScrollViewer.Visibility = Visibility.Collapsed;
        previewScrollViewer.HorizontalAlignment = HorizontalAlignment.Left;
        previewScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
        previewScrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
        previewScrollViewer.Margin = new Thickness(8, 0, 0, 6);
        previewScrollViewer.MaxHeight = 74;
        previewScrollViewer.Content = previewPanel;

        sendButton.Content = "Send";
        sendButton.IsEnabled = false;
        sendButton.MinWidth = 74;
        sendButton.Height = 38;
        sendButton.Margin = new Thickness(14, 0, 8, 0);
        sendButton.Padding = new Thickness(14, 7, 14, 7);
        sendButton.FontWeight = FontWeights.SemiBold;
        sendButton.Foreground = Send_text_disabled;
        sendButton.Background = Send_background_disabled;
        sendButton.BorderBrush = Send_border_disabled;
        sendButton.BorderThickness = new Thickness(1);
        sendButton.Cursor = Cursors.Hand;
        sendButton.Template = UI__chat_send_area__send_button_template();
        sendButton.VerticalAlignment = VerticalAlignment.Center;
        sendButton.Click += (_, _) => Send_requested?.Invoke(this, EventArgs.Empty);
        sendButton.IsEnabledChanged += (_, _) => UI__chat_send_area__apply_send_button_visual(false, false);
        sendButton.MouseEnter += (_, _) => UI__chat_send_area__apply_send_button_visual(true, false);
        sendButton.MouseLeave += (_, _) => UI__chat_send_area__apply_send_button_visual(false, false);
        sendButton.PreviewMouseDown += (_, _) => UI__chat_send_area__apply_send_button_visual(true, true);
        sendButton.PreviewMouseUp += (_, _) => UI__chat_send_area__apply_send_button_visual(sendButton.IsMouseOver, false);

        inputHost.Children.Add(placeholder);
        inputHost.Children.Add(textBox);
        Grid.SetColumn(previewScrollViewer, 0);
        Grid.SetRow(previewScrollViewer, 0);
        Grid.SetColumn(inputHost, 0);
        Grid.SetRow(inputHost, 1);
        Grid.SetColumn(sendButton, 1);
        Grid.SetRow(sendButton, 0);
        Grid.SetRowSpan(sendButton, 2);
        Children.Add(previewScrollViewer);
        Children.Add(inputHost);
        Children.Add(sendButton);
        UI__chat_send_area__apply_layout_mode();
    }

    public Chat_send_message_payload Consume_payload()
    {
        Chat_send_message_payload payload = new()
        {
            Text = textBox.Text.Trim(),
            Images = pendingImages.ToList()
        };

        Clear();
        return payload;
    }

    public void Clear()
    {
        textBox.Clear();
        UI__chat_send_area__clear_pending_image();
        UI__chat_send_area__sync_state();
    }

    public void Focus_input()
    {
        textBox.Focus();
        Keyboard.Focus(textBox);
    }

    private void Textbox__preview_key_down(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.V && Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && UI__chat_send_area__try_paste_image())
        {
            e.Handled = true;
            return;
        }

        if (e.Key != Key.Enter || Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
        {
            return;
        }

        e.Handled = true;
        Send_requested?.Invoke(this, EventArgs.Empty);
    }

    private void UI__chat_send_area__sync_state()
    {
        bool hasText = !string.IsNullOrWhiteSpace(textBox.Text);
        sendButton.IsEnabled = hasText || pendingImages.Count > 0;
        placeholder.Visibility = hasText || pendingImages.Count > 0 ? Visibility.Collapsed : Visibility.Visible;
        UI__chat_send_area__apply_layout_mode();
        UI__chat_send_area__apply_send_button_visual(sendButton.IsMouseOver, false);
    }

    private void UI__chat_send_area__apply_layout_mode()
    {
        if (pendingImages.Count == 0)
        {
            Grid.SetRow(inputHost, 0);
            Grid.SetRow(sendButton, 0);
            Grid.SetRowSpan(sendButton, 1);
            return;
        }

        Grid.SetRow(inputHost, 1);
        Grid.SetRow(sendButton, 0);
        Grid.SetRowSpan(sendButton, 2);
    }

    private void Textbox__paste_executed(object sender, ExecutedRoutedEventArgs e)
    {
        if (UI__chat_send_area__try_paste_image())
        {
            e.Handled = true;
            return;
        }

        if (Clipboard.ContainsText())
        {
            string clipboardText = Clipboard.GetText();
            int selectionStart = textBox.SelectionStart;
            textBox.Text = textBox.Text.Remove(selectionStart, textBox.SelectionLength).Insert(selectionStart, clipboardText);
            textBox.CaretIndex = selectionStart + clipboardText.Length;
        }

        e.Handled = true;
    }

    private bool UI__chat_send_area__try_paste_image()
    {
        List<string> imagePaths = [];

        if (Clipboard.ContainsFileDropList())
        {
            StringCollection fileDropList = Clipboard.GetFileDropList();
            imagePaths = fileDropList.Cast<string>().Where(UI__chat_send_area__is_supported_image_path).ToList();
        }

        if (imagePaths.Count > 0)
        {
            if (!Chat__image_batch_policy.Confirm_if_large_image_batch(Window.GetWindow(this), imagePaths))
            {
                return true;
            }

            foreach (string imagePath in imagePaths)
            {
                BitmapImage bitmapImage = new();
                bitmapImage.BeginInit();
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.UriSource = new Uri(imagePath);
                bitmapImage.EndInit();
                bitmapImage.Freeze();
                UI__chat_send_area__add_pending_image(bitmapImage);
            }

            return true;
        }

        if (!Clipboard.ContainsImage())
        {
            return false;
        }

        if (!Chat__clipboard_image_reader.Try_get_clipboard_image(out BitmapSource? clipboardImage) || clipboardImage is null)
        {
            return false;
        }

        UI__chat_send_area__add_pending_image(clipboardImage);
        return true;
    }

    private void UI__chat_send_area__add_pending_image(BitmapSource The_image)
    {
        pendingImages.Add(The_image);
        UI__chat_send_area__render_previews();
        UI__chat_send_area__sync_state();
    }

    private void UI__chat_send_area__render_previews()
    {
        previewPanel.Children.Clear();
        for (int index = 0; index < pendingImages.Count; index++)
        {
            int imageIndex = index;
            previewPanel.Children.Add(new Chat__send_message__image_preview(pendingImages[index], () => UI__chat_send_area__remove_pending_image(imageIndex)));
        }

        previewScrollViewer.Visibility = pendingImages.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
    }

    private void UI__chat_send_area__remove_pending_image(int The_index)
    {
        if (The_index < 0 || The_index >= pendingImages.Count)
        {
            return;
        }

        pendingImages.RemoveAt(The_index);
        UI__chat_send_area__render_previews();
        UI__chat_send_area__sync_state();
        textBox.Focus();
    }

    private void UI__chat_send_area__clear_pending_image()
    {
        pendingImages.Clear();
        UI__chat_send_area__render_previews();
    }

    private void UI__chat_send_area__text_changed()
    {
        if (!isTrimmingText && textBox.Text.Length > Max__message__characters)
        {
            isTrimmingText = true;
            int caretIndex = Math.Min(textBox.CaretIndex, Max__message__characters);
            textBox.Text = textBox.Text[..Max__message__characters];
            textBox.CaretIndex = caretIndex;
            isTrimmingText = false;
            Noctalk_message.Show(Window.GetWindow(this), "Message too long", "The message is too long, something was cut off.");
        }

        UI__chat_send_area__sync_state();
    }

    private static Style UI__chat_send_area__scrollbar_style()
    {
        Style style = new(typeof(ScrollBar));
        style.Setters.Add(new Setter(WidthProperty, 7.0));
        style.Setters.Add(new Setter(MinWidthProperty, 7.0));
        style.Setters.Add(new Setter(BackgroundProperty, Scrollbar_track));
        style.Setters.Add(new Setter(Control.ForegroundProperty, Scrollbar_thumb));
        return style;
    }

    private static ControlTemplate UI__chat_send_area__send_button_template()
    {
        FrameworkElementFactory border = new(typeof(Border));
        border.SetValue(Border.BackgroundProperty, new TemplateBindingExtension(Control.BackgroundProperty));
        border.SetValue(Border.BorderBrushProperty, new TemplateBindingExtension(Control.BorderBrushProperty));
        border.SetValue(Border.BorderThicknessProperty, new TemplateBindingExtension(Control.BorderThicknessProperty));
        border.SetValue(Border.CornerRadiusProperty, new CornerRadius(12));

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

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

    private static bool UI__chat_send_area__is_supported_image_path(string The_path)
    {
        string extension = Path.GetExtension(The_path).ToLowerInvariant();
        return extension is ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif";
    }

    private void UI__chat_send_area__apply_send_button_visual(bool Is_mouse_over, bool Is_mouse_down)
    {
        if (!sendButton.IsEnabled)
        {
            sendButton.Background = Send_background_disabled;
            sendButton.BorderBrush = Send_border_disabled;
            sendButton.Foreground = Send_text_disabled;
            return;
        }

        sendButton.Background = Is_mouse_down ? Send_background_down : Is_mouse_over ? Send_background_hover : Send_background_normal;
        sendButton.BorderBrush = Send_border;
        sendButton.Foreground = Send_text;
    }
}

public sealed class Chat_send_message_payload
{
    public string Text { get; set; } = string.Empty;

    public List<BitmapSource> Images { get; set; } = [];
}
