using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CtrEditor.ObjetosSim;
using CtrEditor.Models;

namespace CtrEditor.PopUps
{
    /// <summary>
    /// Interaction logic for TagEditorWindow.xaml
    /// </summary>
    public partial class TagEditorWindow : Window
    {
        public TagEditorWindow(osBase objeto, IEnumerable<osBase> todosLosObjetos, Dictionary<string, ImageData> imageDataDictionary = null)
        {
            InitializeComponent();
            DataContext = new TagEditorViewModel(objeto, todosLosObjetos, this, imageDataDictionary);
        }

        private void TxtNuevaEtiqueta_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                if (DataContext is TagEditorViewModel viewModel)
                {
                    viewModel.AgregarEtiquetaCommand.Execute(null);
                }
            }
        }
    }

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

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

    public partial class TagEditorViewModel : ObservableObject
    {
        private readonly osBase _objeto;
        private readonly IEnumerable<osBase> _todosLosObjetos;
        private readonly Dictionary<string, ImageData> _imageDataDictionary;
        private readonly TagEditorWindow _window;
        private readonly List<string> _etiquetasOriginales;

        [ObservableProperty]
        private string nuevaEtiqueta = "";

        [ObservableProperty]
        private ObservableCollection<TagInfo> etiquetasObjeto = new();

        [ObservableProperty]
        private ObservableCollection<TagInfo> etiquetasDisponibles = new();

        public ICommand AgregarEtiquetaCommand { get; }
        public ICommand AgregarEtiquetaExistenteCommand { get; }
        public ICommand RemoverEtiquetaCommand { get; }
        public ICommand AplicarCommand { get; }
        public ICommand CancelarCommand { get; }

        public TagEditorViewModel(osBase objeto, IEnumerable<osBase> todosLosObjetos, TagEditorWindow window, Dictionary<string, ImageData> imageDataDictionary = null)
        {
            _objeto = objeto;
            _todosLosObjetos = todosLosObjetos;
            _imageDataDictionary = imageDataDictionary;
            _window = window;

            // Guardar las etiquetas originales para poder cancelar
            _etiquetasOriginales = objeto.ListaEtiquetas.ToList();

            // Inicializar comandos
            AgregarEtiquetaCommand = new RelayCommand(AgregarEtiqueta, () => !string.IsNullOrWhiteSpace(NuevaEtiqueta));
            AgregarEtiquetaExistenteCommand = new RelayCommand<string>(AgregarEtiquetaExistente);
            RemoverEtiquetaCommand = new RelayCommand<string>(RemoverEtiqueta);
            AplicarCommand = new RelayCommand(Aplicar);
            CancelarCommand = new RelayCommand(Cancelar);

            // Cargar datos iniciales
            CargarEtiquetasObjeto();
            CargarEtiquetasDisponibles();

            // Suscribirse al cambio de NuevaEtiqueta para actualizar el comando
            PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(NuevaEtiqueta))
                {
                    (AgregarEtiquetaCommand as IRelayCommand)?.NotifyCanExecuteChanged();
                }
            };
        }

        private void CargarEtiquetasObjeto()
        {
            EtiquetasObjeto.Clear();
            foreach (var tag in _objeto.ListaEtiquetas.OrderBy(t => t))
            {
                EtiquetasObjeto.Add(new TagInfo(tag));
            }
        }

        private void CargarEtiquetasDisponibles()
        {
            EtiquetasDisponibles.Clear();

            // Obtener todas las etiquetas únicas de todos los objetos
            var todasLasEtiquetas = _todosLosObjetos
                .SelectMany(obj => obj.ListaEtiquetas)
                .Distinct()
                .ToList();

            // Agregar etiquetas de las imágenes si está disponible el diccionario
            if (_imageDataDictionary != null)
            {
                var etiquetasImagenes = _imageDataDictionary.Values
                    .SelectMany(imageData => imageData.ListaEtiquetas)
                    .Distinct();

                todasLasEtiquetas.AddRange(etiquetasImagenes);
                todasLasEtiquetas = todasLasEtiquetas.Distinct().ToList();
            }

            // Ordenar todas las etiquetas
            todasLasEtiquetas = todasLasEtiquetas.OrderBy(tag => tag).ToList();

            // Mostrar solo las que no están en el objeto actual
            var etiquetasObjetoActual = _objeto.ListaEtiquetas;
            foreach (var tag in todasLasEtiquetas.Except(etiquetasObjetoActual))
            {
                EtiquetasDisponibles.Add(new TagInfo(tag));
            }
        }

        private void AgregarEtiqueta()
        {
            if (string.IsNullOrWhiteSpace(NuevaEtiqueta))
                return;

            // Limpiar la etiqueta (remover # si existe y convertir a minúsculas)
            string tagLimpia = NuevaEtiqueta.Trim();
            if (tagLimpia.StartsWith("#"))
                tagLimpia = tagLimpia.Substring(1);

            tagLimpia = tagLimpia.ToLowerInvariant();

            // Validar que no esté vacía después de limpiar
            if (string.IsNullOrWhiteSpace(tagLimpia))
                return;

            // Verificar que no existe ya
            if (_objeto.ListaEtiquetas.Contains(tagLimpia))
                return;

            // Agregar la etiqueta al objeto
            var etiquetasActuales = string.IsNullOrWhiteSpace(_objeto.Etiquetas) ?
                new List<string>() :
                _objeto.Etiquetas.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList();

            etiquetasActuales.Add("#" + tagLimpia);
            _objeto.Etiquetas = string.Join(" ", etiquetasActuales);

            // Actualizar las listas
            CargarEtiquetasObjeto();
            CargarEtiquetasDisponibles();

            // Limpiar el campo
            NuevaEtiqueta = "";
        }

        private void AgregarEtiquetaExistente(string tagName)
        {
            if (string.IsNullOrWhiteSpace(tagName) || _objeto.ListaEtiquetas.Contains(tagName))
                return;

            // Agregar la etiqueta al objeto
            var etiquetasActuales = string.IsNullOrWhiteSpace(_objeto.Etiquetas) ?
                new List<string>() :
                _objeto.Etiquetas.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList();

            etiquetasActuales.Add("#" + tagName);
            _objeto.Etiquetas = string.Join(" ", etiquetasActuales);

            // Actualizar las listas
            CargarEtiquetasObjeto();
            CargarEtiquetasDisponibles();
        }

        private void RemoverEtiqueta(string tagName)
        {
            if (string.IsNullOrWhiteSpace(tagName))
                return;

            // Remover la etiqueta del objeto
            var etiquetasActuales = _objeto.Etiquetas
                .Split(' ', StringSplitOptions.RemoveEmptyEntries)
                .Where(tag => !tag.Equals("#" + tagName, StringComparison.OrdinalIgnoreCase))
                .ToList();

            _objeto.Etiquetas = string.Join(" ", etiquetasActuales);

            // Actualizar las listas
            CargarEtiquetasObjeto();
            CargarEtiquetasDisponibles();
        }

        private void Aplicar()
        {
            _window.DialogResult = true;
            _window.Close();
        }

        private void Cancelar()
        {
            // Restaurar las etiquetas originales
            var etiquetasOriginalesString = _etiquetasOriginales.Any() ?
                string.Join(" ", _etiquetasOriginales.Select(tag => "#" + tag)) :
                "";
            _objeto.Etiquetas = etiquetasOriginalesString;

            _window.DialogResult = false;
            _window.Close();
        }
    }
}