using System.Collections.ObjectModel;
using System.ComponentModel;  // Add this for PropertyChangedEventHandler and PropertyChangedEventArgs
using System.Reflection;
using System.Text.Json.Serialization;
using System.Windows;
using System.Windows.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.ObjetosSim;

namespace CtrEditor.Controls
{
    public class FilterChangedEventArgs : EventArgs
    {
        public osVisFilterViewModel FilterViewModel { get; private set; }

        public FilterChangedEventArgs(osVisFilterViewModel viewModel)
        {
            FilterViewModel = viewModel;
        }
    }

    /// <summary>
    /// Interaction logic for osVisFilter.xaml
    /// </summary>
    public partial class osVisFilter : UserControl
    {
        public osVisFilter()
        {
            InitializeComponent();
            DataContext = FilterViewModel = new osVisFilterViewModel { Parent = this }; // Set the Parent property
        }

        public osVisFilterViewModel FilterViewModel { get; private set; }

        public event EventHandler<FilterChangedEventArgs> FilterChanged;

        public virtual void OnFilterChanged()  // Changed from protected to public
        {
            FilterChanged?.Invoke(this, new FilterChangedEventArgs(FilterViewModel));
        }

        /// <summary>
        /// Updates the type filters based on the provided types
        /// </summary>
        public void UpdateAvailableTypes(IEnumerable<Type> types)
        {
            FilterViewModel.UpdateTypeFilters(types);
        }

        /// <summary>
        /// Updates the tag filters based on the provided objects
        /// </summary>
        public void UpdateAvailableTags(IEnumerable<osBase> objects)
        {
            FilterViewModel.UpdateTagFilters(objects);
        }
    }

    /// <summary>
    /// ViewModel for the osVisFilter control
    /// </summary>
    public partial class osVisFilterViewModel : ObservableObject
    {
        [ObservableProperty]
        private bool showAll = true;

        [ObservableProperty]
        private bool showCloned;

        [ObservableProperty]
        private bool showAutoCreated;

        [ObservableProperty]
        private bool showEnableOnAllPages;

        [ObservableProperty]
        private bool showOnThisPage;

        [ObservableProperty]
        private ObservableCollection<TypeFilterItem> typeFilters = new ObservableCollection<TypeFilterItem>();

        [ObservableProperty]
        private ObservableCollection<TagFilterItem> tagFilters = new ObservableCollection<TagFilterItem>();

        [ObservableProperty]
        private string searchTags = "";

        partial void OnShowAllChanged(bool value)
        {
            NotifyFilterChanged();
        }

        partial void OnShowClonedChanged(bool value)
        {
            NotifyFilterChanged();
        }

        partial void OnShowAutoCreatedChanged(bool value)
        {
            NotifyFilterChanged();
        }

        partial void OnShowEnableOnAllPagesChanged(bool value)
        {
            NotifyFilterChanged();
        }

        partial void OnShowOnThisPageChanged(bool value)
        {
            NotifyFilterChanged();
        }

        partial void OnTypeFiltersChanged(ObservableCollection<TypeFilterItem> value)
        {
            if (value != null)
            {
                foreach (var filter in value)
                {
                    filter.PropertyChanged += (s, e) =>
                    {
                        if (e.PropertyName == nameof(TypeFilterItem.IsSelected))
                        {
                            NotifyFilterChanged();
                        }
                    };
                }
            }
        }

        partial void OnTagFiltersChanged(ObservableCollection<TagFilterItem> value)
        {
            if (value != null)
            {
                foreach (var filter in value)
                {
                    filter.PropertyChanged += (s, e) =>
                    {
                        if (e.PropertyName == nameof(TagFilterItem.IsSelected))
                        {
                            NotifyFilterChanged();
                        }
                    };
                }
            }
        }

        partial void OnSearchTagsChanged(string value)
        {
            NotifyFilterChanged();
        }

        private void NotifyFilterChanged()
        {
            if (this.Parent is osVisFilter filter)
            {
                filter.OnFilterChanged();
            }
        }

        [JsonIgnore]
        public osVisFilter Parent { get; set; }

        public osVisFilterViewModel()
        {
            // PropertyChanged listeners could be added here if needed
            if (this.Parent is osVisFilter filter)
            {
                filter.OnFilterChanged();
            }
        }

