using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CtrEditor.ObjetosSim;
using CtrEditor.ObjetosSim.Extraccion_Datos;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Threading;  // Add this line
using System.Linq;
using ClosedXML.Excel;
using System.Diagnostics;

namespace CtrEditor.PopUps
{
    public class MatrixItem : ObservableObject
    {
        public string TagName { get; set; }
        private string columnName;
        public string ColumnName
        {
            get => columnName;
            set => SetProperty(ref columnName, value);
        }
        private int columnNumber;
        public int ColumnNumber
        {
            get => columnNumber;
            set => SetProperty(ref columnNumber, value);
        }
        public string Value { get; set; }
        public string Type { get; set; }
        public bool IsCloned { get; set; }
        public UniqueId Id { get; set; }
        public string Source_Image { get; set; }
        public int Copy_Number { get; set; }  // Add this property
    }

    public partial class MatrixPreviewViewModel : ObservableObject
    {
        private Window _window;
        private MainViewModel _mainViewModel;
        private DataGrid _dataGrid;
        private readonly Services.LLMService _llmService;

        public MatrixPreviewViewModel()
        {
            _llmService = new Services.LLMService();
        }

        [ObservableProperty]
        private ObservableCollection<MatrixItem> matrixItems;

        [ObservableProperty]
        private ObservableCollection<Dictionary<string, string>> matrixRows;

        [ObservableProperty]
        private GridLength detailsHeight = new GridLength(150);

        [ObservableProperty]
        private double detailsHeightValue = 150;

        private ObservableCollection<string> selectedImages;

        partial void OnDetailsHeightValueChanged(double value)
        {
            DetailsHeight = new GridLength(value);
        }

        public void Initialize(MainViewModel mainViewModel, Window window, ObservableCollection<string> images = null)
        {
            _mainViewModel = mainViewModel;
            _window = window;
            _dataGrid = (_window as MatrixPreviewWindow)?.MatrixPreview;
            selectedImages = images ?? new ObservableCollection<string> { mainViewModel.SelectedImage };
            
            MatrixItems = new ObservableCollection<MatrixItem>();
            MatrixRows = new ObservableCollection<Dictionary<string, string>>();
            
            AnalyzeMatrixMultiPage();
        }

        private void UpdateMatrixPreview()
        {
            if (_dataGrid == null) return;
            if (MatrixRows == null) MatrixRows = new ObservableCollection<Dictionary<string, string>>();

            MatrixRows.Clear();
            _dataGrid.Columns.Clear();

            if (!MatrixItems.Any())
            {
                Debug.WriteLine("No matrix items found.");
                return;
            }

            Debug.WriteLine($"Total matrix items: {MatrixItems.Count}");

            // Add Image column first
            var imageColumn = new DataGridTextColumn
            {
                Header = "Image",
                Binding = new Binding("[Image]"),
                Width = DataGridLength.Auto
            };
            _dataGrid.Columns.Add(imageColumn);

            // Group items by source image and then by column number
            var itemsByImage = MatrixItems.GroupBy(x => x.Source_Image).ToList();
            Debug.WriteLine($"Images in matrix: {itemsByImage.Count}");

            // Sort items by column number
            var orderedItems = MatrixItems
                .GroupBy(x => x.ColumnNumber)
                .OrderBy(g => g.Key)
                .Select(g => g.First())
                .ToList();

            Debug.WriteLine($"Distinct columns: {orderedItems.Count}");

            // Create data grid columns
            foreach (var item in orderedItems)
            {
                if (item.ColumnNumber <= 0) continue; // Skip invalid column numbers

                var column = new DataGridTextColumn
                {
                    Header = $"{item.ColumnNumber}:{item.ColumnName}",
                    Binding = new Binding($"[{item.ColumnNumber}]"),
                    Width = DataGridLength.Auto
                };
                _dataGrid.Columns.Add(column);
            }

            // Process each image's data
            foreach (var imageGroup in itemsByImage)
            {
                Debug.WriteLine($"Processing image: {imageGroup.Key} with {imageGroup.Count()} items");

                // Calculate max rows needed for this image
                int maxRows = 1;
                var clonedItems = imageGroup.Where(x => x.IsCloned).ToList();
                if (clonedItems.Any())
                {
                    maxRows = clonedItems.Max(x => x.Copy_Number) + 1;
                    Debug.WriteLine($"Found cloned items, max rows: {maxRows}");
                }

                // Create rows for this image
                for (int row = 0; row < maxRows; row++)
                {
                    var rowData = new Dictionary<string, string>();

                    // Add image identifier
                    rowData["Image"] = imageGroup.Key;

                    // Add fixed (non-cloned) values in all rows
                    foreach (var item in imageGroup.Where(x => !x.IsCloned))
                    {
                        if (item.ColumnNumber > 0)
                        {
                            rowData[item.ColumnNumber.ToString()] = item.Value ?? string.Empty;
                        }
                    }

                    // Add cloned values only in their corresponding row
                    foreach (var item in imageGroup.Where(x => x.IsCloned))
                    {
                        if (item.ColumnNumber > 0 && item.Copy_Number == row)
                        {
                            rowData[item.ColumnNumber.ToString()] = item.Value ?? string.Empty;
                        }
                    }

                    MatrixRows.Add(rowData);
                }
            }

            Debug.WriteLine($"Total matrix rows created: {MatrixRows.Count}");
        }

