using FasdDesktopUi.Basics.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Basics.UserControls
{
    public partial class HierarchicalSelectionControl : UserControl
    {
        private readonly ObservableCollection<HierarchicalSelectionItem> visibleItems = new ObservableCollection<HierarchicalSelectionItem>();
        private readonly Dictionary<string, HierarchicalSelectionItem> itemLookup = new Dictionary<string, HierarchicalSelectionItem>();
        private readonly DispatcherTimer searchDelayTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) };
        private string lastSearchText = string.Empty;
        private bool suppressTreeSelectionChanged;

        private TextBox searchTextBox;
        private TreeView treeViewControl;

        public ObservableCollection<HierarchicalSelectionItem> VisibleItems => visibleItems;

        public event EventHandler DropDownOpened;
        public event EventHandler DropDownClosed;

        public HierarchicalSelectionControl()
        {
            InitializeComponent();
            searchDelayTimer.Tick += SearchDelayTimer_Tick;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            EnsureTemplateParts();
            if (treeViewControl != null)
                treeViewControl.ItemsSource = VisibleItems;
            UpdateDisplaySelection();
        }

        #region DependencyProperties

        public ObservableCollection<HierarchicalSelectionItem> ItemsSource
        {
            get => (ObservableCollection<HierarchicalSelectionItem>)GetValue(ItemsSourceProperty);
            set => SetValue(ItemsSourceProperty, value);
        }

        public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
            nameof(ItemsSource),
            typeof(ObservableCollection<HierarchicalSelectionItem>),
            typeof(HierarchicalSelectionControl),
            new PropertyMetadata(null, OnItemsSourceChanged));

        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is HierarchicalSelectionControl control)
            {
                control.RebuildLookup();
                control.ApplyFilter(control.lastSearchText);
                control.TryExpandToSelectedItem();
            }
        }

        public HierarchicalSelectionItem SelectedItem
        {
            get => (HierarchicalSelectionItem)GetValue(SelectedItemProperty);
            set => SetValue(SelectedItemProperty, value);
        }

        public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
            nameof(SelectedItem),
            typeof(HierarchicalSelectionItem),
            typeof(HierarchicalSelectionControl),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemChanged));

        private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is HierarchicalSelectionControl control)
            {
                control.LogSelectedItemChange(e.NewValue as HierarchicalSelectionItem);
                control.TryExpandToSelectedItem();
            }
        }

        public Brush ComboBoxBackground
        {
            get => (Brush)GetValue(ComboBoxBackgroundProperty);
            set => SetValue(ComboBoxBackgroundProperty, value);
        }

        public static readonly DependencyProperty ComboBoxBackgroundProperty =
            DependencyProperty.Register(nameof(ComboBoxBackground), typeof(Brush), typeof(HierarchicalSelectionControl), new PropertyMetadata(Brushes.Transparent));

        public string SearchPlaceholderText
        {
            get => (string)GetValue(SearchPlaceholderTextProperty);
            set => SetValue(SearchPlaceholderTextProperty, value);
        }

        public static readonly DependencyProperty SearchPlaceholderTextProperty =
            DependencyProperty.Register(nameof(SearchPlaceholderText), typeof(string), typeof(HierarchicalSelectionControl), new PropertyMetadata(string.Empty));

        #endregion

        private void ComboBoxControl_DropDownOpened(object sender, EventArgs e)
        {
            EnsureTemplateParts();
            searchTextBox?.Focus();
            searchTextBox?.SelectAll();
            suppressTreeSelectionChanged = false;
            LogEntry($"[CategoryPicker] DropDownOpened. Selected={SelectedItem?.FullPath ?? "<null>"}");
            DropDownOpened?.Invoke(this, e);
        }

        private void ComboBoxControl_DropDownClosed(object sender, EventArgs e)
        {
            searchDelayTimer.Stop();
            suppressTreeSelectionChanged = false;
            LogEntry("[CategoryPicker] DropDownClosed");
            DropDownClosed?.Invoke(this, e);
        }

        private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            searchDelayTimer.Stop();
            searchDelayTimer.Start();
        }

        private void SearchDelayTimer_Tick(object sender, EventArgs e)
        {
            searchDelayTimer.Stop();
            lastSearchText = searchTextBox?.Text ?? string.Empty;
            LogEntry($"[CategoryPicker] Search text changed: '{lastSearchText}'");
            ApplyFilter(lastSearchText);
        }

        private void TreeViewControl_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (suppressTreeSelectionChanged)
                return;

            if (e.NewValue is HierarchicalSelectionItem selected)
            {
                var original = ResolveOriginalItem(selected);
                if (original != null && !Equals(SelectedItem, original))
                {
                    SelectedItem = original;
                    LogEntry($"[CategoryPicker] Tree selection changed: {original.FullPath}");
                }

                suppressTreeSelectionChanged = true;
                ComboBoxControl.IsDropDownOpen = false;
            }
        }

        private HierarchicalSelectionItem ResolveOriginalItem(HierarchicalSelectionItem item)
        {
            if (item == null)
                return null;

            if (!string.IsNullOrWhiteSpace(item.Id) && itemLookup.TryGetValue(item.Id, out var original))
                return original;

            return null;
        }

        private void RebuildLookup()
        {
            itemLookup.Clear();

            if (ItemsSource == null)
                return;

            foreach (var entry in ItemsSource.SelectMany(item => item.SelfAndDescendants()))
            {
                if (string.IsNullOrWhiteSpace(entry.Id))
                    continue;

                itemLookup[entry.Id] = entry;
            }
        }

        private void ApplyFilter(string searchText)
        {
            visibleItems.Clear();

            if (ItemsSource == null)
                return;

            if (string.IsNullOrWhiteSpace(searchText))
            {
                foreach (var item in ItemsSource)
                {
                    item.SetExpandedRecursive(false);
                    visibleItems.Add(item);
                }

                TryExpandToSelectedItem();
                return;
            }

            var comparison = StringComparison.CurrentCultureIgnoreCase;

            foreach (var root in ItemsSource)
            {
                var clone = root.CloneBranch(node =>
                    node.FullPath?.IndexOf(searchText, comparison) >= 0 ||
                    node.DisplayName?.IndexOf(searchText, comparison) >= 0);

                if (clone == null)
                    continue;

                clone.SetExpandedRecursive(true);
                visibleItems.Add(clone);
            }
        }

        private void TryExpandToSelectedItem()
        {
            if (SelectedItem == null || string.IsNullOrWhiteSpace(SelectedItem.Id))
                return;

            if (!string.IsNullOrWhiteSpace(lastSearchText))
                return;

            var chain = SelectedItem;
            while (chain != null)
            {
                chain.IsExpanded = true;
                chain = chain.Parent;
            }
        }

        private void EnsureTemplateParts()
        {
            if (treeViewControl == null)
            {
                treeViewControl = ComboBoxControl.Template.FindName("PART_TreeView", ComboBoxControl) as TreeView;
                if (treeViewControl != null)
                {
                    treeViewControl.SelectedItemChanged += TreeViewControl_SelectedItemChanged;
                    treeViewControl.ItemsSource = VisibleItems;
                }
            }

            if (searchTextBox == null)
            {
                searchTextBox = ComboBoxControl.Template.FindName("PART_SearchTextBox", ComboBoxControl) as TextBox;
                if (searchTextBox != null)
                    searchTextBox.TextChanged += SearchTextBox_TextChanged;
            }
        }

        private void UpdateDisplaySelection()
        {
            // Display handled by template TextBlock bound to SelectedItem.FullPath.
        }

        private void LogSelectedItemChange(HierarchicalSelectionItem newValue)
        {
            var description = "<null>";
            if (newValue != null)
            {
                var fullPath = string.IsNullOrWhiteSpace(newValue.FullPath) ? newValue.DisplayName : newValue.FullPath;
                var id = string.IsNullOrWhiteSpace(newValue.Id) ? "<null>" : newValue.Id;
                description = $"{fullPath} (Id={id})";
            }

            LogEntry($"[CategoryPicker] DependencyProperty SelectedItem updated -> {description}");
        }

        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);

            if (!IsEnabled)
                return;

            if (!ComboBoxControl.IsDropDownOpen && (e.Key == Key.Enter || e.Key == Key.Down || e.Key == Key.Space))
            {
                ComboBoxControl.IsDropDownOpen = true;
                e.Handled = true;
                return;
            }

            if (ComboBoxControl.IsDropDownOpen && e.Key == Key.Escape)
            {
                ComboBoxControl.IsDropDownOpen = false;
                e.Handled = true;
            }
        }
    }
}