        /// <summary>
        /// Updates the type filters based on the provided types
        /// </summary>
        public void UpdateTypeFilters(IEnumerable<Type> types)
        {
            // Remove types that are no longer present
            var typesToRemove = TypeFilters
                .Where(tf => !types.Contains(tf.Type))
                .ToList();

            foreach (var item in typesToRemove)
            {
                UnsubscribeFromTypeFilter(item);
                TypeFilters.Remove(item);
            }

            // Add new types that aren't already in the list
            foreach (var type in types)
            {
                if (!TypeFilters.Any(tf => tf.Type == type))
                {
                    var newFilter = new TypeFilterItem(type)
                    {
                        DisplayName = GetTypeDisplayName(type),
                        IsSelected = true
                    };
                    SubscribeToTypeFilter(newFilter);
                    TypeFilters.Add(newFilter);
                }
            }
        }

        /// <summary>
        /// Updates the tag filters based on the provided objects
        /// </summary>
        public void UpdateTagFilters(IEnumerable<osBase> objects)
        {
            // Get all unique tags from all objects
            var allTags = objects
                .SelectMany(obj => obj.ListaEtiquetas)
                .Distinct()
                .OrderBy(tag => tag)
                .ToList();

            // Remove tags that are no longer present
            var tagsToRemove = TagFilters
                .Where(tf => !allTags.Contains(tf.TagName))
                .ToList();

            foreach (var item in tagsToRemove)
            {
                UnsubscribeFromTagFilter(item);
                TagFilters.Remove(item);
            }

            // Add new tags that aren't already in the list
            foreach (var tag in allTags)
            {
                if (!TagFilters.Any(tf => tf.TagName == tag))
                {
                    var newFilter = new TagFilterItem(tag)
                    {
                        IsSelected = true
                    };
                    SubscribeToTagFilter(newFilter);
                    TagFilters.Add(newFilter);
                }
            }
        }

        private void SubscribeToTypeFilter(TypeFilterItem filter)
        {
            filter.PropertyChanged += TypeFilter_PropertyChanged;
        }

        private void UnsubscribeFromTypeFilter(TypeFilterItem filter)
        {
            filter.PropertyChanged -= TypeFilter_PropertyChanged;
        }

        private void SubscribeToTagFilter(TagFilterItem filter)
        {
            filter.PropertyChanged += TagFilter_PropertyChanged;
        }

        private void UnsubscribeFromTagFilter(TagFilterItem filter)
        {
            filter.PropertyChanged -= TagFilter_PropertyChanged;
        }

        private void TypeFilter_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(TypeFilterItem.IsSelected))
            {
                NotifyFilterChanged();
            }
        }

        private void TagFilter_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(TagFilterItem.IsSelected))
            {
                NotifyFilterChanged();
            }
        }

        /// <summary>
        /// Gets the display name for a type, using the NombreClase static method if available
        /// </summary>
        private string GetTypeDisplayName(Type type)
        {
            var methodInfo = type.GetMethod("NombreClase",
                BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
            return methodInfo != null ?
                methodInfo.Invoke(null, null)?.ToString() :
                type.Name;
        }
    }

    /// <summary>
    /// Represents a type filter item with selection state
    /// </summary>
    public partial class TypeFilterItem : ObservableObject
    {
        [ObservableProperty]
        private bool isSelected = true;

        [ObservableProperty]
        private string displayName;

        public Type Type { get; }

        public TypeFilterItem(Type type)
        {
            Type = type;
            DisplayName = type?.Name ?? "Unknown Type";
        }

        partial void OnIsSelectedChanged(bool value)
        {
            OnPropertyChanged(nameof(IsSelected));
        }
    }

    /// <summary>
    /// Represents a tag filter item with selection state
    /// </summary>
    public partial class TagFilterItem : ObservableObject
    {
        [ObservableProperty]
        private bool isSelected;

        public string TagName { get; }
        public string DisplayName => "#" + TagName;

        public TagFilterItem(string tagName)
        {
            TagName = tagName;
        }

        partial void OnIsSelectedChanged(bool value)
        {
            // Could add logic here if needed when selection changes
        }
    }
}