using System.Text;

namespace HistoryView.Controls.Input;

public partial class TextboxKeyboard : UserControl
{
    public TextboxKeyboard()
    {
        InitializeComponent();
    }

    private void TextBox_GotFocus(object sender, RoutedEventArgs e)
    {
        //if (TabTipHelper.ShowTaptip())
        //    return;
        if (KeyboardPopStatus.IsDisplayed)
            return;
        KeyboardPopStatus.IsDisplayed = true;
        this.PopKeyboard.IsOpen = true;
        this.Display = this.Text?.ToString()!;
    }

    public bool DirectInput
    {
        get { return (bool)GetValue(DirectInputProperty); }
        set { SetValue(DirectInputProperty, value); }
    }

    public static readonly DependencyProperty DirectInputProperty =
        DependencyProperty.Register("DirectInput", typeof(bool), typeof(TextboxKeyboard), new PropertyMetadata(false, DirectInputChangedCallback));

    private static void DirectInputChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not TextboxKeyboard keyboard)
            return;

        if (e.NewValue is not bool direct)
            return;

        if (direct)
        {
            keyboard.Preview.Visibility = Visibility.Collapsed;
            keyboard.Selection.Visibility = Visibility.Collapsed;
            keyboard.Cancel.IsEnabled = false;
            keyboard.Cancel.Background = (Brush)App.Current.Resources["DisableColor"];
        }
        else
        {
            keyboard.Preview.Visibility = Visibility.Visible;
            keyboard.Selection.Visibility = Visibility.Visible;
            keyboard.Cancel.IsEnabled = true;
            keyboard.Cancel.Background = (Brush)App.Current.Resources["EmergencyColor"];
        }

    }

    public object DisplayContent
    {
        get { return (object)GetValue(DisplayContentProperty); }
        set { SetValue(DisplayContentProperty, value); }
    }

    public static readonly DependencyProperty DisplayContentProperty =
        DependencyProperty.Register("DisplayContent", typeof(object), typeof(TextboxKeyboard), new PropertyMetadata(default));

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(TextboxKeyboard), new PropertyMetadata(default));

    public IEnumerable<string> BackWords
    {
        get { return (IEnumerable<string>)GetValue(BackWordsProperty); }
        set { SetValue(BackWordsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for BackWords.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty BackWordsProperty =
        DependencyProperty.Register("BackWords", typeof(IEnumerable<string>), typeof(TextboxKeyboard), new PropertyMetadata(default));


    #region Private Dependcy Properties
    private string Display
    {
        get { return (string)GetValue(DisplayProperty); }
        set { SetValue(DisplayProperty, value); }
    }

    public static readonly DependencyProperty DisplayProperty =
        DependencyProperty.Register("Display", typeof(string), typeof(TextboxKeyboard), new PropertyMetadata(default));


    public ObservableCollection<string> Filtered
    {
        get { return (ObservableCollection<string>)GetValue(FilteredProperty); }
        set { SetValue(FilteredProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Filtered.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FilteredProperty =
        DependencyProperty.Register("Filtered", typeof(ObservableCollection<string>), typeof(TextboxKeyboard), new PropertyMetadata(default));

    private bool IsCaps
    {
        get { return (bool)GetValue(IsCapsProperty); }
        set { SetValue(IsCapsProperty, value); }
    }

    public static readonly DependencyProperty IsCapsProperty =
        DependencyProperty.Register("IsCaps", typeof(bool), typeof(TextboxKeyboard), new PropertyMetadata(false, PropertyChangedCallback));

    private bool IsShift
    {
        get { return (bool)GetValue(IsShiftProperty); }
        set { SetValue(IsShiftProperty, value); }
    }

    public static readonly DependencyProperty IsShiftProperty =
        DependencyProperty.Register("IsShift", typeof(bool), typeof(TextboxKeyboard), new PropertyMetadata(false, PropertyChangedCallback));
    static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not TextboxKeyboard keyboard)
            return;

        if (e.NewValue is not bool b)
            return;

        List<TextBlock> textBlocks = FindVisualChildren.Find<TextBlock>(keyboard.Line1);
        textBlocks.AddRange(FindVisualChildren.Find<TextBlock>(keyboard.Line2));
        textBlocks.AddRange(FindVisualChildren.Find<TextBlock>(keyboard.Line3));

        foreach (TextBlock textBlock in textBlocks)
        {
            if (textBlock.Text.Length != 1)
                continue;

            byte t = Encoding.ASCII.GetBytes(textBlock.Text)[0];

            if (b && t >= 97 && t <= 122)
            {
                textBlock.Text = Encoding.ASCII.GetString([(byte)(t - 32)]);
            }
            if (!b && t >= 65 && t <= 90)
            {
                textBlock.Text = Encoding.ASCII.GetString([(byte)(t + 32)]);
            }

        }

    }
    #endregion


    private void CancelConfirm(object sender, RoutedEventArgs e)
    {
        if (sender is not Button button)
            return;

        if (button.CommandParameter is not string input)
            return;

        if (DirectInput)
        {
            this.PopKeyboard.IsOpen = false;
            KeyboardPopStatus.IsDisplayed = false;
            Keyboard.ClearFocus();
            return;
        }

        if (input == "Cancel")
        {
            this.Display = string.Empty;
            this.PopKeyboard.IsOpen = false;
            KeyboardPopStatus.IsDisplayed = false;
            Keyboard.ClearFocus();
            return;
        }

        this.Text = Display;
        this.PopKeyboard.IsOpen = false;
        KeyboardPopStatus.IsDisplayed = false;
        Keyboard.ClearFocus();

    }
    private void SendKey(object sender, RoutedEventArgs e)
    {
        if (sender is not Button button)
            return;

        if (button.Content is not string input)
            return;

        if (Text is null)
            return;

        input = input switch
        {
            "Space" => " ",
            _ => input
        };

        if (this.IsCaps)
            input = input.ToUpper();
        if (this.IsShift)
        {
            this.IsShift = false;
            input = input.ToUpper();
        }

        if (!this.DirectInput)
        {
            this.Display += input;
            if (this.BackWords is null)
                return;
            this.Filtered ??= [];
            this.Filtered.Clear();
            IEnumerable<string> filtered = this.BackWords.Where(t => t.Contains(this.Display));
            this.Filtered.AddRange(filtered);
        }
        else
        {
            this.Text += input;
        }
    }
    private void Delete(object sender, RoutedEventArgs e)
    {

        if (!this.DirectInput)
        {

            if (string.IsNullOrEmpty(this.Display))
                return;

            if (Display.Length == 1)
            {
                Display = string.Empty;
                return;
            }

            Display = Display[..^1];
        }
        else
        {
            if (string.IsNullOrEmpty(this.Text))
                return;

            if (Text.Length == 1)
            {
                Text = string.Empty;
                return;
            }

            Text = Text[..^1];
        }
    }

    private void Clear(object sender, RoutedEventArgs e)
    {
        if (!this.DirectInput)
        {
            Display = string.Empty;
            this.Filtered ??= [];
            this.Filtered.Clear();
        }
        else
        {
            Text = string.Empty;
        }
    }

    private void Select(object sender, RoutedEventArgs e)
    {
        if (sender is not Button button)
            return;

        if (button.Content is not string input)
            return;

        if (Text is null)
            return;
        this.Display = input;
        this.Filtered ??= [];
        this.Filtered.Clear();
    }

    private void Button_TouchDown(object sender, TouchEventArgs e)
    {
        if (sender is not Button button)
            return;

        if (IsShift || IsCaps)
            this.HintText.Text = ((string)button.Content).ToUpper();
        else
            this.HintText.Text = (string)button.Content;

        this.Hint.PlacementTarget = button;
        this.Hint.IsOpen = true;
    }

    private void Button_TouchLeave(object sender, TouchEventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            Thread.Sleep(200);
            App.Current.Dispatcher.Invoke(() =>
            {
                this.Hint.IsOpen = false;
            });
        });
    }
}
