using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Xceed.Wpf.Toolkit.Primitives;

namespace CtrEditor.ObjetosSim.UserControls
{
    /// <summary>
    /// Interaction logic for TreeListControlOS.xaml
    /// </summary>
    public partial class TreeListControlOS : UserControl
    {
        public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
            nameof(ItemsSource), typeof(ObservableCollection<osBase>), typeof(TreeListControlOS), new PropertyMetadata(null, OnItemsSourceChanged));

        public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
            nameof(SelectedItem), typeof(TreeItemViewModel), typeof(TreeListControlOS), new PropertyMetadata(null, OnSelectedItemChanged));


        public event EventHandler<SelectionChangedEventArgs> SelectionChanged;

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

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

        public ObservableCollection<TreeItemViewModel> Items { get; set; } = new ObservableCollection<TreeItemViewModel>();

        public TreeListControlOS()
        {
            InitializeComponent();
            DataContext = this;
        }

        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TreeListControlOS control)
            {
                control.LoadItems((ObservableCollection<osBase>)e.NewValue);
            }
        }

        private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TreeListControlOS control && e.NewValue is TreeItemViewModel newItem)
            {
                // Update the TreeView selection if necessary
                control.UpdateTreeViewSelection(newItem);
                control.OnSelectionChanged(new SelectionChangedEventArgs(newItem));
            }
        }

        private void UpdateTreeViewSelection(TreeItemViewModel selectedItem)
        {
            if (treeView != null && selectedItem != null)
            {
                TreeViewSelectedItemExBehavior.SetSelectedItemEx(treeView, selectedItem);
            }
        }


        public TreeItemViewModel FindViewModelForItem(osBase item)
        {
            foreach (var i in Items)
            {
                if (i.Item == item)
                    return i;
                foreach (var child in i.Children)
                    if (child.Item == item)
                        return child;
            }
            return null;
        }

        private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (e.NewValue is TreeItemViewModel selectedItem)
            {
                SelectedItem = selectedItem;
                OnSelectionChanged(new SelectionChangedEventArgs(selectedItem));
            }
        }

        private void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            SelectionChanged?.Invoke(this, e);
        }

        private void LoadItems(ObservableCollection<osBase> allItems)
        {
            Items.Clear();
            if (allItems == null) return;

            var rootItems = allItems.Where(i => !i.Cloned);
            foreach (var item in rootItems)
            {
                Items.Add(new TreeItemViewModel(item, allItems));
            }
        }
    }


    public partial class vmTreeListControlOS : ObservableObject
    {
        [ObservableProperty]
        private object selectedItemTreeViewSs = new object();

        [ObservableProperty]
        private ObservableCollection<object> selectedItemsTreeViewSs = new ObservableCollection<object>();

        [ObservableProperty]
        private ObservableCollection<TreeItemViewModel> itemsTreeViewSs = new ObservableCollection<TreeItemViewModel>();

    }


    public class TreeItemViewModel
    {
        public osBase Item { get; set; }
        public ObservableCollection<TreeItemViewModel> Children { get; set; } = new ObservableCollection<TreeItemViewModel>();

        public TreeItemViewModel(osBase item, ObservableCollection<osBase> allItems)
        {
            Item = item;
            LoadChildren(allItems);
        }

        private void LoadChildren(ObservableCollection<osBase> allItems)
        {
            foreach (var child in allItems.Where(i => i.Cloned && i.Cloned_from == Item.Id))
            {
                Children.Add(new TreeItemViewModel(child, allItems));
            }
        }
    }

    // Cambia la clase SelectionChangedEventArgs
    public class SelectionChangedEventArgs : EventArgs
    {
        public TreeItemViewModel SelectedItem { get; }

        public SelectionChangedEventArgs(TreeItemViewModel selectedItem)
        {
            SelectedItem = selectedItem;
        }
    }


    public static class TreeViewSelectedItemExBehavior
    {
        private static List<TreeView> isRegisteredToSelectionChanged = new List<TreeView>();

        public static readonly DependencyProperty SelectedItemExProperty =
            DependencyProperty.RegisterAttached("SelectedItemEx",
                typeof(object),
                typeof(TreeViewSelectedItemExBehavior),
                new FrameworkPropertyMetadata(new object(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemExChanged, null));

        #region SelectedItemEx

        public static object GetSelectedItemEx(TreeView target)
        {
            return target.GetValue(SelectedItemExProperty);
        }

        public static void SetSelectedItemEx(TreeView target, object value)
        {
            target.SetValue(SelectedItemExProperty, value);
            var treeViewItemToSelect = GetTreeViewItem(target, value);
            if (treeViewItemToSelect == null)
            {
                if (target.SelectedItem == null)
                    return;
                var treeViewItemToUnSelect = GetTreeViewItem(target, target.SelectedItem);
                treeViewItemToUnSelect.IsSelected = false;
            }
            else
                treeViewItemToSelect.IsSelected = true;
        }

        public static void OnSelectedItemExChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
            var treeView = depObj as TreeView;
            if (treeView == null)
                return;
            if (!isRegisteredToSelectionChanged.Contains(treeView))
            {
                treeView.SelectedItemChanged += TreeView_SelectedItemChanged;
                isRegisteredToSelectionChanged.Add(treeView);
            }
        }

        #endregion

        private static void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var treeView = (TreeView)sender;
            SetSelectedItemEx(treeView, e.NewValue);
        }

        #region Helper Structures & Methods

        public class MyVirtualizingStackPanel : VirtualizingStackPanel
        {
            /// <summary>
            /// Publically expose BringIndexIntoView.
            /// </summary>
            public void BringIntoView(int index)
            {
                BringIndexIntoView(index);
            }
        }

        /// <summary>Recursively search for an item in this subtree.</summary>
        /// <param name="container">The parent ItemsControl. This can be a TreeView or a TreeViewItem.</param>
        /// <param name="item">The item to search for.</param>
        /// <returns>The TreeViewItem that contains the specified item.</returns>
        private static TreeViewItem GetTreeViewItem(ItemsControl container, object item)
        {
            if (container != null)
            {
                if (container.DataContext == item)
                {
                    return container as TreeViewItem;
                }

                // Expand the current container
                if (container is TreeViewItem && !((TreeViewItem)container).IsExpanded)
                {
                    container.SetValue(TreeViewItem.IsExpandedProperty, true);
                }

                // Try to generate the ItemsPresenter and the ItemsPanel.
                // by calling ApplyTemplate.  Note that in the 
                // virtualizing case even if the item is marked 
                // expanded we still need to do this step in order to 
                // regenerate the visuals because they may have been virtualized away.

                container.ApplyTemplate();
                ItemsPresenter itemsPresenter =
                    (ItemsPresenter)container.Template.FindName("ItemsHost", container);
                if (itemsPresenter != null)
                {
                    itemsPresenter.ApplyTemplate();
                }
                else
                {
                    // The Tree template has not named the ItemsPresenter, 
                    // so walk the descendents and find the child.
                    itemsPresenter = FindVisualChild<ItemsPresenter>(container);
                    if (itemsPresenter == null)
                    {
                        container.UpdateLayout();

                        itemsPresenter = FindVisualChild<ItemsPresenter>(container);
                    }
                }

                Panel itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);


                // Ensure that the generator for this panel has been created.
                UIElementCollection children = itemsHostPanel.Children;

                MyVirtualizingStackPanel virtualizingPanel =
                    itemsHostPanel as MyVirtualizingStackPanel;

                for (int i = 0, count = container.Items.Count; i < count; i++)
                {
                    TreeViewItem subContainer;
                    if (virtualizingPanel != null)
                    {
                        // Bring the item into view so 
                        // that the container will be generated.
                        virtualizingPanel.BringIntoView(i);

                        subContainer =
                            (TreeViewItem)container.ItemContainerGenerator.
                            ContainerFromIndex(i);
                    }
                    else
                    {
                        subContainer =
                            (TreeViewItem)container.ItemContainerGenerator.
                            ContainerFromIndex(i);

                        // Bring the item into view to maintain the 
                        // same behavior as with a virtualizing panel.
                        subContainer.BringIntoView();
                    }

                    if (subContainer != null)
                    {
                        // Search the next level for the object.
                        TreeViewItem resultContainer = GetTreeViewItem(subContainer, item);
                        if (resultContainer != null)
                        {
                            return resultContainer;
                        }
                        else
                        {
                            // The object is not under this TreeViewItem
                            // so collapse it.
                            subContainer.IsExpanded = false;
                        }
                    }
                }
            }

            return null;
        }

        /// <summary>Search for an element of a certain type in the visual tree.</summary>
        /// <typeparam name="T">The type of element to find.</typeparam>
        /// <param name="visual">The parent element.</param>
        /// <returns></returns>
        private static T FindVisualChild<T>(Visual visual) where T : Visual
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
            {
                Visual child = (Visual)VisualTreeHelper.GetChild(visual, i);
                if (child != null)
                {
                    T correctlyTyped = child as T;
                    if (correctlyTyped != null)
                    {
                        return correctlyTyped;
                    }

                    T descendent = FindVisualChild<T>(child);
                    if (descendent != null)
                    {
                        return descendent;
                    }
                }
            }
            return null;
        }

        #endregion
    }

}