        private void UpdateColumnHeaders()
        {
            if (_dataGrid == null) return;
            
            foreach (var col in _dataGrid.Columns.Cast<DataGridColumn>())
            {
                if (col is DataGridTextColumn textCol)
                {
                    var item = MatrixItems.FirstOrDefault(x => x.ColumnName == (textCol.Header?.ToString() ?? "").Split(':').Last());
                    if (item != null)
                    {
                        textCol.Header = $"{item.ColumnNumber}:{item.ColumnName}";
                    }
                }
            }
        }

        private async void AnalyzeMatrixMultiPage()
        {
            MatrixItems.Clear();
            bool originalHasUnsavedChanges = _mainViewModel.HasUnsavedChanges;
            _mainViewModel.HasUnsavedChanges = false;

            try
            {
                foreach (var imageName in selectedImages)
                {
                    // Store current image
                    var currentImage = _mainViewModel.SelectedImage;

                    // Change to target image and wait for UI update
                    _mainViewModel.SelectedImage = imageName;
                    await _mainViewModel.WaitForUIUpdateAsync();

                    // Analyze current page
                    var items = AnalyzePage();
                    if (items.Count == 0)
                    {
                        Debug.WriteLine($"Warning: No items found for image {imageName}");
                    }
                    else
                    {
                        Debug.WriteLine($"Found {items.Count} items for image {imageName}");
                    }

                    foreach (var item in items)
                    {
                        item.Source_Image = imageName;
                        MatrixItems.Add(item);
                    }

                    // Restore original image if needed
                    if (currentImage != imageName)
                    {
                        _mainViewModel.SelectedImage = currentImage;
                        await _mainViewModel.WaitForUIUpdateAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error in AnalyzeMatrixMultiPage: {ex.Message}");
                MessageBox.Show($"Error analyzing matrix: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                _mainViewModel.HasUnsavedChanges = originalHasUnsavedChanges;
            }

            Debug.WriteLine($"Total items collected: {MatrixItems.Count}");
            ResolveColumnConflicts();
            UpdateMatrixPreview();
        }

        /// <summary>
        /// Analyzes the current page and collects all extraction tags data for matrix preview.
        /// </summary>
        /// <remarks>
        /// The method processes three types of extraction tags:
        /// 1. Fixed Tags: Tags without Search Templates association
        /// 2. Grouped Tags: Tags linked to Search Templates but not cloned
        /// 3. Cloned Tags: Tags created by Search Templates pattern matching
        ///
        /// Workflow:
        /// 1. Filters objects by visibility on current page
        /// 2. Groups tags by their type (fixed, grouped, cloned)
        /// 3. Performs OCR extraction on each tag
        /// 4. Creates MatrixItems with extracted data
        ///
        /// Data Organization:
        /// - Fixed tags maintain their original position and values
        /// - Grouped tags are associated with their Search Templates
        /// - Cloned tags inherit Copy_Number from their creation order in pattern matching
        ///
        /// Related Classes:
        /// - osExtraccionTag: Contains OCR extraction logic and tag properties
        /// - osBuscarCoincidencias: Handles pattern matching and tag cloning
        /// </remarks>
        /// <returns>A list of MatrixItems containing all processed tag data for the current page</returns>
        private List<MatrixItem> AnalyzePage()
        {
            var items = new List<MatrixItem>();

            // Filter visible objects by type
            var osBuscarCoincidencias_List = _mainViewModel.ObjetosSimulables
                .OfType<osBuscarCoincidencias>()
                .Where(tag => tag.Show_On_This_Page)
                .ToList();

            // Get base tags that are linked to Search Templates
            var osExtraccionTagBaseGrouped_List = _mainViewModel.ObjetosSimulables
                .OfType<osExtraccionTag>()
                .Where(tag => tag.Show_On_This_Page &&
                              !tag.Cloned &&
                              !string.IsNullOrEmpty(tag.Id_Search_Templates))
                .ToList();

            // Get fixed tags (not linked to Search Templates)
            var osExtraccionTagBaseFix_List = _mainViewModel.ObjetosSimulables
                .OfType<osExtraccionTag>()
                .Where(tag => tag.Show_On_This_Page &&
                              !tag.Cloned &&
                              string.IsNullOrEmpty(tag.Id_Search_Templates))
                .ToList();

            // Get cloned tags (created by Search Templates)
            var osExtraccionTagCloned_List = _mainViewModel.ObjetosSimulables
                .OfType<osExtraccionTag>()
                .Where(tag => tag.Show_On_This_Page && tag.Cloned)
                .ToList();

            // Log counts for debugging
            Debug.WriteLine($"Fixed tags: {osExtraccionTagBaseFix_List.Count}");
            Debug.WriteLine($"Grouped tags: {osExtraccionTagBaseGrouped_List.Count}");
            Debug.WriteLine($"Cloned tags: {osExtraccionTagCloned_List.Count}");

            // Process fixed tags
            foreach (var tag in osExtraccionTagBaseFix_List)
            {
                tag.CaptureImageAreaAndDoOCR();
                items.Add(new MatrixItem
                {
                    TagName = tag.Nombre,
                    ColumnName = tag.Collumn_name,
                    ColumnNumber = tag.Collumn_number,
                    Value = tag.Tag_extract,
                    Type = "Fixed",
                    IsCloned = false,
                    Id = tag.Id,
                    Source_Image = _mainViewModel.SelectedImage,
                    Copy_Number = 0
                });
            }

            // Process grouped tags
            foreach (var tag in osExtraccionTagBaseGrouped_List)
            {
                tag.CaptureImageAreaAndDoOCR();
                items.Add(new MatrixItem
                {
                    TagName = tag.Nombre,
                    ColumnName = tag.Collumn_name,
                    ColumnNumber = tag.Collumn_number,
                    Value = tag.Tag_extract,
                    Type = $"Grouped ({tag.Id_Search_Templates})",
                    IsCloned = false,
                    Id = tag.Id,
                    Source_Image = _mainViewModel.SelectedImage,
                    Copy_Number = 0
                });
            }

            // Process cloned tags
            foreach (var tag in osExtraccionTagCloned_List)
            {
                tag.CaptureImageAreaAndDoOCR();
                items.Add(new MatrixItem
                {
                    TagName = tag.Nombre,
                    ColumnName = tag.Collumn_name,
                    ColumnNumber = tag.Collumn_number,
                    Value = tag.Tag_extract,
                    Type = "Cloned",
                    IsCloned = true,
                    Id = tag.Id,
                    Source_Image = _mainViewModel.SelectedImage,
                    Copy_Number = tag.Copy_Number
                });
            }

            return items;
        }

        partial void OnMatrixItemsChanged(ObservableCollection<MatrixItem> value)
        {
            if (value != null)
            {
                foreach (var item in value)
                {
                    item.PropertyChanged += (s, e) =>
                    {
                        if (e.PropertyName == nameof(MatrixItem.ColumnNumber) || 
                            e.PropertyName == nameof(MatrixItem.ColumnName))
                        {
                            UpdateColumnHeaders();
                        }
                    };
                }
            }
            UpdateMatrixPreview();
        }

        [RelayCommand]
        private async void ApplyChanges()
        {
            // Resolver solo los conflictos reales, mantener el orden existente
            var conflicts = MatrixItems
                .GroupBy(x => x.ColumnNumber)
                .Where(g => g.Select(x => x.ColumnName).Distinct().Count() > 1)
                .Any();

            if (conflicts)
            {
                ResolveColumnConflicts();
            }

            // Validar números de columna
            var columnNumbers = MatrixItems.Select(x => x.ColumnNumber).OrderBy(x => x).ToList();
            for (int i = 0; i < columnNumbers.Count; i++)
            {
                if (columnNumbers[i] <= 0)
                {
                    MessageBox.Show("Column numbers must be greater than 0", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
            }

            bool originalHasUnsavedChanges = _mainViewModel.HasUnsavedChanges;
            _mainViewModel.HasUnsavedChanges = false;

            try
            {
                foreach (var imageName in selectedImages)
                {
                    // Store current image
                    var currentImage = _mainViewModel.SelectedImage;
                    
                    // Change to target image and wait for UI update
                    _mainViewModel.SelectedImage = imageName;
                    await Task.Yield();
                    Application.Current.Dispatcher.Invoke(() => { }, DispatcherPriority.ApplicationIdle);

                    // Apply changes for current page
                    var pageItems = MatrixItems.Where(x => x.Source_Image == imageName);
                    foreach (var item in pageItems)
                    {
                        // Find the tag by Id instead of direct reference
                        var tag = _mainViewModel.ObjetosSimulables
                            .OfType<osExtraccionTag>()
                            .FirstOrDefault(t => t.Id == item.Id);

                        if (tag != null)
                        {
                            tag.Collumn_name = item.ColumnName;
                            tag.Collumn_number = item.ColumnNumber;
                        }
                    }

                    // Restore original image if needed
                    if (currentImage != imageName)
                    {
                        _mainViewModel.SelectedImage = currentImage;
                        await Task.Yield();
                        Application.Current.Dispatcher.Invoke(() => { }, DispatcherPriority.ApplicationIdle);
                    }
                    
                    _mainViewModel.SaveStateObjetosSimulables();
                }
            }
            finally
            {
                _mainViewModel.HasUnsavedChanges = originalHasUnsavedChanges;
            }

            _window.Close();
        }

        [RelayCommand]
        private void Close()
        {
            _window.Close();
        }

        [RelayCommand]
        private void RegenerateMatrix()
        {
            ResolveColumnConflicts();
            UpdateMatrixPreview();
        }

        private void ResolveColumnConflicts()
        {
            // Paso 1: Mantener el orden actual y resolver solo los conflictos reales
            var columnGroups = MatrixItems
                .GroupBy(x => x.ColumnNumber)
                .Where(g => g.Select(x => x.ColumnName).Distinct().Count() > 1)
                .ToList();

            foreach (var group in columnGroups)
            {
                var nameGroups = group
                    .GroupBy(x => x.ColumnName)
                    .OrderByDescending(g => g.Count())
                    .ToList();

                // El grupo más grande mantiene su número
                var largestGroup = nameGroups.First();

                // Solo reasignar números para grupos que tengan conflicto
                for (int i = 1; i < nameGroups.Count; i++)
                {
                    var newColumnNumber = GetNextAvailableColumnNumber();
                    foreach (var item in nameGroups[i])
                    {
                        item.ColumnNumber = newColumnNumber;
                    }
                }
            }

            // Paso 2: Asegurarse de que los números son consecutivos sin alterar el orden relativo
            var orderedItems = MatrixItems
                .OrderBy(x => x.ColumnNumber)
                .GroupBy(x => x.ColumnName)
                .ToList();

            int currentNumber = 1;
            foreach (var group in orderedItems)
            {
                foreach (var item in group)
                {
                    item.ColumnNumber = currentNumber;
                }
                currentNumber++;
            }
        }

        private int GetNextAvailableColumnNumber()
        {
            var usedNumbers = MatrixItems.Select(x => x.ColumnNumber).Distinct().OrderBy(x => x).ToList();
            int nextNumber = 1;

            foreach (var number in usedNumbers)
            {
                if (number > nextNumber)
                    return nextNumber;
                nextNumber = number + 1;
            }

            return nextNumber;
        }

        [RelayCommand]
        private void ExportToExcel()
        {
            var saveDialog = new Microsoft.Win32.SaveFileDialog
            {
                DefaultExt = ".xlsx",
                Filter = "Excel files (*.xlsx)|*.xlsx",
                InitialDirectory = EstadoPersistente.Instance.directorio,
                FileName = "MatrixExport.xlsx"
            };

            if (saveDialog.ShowDialog() == true)
            {
                try
                {
                    using (var workbook = new XLWorkbook())
                    {
                        var worksheet = workbook.Worksheets.Add("Matrix");

                        // Write headers
                        int colIndex = 1;
                        worksheet.Cell(1, colIndex++).Value = "Image";
                        
                        var columns = MatrixItems
                            .GroupBy(x => x.ColumnNumber)
                            .OrderBy(g => g.Key)
                            .Select(g => g.First())
                            .ToList();

                        foreach (var col in columns)
                        {
                            worksheet.Cell(1, colIndex++).Value = col.ColumnName;
                        }

                        // Write data
                        int rowIndex = 2;
                        foreach (var row in MatrixRows)
                        {
                            colIndex = 1;
                            worksheet.Cell(rowIndex, colIndex++).Value = row["Image"];

                            foreach (var col in columns)
                            {
                                var value = row.ContainsKey(col.ColumnNumber.ToString()) 
                                    ? row[col.ColumnNumber.ToString()] 
                                    : string.Empty;
                                worksheet.Cell(rowIndex, colIndex++).Value = value;
                            }
                            rowIndex++;
                        }

                        // Format headers
                        var headerRow = worksheet.Row(1);
                        headerRow.Style.Font.Bold = true;
                        headerRow.Style.Fill.BackgroundColor = XLColor.LightGray;
                        headerRow.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;

                        // Auto-fit columns
                        worksheet.Columns().AdjustToContents();

                        workbook.SaveAs(saveDialog.FileName);
                    }

                    MessageBox.Show("Export completed successfully", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"Error exporting to Excel: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        [RelayCommand]
        private async Task AICorrectMatrix()
        {
            try
            {
                if (_llmService == null)
                {
                    MessageBox.Show("LLM Service not initialized", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                var columnNames = MatrixItems
                    .Select(x => x.ColumnName)
                    .Distinct()
                    .ToList();

                var dialog = new ColumnSelectionDialog(columnNames);
                if (dialog.ShowDialog() != true) return;

                var sourceColumn = dialog.SelectedSourceColumn;
                var targetColumn = dialog.SelectedTargetColumn;
                var sourceLanguage = dialog.SelectedSourceLanguage;
                var targetLanguage = dialog.SelectedTargetLanguage;

                // Group items by image and process each row
                var itemsByImage = MatrixItems.GroupBy(x => x.Source_Image);
                int batchSize = 10;
                int processedCount = 0;

                foreach (var imageGroup in itemsByImage)
                {
                    var textPairs = new List<(string Source, string Target)>();
                    var itemsToUpdate = new List<(MatrixItem SourceItem, MatrixItem TargetItem)>();
                    
                    // Create pairs for each row
                    var sourceItems = imageGroup
                        .Where(x => x.ColumnName == sourceColumn)
                        .OrderBy(x => x.Copy_Number);
                    
                    var targetItems = imageGroup
                        .Where(x => x.ColumnName == targetColumn)
                        .OrderBy(x => x.Copy_Number);

                    foreach (var (source, target) in sourceItems.Zip(targetItems, (s, t) => (s, t)))
                    {
                        if (!string.IsNullOrWhiteSpace(source.Value) && !string.IsNullOrWhiteSpace(target.Value))
                        {
                            textPairs.Add((source.Value, target.Value));
                            itemsToUpdate.Add((source, target));
                        }
                    }

                    // Process in batches
                    for (int i = 0; i < textPairs.Count; i += batchSize)
                    {
                        var batchPairs = textPairs.Skip(i).Take(batchSize).ToList();
                        var batchItems = itemsToUpdate.Skip(i).Take(batchSize).ToList();

                        var correctedPairs = await _llmService.ProcessTextBatch(batchPairs, sourceLanguage, targetLanguage);

                        // Update values
                        for (int j = 0; j < correctedPairs.Count; j++)
                        {
                            batchItems[j].SourceItem.Value = correctedPairs[j].Source;
                            batchItems[j].TargetItem.Value = correctedPairs[j].Target;
                            processedCount += 2;
                        }
                    }
                }

                UpdateMatrixPreview();
                MessageBox.Show($"AI Correction completed. Processed {processedCount} items.", 
                    "Success", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error during AI correction: {ex.Message}", 
                    "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        ~MatrixPreviewViewModel()
        {
            _llmService?.Dispose();
        }
    }
}
