using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Globalization;

namespace HashCalculator.GUI
{
    /// <summary>
    /// InputBar.xaml 的交互逻辑
    /// </summary>
    [SuppressMessage("Microsoft.Performance", "CA1812")]
    internal partial class InputBar : UserControl
    {
        public static readonly DependencyProperty HintTextProperty =
            DependencyProperty.Register(nameof(HintText), typeof(string), typeof(InputBar), new FrameworkPropertyMetadata
            {
                BindsTwoWayByDefault = true,
                DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
            });
        public string? HintText
        {
            get => GetValue(HintTextProperty) as string;
            set => SetValue(HintTextProperty, value);
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(nameof(Text), typeof(string), typeof(InputBar), new FrameworkPropertyMetadata
            {
                BindsTwoWayByDefault = true,
                DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
            });
        public string? Text
        {
            get => GetValue(TextProperty) as string;
            set => SetValue(TextProperty, value);
        }

        public static readonly DependencyProperty CollectionProperty =
            DependencyProperty.Register(nameof(Collection), typeof(IEnumerable<InputEntry>), typeof(InputBar), new FrameworkPropertyMetadata
            {
                BindsTwoWayByDefault = true,
                DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                CoerceValueCallback = (d, baseObject) =>
                {
                    var value = baseObject as IEnumerable<InputEntry>;
                    if (value?.Count() > 100)
                    {
                        value = value
                            .Take(99)
                            .Append(new InputEntry(InputEntryType.Path, $"Other {value.Count() - 50} items...", string.Empty));
                    }
                    return value;
                }
            });
        public IEnumerable<InputEntry>? Collection
        {
            get => GetValue(CollectionProperty) as IEnumerable<InputEntry>;
            set => SetValue(CollectionProperty, value);
        }

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register(nameof(SelectedItem), typeof(InputEntry), typeof(InputBar), new FrameworkPropertyMetadata
            {
                BindsTwoWayByDefault = true,
                DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                PropertyChangedCallback = (d, e) =>
                {
                    var self = (InputBar)d;
                    self.OnSelectionChanged();
                }
            });
        public InputEntry? SelectedItem
        {
            get => GetValue(SelectedItemProperty) as InputEntry;
            set => SetValue(SelectedItemProperty, value);
        }

        public static readonly DependencyProperty SelectedIndexProperty =
            DependencyProperty.Register(nameof(SelectedIndex), typeof(int), typeof(InputBar), new FrameworkPropertyMetadata
            {
                BindsTwoWayByDefault = true,
                DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                CoerceValueCallback = (d, baseObject) =>
                {
                    var self = (InputBar)d;
                    return self.NormalizeIndex((int)baseObject);
                }
            });
        public int SelectedIndex
        {
            get => (int)GetValue(SelectedIndexProperty);
            set => SetValue(SelectedIndexProperty, value);
        }

        public InputBar()
        {
            InitializeComponent();
        }

        private void OnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Down:
                    SelectedIndex += 1;
                    ListBox.ScrollIntoView(ListBox.SelectedItem);
                    DropDown.IsOpen = true;
                    break;
                case Key.Up:
                    SelectedIndex -= 1;
                    ListBox.ScrollIntoView(ListBox.SelectedItem);
                    break;
                case Key.Escape:
                case Key.Enter:
                    DropDown.IsOpen = false;
                    break;
                default:
                    DropDown.IsOpen = true;
                    break;
            }
        }

        private void OnSelectionChanged()
        {
            if (SelectedItem != null)
            {
                Text = SelectedItem.ToString();
                TextBox.Select(Text.Length, 0);
            }
        }

        private void OnLostFocus(object sender, RoutedEventArgs e)
        {
            DropDown.IsOpen = false;
        }

        private int NormalizeIndex(int rawIndex)
        {
            if (Collection == null)
            {
                return -1;
            }

            return Math.Min(Math.Max(rawIndex, -1), Collection.Count() - 1);
        }

        private void OnToggleDropDownButtonClick(object sender, RoutedEventArgs e)
        {
            TextBox.Focus();
            TextBox.Select(Text?.Length ?? 0, 0);
            if (!DropDown.IsOpen)
            {
                DropDown.IsOpen = true;
            }
        }
    }
}