using DryIoc;
using System.Net;

namespace HistoryView.Controls.Input;

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

    //private readonly Stopwatch sw = new();
    //Point _startPosition;

    private void presenter_TouchEnter(object sender, TouchEventArgs e)
    {
        //TouchPoint point = e.GetTouchPoint(this);
        //_startPosition = point.Position;

        //sw.Start();
    }

    private void presenter_TouchLeave(object sender, TouchEventArgs e)
    {
        //sw.Stop();
        //try
        //{
        //    while (true)
        //    {
        //        if (sw.ElapsedMilliseconds >= 80)
        //            return;
        //        Point point = e.GetTouchPoint(this).Position;
        //        if (Math.Abs(_startPosition.X - point.X) > 1)
        //            return;
        //        if (Math.Abs(_startPosition.Y - point.Y) > 1)
        //            return;
        //        break;
        //    }

        //    Show();
        //}
        //finally
        //{
        //    sw.Reset();
        //}

        Show();

    }


    private void Show()
    {
        if (KeyboardPopStatus.IsDisplayed)
            return;
        KeyboardPopStatus.IsDisplayed = true;
        this.PopKeyboard.IsOpen = true;
        this.Display = this.Text?.ToString()!;
    }

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

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


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

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

    public string Display
    {
        get { return (string)GetValue(DisplayProperty); }
        set { SetValue(DisplayProperty, value); }
    }

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

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

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

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

        switch (Type.GetTypeCode(this.Text.GetType()))
        {
            case TypeCode.Int16:
                if (!Int16.TryParse(this.Display, out short s))
                    return;
                Text = s;
                break;
            case TypeCode.UInt16:
                if (!UInt16.TryParse(this.Display, out ushort us))
                    return;
                Text = us;
                break;
            case TypeCode.Int32:
                if (!Int32.TryParse(this.Display, out int i))
                    return;
                Text = i;
                break;
            case TypeCode.UInt32:
                if (!UInt32.TryParse(this.Display, out uint ui))
                    return;
                Text = ui;
                break;
            case TypeCode.Int64:
                if (!Int64.TryParse(this.Display, out long l))
                    return;
                Text = l;
                break;
            case TypeCode.UInt64:
                if (!UInt64.TryParse(this.Display, out ulong ul))
                    return;
                Text = ul;
                break;
            case TypeCode.Single:
                if (!Single.TryParse(this.Display, out float f))
                    return;
                Text = f;
                break;
            case TypeCode.Double:
                if (!Double.TryParse(this.Display, out double d))
                    return;
                Text = d;
                break;
            case TypeCode.Decimal:
                if (!Decimal.TryParse(this.Display, out decimal dec))
                    return;
                Text = dec;
                break;
            default:
                return;
        }
        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.CommandParameter is not string input)
            return;

        if (Text is null)
            return;

        string temp = Display.TrimStart('0');
        temp += input;

        bool success = Type.GetTypeCode(this.Text.GetType()) switch
        {
            TypeCode.Int16 => Int16.TryParse(temp, out _),
            TypeCode.UInt16 => UInt16.TryParse(temp, out _),
            TypeCode.Int32 => Int32.TryParse(temp, out _),
            TypeCode.UInt32 => UInt32.TryParse(temp, out _),
            TypeCode.Int64 => Int64.TryParse(temp, out _),
            TypeCode.UInt64 => UInt64.TryParse(temp, out _),
            TypeCode.Single => Single.TryParse(temp, out _),
            TypeCode.Double => Double.TryParse(temp, out _),
            TypeCode.Decimal => Decimal.TryParse(temp, out _),
            _ => false
        };

        if (!success)
            return;
        this.Display = temp;
    }
    private void Delete(object sender, RoutedEventArgs e)
    {
        if (Display.Length == 1)
        {
            Display = "0";
            return;
        }

        Display = Display[..^1];
    }

    private void Clear(object sender, RoutedEventArgs e)
    {
        Display = "0";
    }

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

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

        switch (Type.GetTypeCode(this.Text.GetType()))
        {
            case TypeCode.Int16:
                if (!Int16.TryParse(this.Display, out short s))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (s + 1).ToString();
                        break;
                    case "-1":
                        Display = (s - 1).ToString();
                        break;
                    default:
                        return;
                }
                break;
            case TypeCode.UInt16:
                if (!UInt16.TryParse(this.Display, out ushort us))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (us + 1).ToString();
                        break;
                    case "-1":
                        Display = (us - 1).ToString();
                        break;
                    default:
                        return;
                }
                break;
            case TypeCode.Int32:
                if (!Int32.TryParse(this.Display, out int i))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (i + 1).ToString();
                        break;
                    case "-1":
                        Display = (i - 1).ToString();
                        break;
                    default:
                        return;
                }
                break;
            case TypeCode.UInt32:
                if (!UInt32.TryParse(this.Display, out uint ui))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (ui + 1).ToString();
                        break;
                    case "-1":
                        Display = (ui - 1).ToString();
                        break;
                    default:
                        return;
                }
                break;
            case TypeCode.Int64:
                if (!Int64.TryParse(this.Display, out long l))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (l + 1).ToString();
                        break;
                    case "-1":
                        Display = (l - 1).ToString();
                        break;
                    default:
                        return;
                }
                break;
            case TypeCode.UInt64:
                if (!UInt64.TryParse(this.Display, out ulong ul))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (ul + 1).ToString();
                        break;
                    case "-1":
                        Display = (ul - 1).ToString();
                        break;
                    default:
                        return;
                }
                break;
            case TypeCode.Single:
                if (!Single.TryParse(this.Display, out float f))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (f + 1f).ToString("0.0");
                        break;
                    case "-1":
                        Display = (f - 1f).ToString("0.0");
                        break;
                    default:
                        return;
                    case "-.1":
                        Display = (f - 0.1f).ToString("0.0");
                        break;
                    case "+.1":
                        Display = (f + 0.1f).ToString("0.0");
                        break;
                }
                break;
            case TypeCode.Double:
                if (!Double.TryParse(this.Display, out double d))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (d + 1d).ToString("0.0");
                        break;
                    case "-1":
                        Display = (d - 1d).ToString("0.0");
                        break;
                    default:
                        return;
                    case "-.1":
                        Display = (d - 0.1d).ToString("0.0");
                        break;
                    case "+.1":
                        Display = (d + 0.1d).ToString("0.0");
                        break;
                }
                break;
            case TypeCode.Decimal:
                if (!Decimal.TryParse(this.Display, out decimal dec))
                    return;
                switch (Operate)
                {
                    case "+1":
                        Display = (dec + 1).ToString();
                        break;
                    case "-1":
                        Display = (dec - 1).ToString();
                        break;
                    case "-.1":
                        Display = (dec - (decimal)0.1).ToString();
                        break;
                    case "+.1":
                        Display = (dec + (decimal)0.1).ToString();
                        break;
                    default:
                        return;
                }
                break;
            default:
                return;
        }
    }

    private void Button_TouchDown(object sender, TouchEventArgs e)
    {
        if (sender is not Button button)
            return;
        if (this.Hint.IsOpen)
            this.Hint.IsOpen = false;
        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;
            });
        });
    }

    private void presenter_GotFocus(object sender, RoutedEventArgs e)
    {
        Show();
    }
}
