using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Diagnostics;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
using Xceed.Wpf.Toolkit.PropertyGrid;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using UserControl = System.Windows.Controls.UserControl;

namespace CtrEditor
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // Para el Canvas
        private Point _lastMousePosition;
        private bool _isDrawingCanvas = false;
        private bool _isDraggingCanvas = false;
        private Image imagenDeFondo;
        internal ObjectManipulationManager _objectManager;

        // Temporizadores y animación
        private DispatcherTimer _zoomTimer;
        private double _targetZoomFactor;
        private double _initialZoomFactor;
        private double _currentZoomStep;
        private Point _zoomCursorPosition;
        private const int ZoomDuration = 500; // Duración del zoom en milisegundos
        private int _ZoomDuration;
        private const double MinZoomScale = 0.1; // Límite mínimo de zoom
        private Stopwatch _stopwatch;

        private dataDebug dataDebug = new dataDebug();

        public MainWindow()
        {
            InitializeComponent();

            _objectManager = new ObjectManipulationManager(this, ImagenEnTrabajoCanvas);

            // Inicializar temporizador de zoom
            _zoomTimer = new DispatcherTimer();
            _zoomTimer.Interval = TimeSpan.FromMilliseconds(1);
            _zoomTimer.Tick += ZoomTimer_Tick;
            _stopwatch = new Stopwatch();

            // Suscribir eventos
            this.Loaded += MainWindow_Loaded;
            ImagenEnTrabajoScrollViewer.PreviewMouseWheel += ImagenEnTrabajoCanvas_MouseWheel;
            ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown_Panning;
            ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove_Panning;
            ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning;
            this.KeyDown += MainWindow_KeyDown;
            ImagenEnTrabajoCanvas.MouseEnter += Canvas_MouseEnter;
            this.Closed += MainWindow_Closed;

            // Importante: Agregar el evento para el menú contextual
            ImagenEnTrabajoCanvas.MouseRightButtonDown += Canvas_MouseRightButtonDown;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            if (DataContext is MainViewModel viewModel)
            {
                viewModel.MainWindow = this;
                viewModel.ImageSelected += ViewModel_ImageSelected;
                viewModel?.LoadInitialData();
                viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas;
                viewModel.MainCanvas = ImagenEnTrabajoCanvas;
            }
        }

        public void SuscribirEventos(UserControl userControl)
        {
            _objectManager.SuscribirEventos(userControl);
        }

        public void AgregarRegistrarUserControlCanvas(UserControl userControl)
        {
            if (userControl is IDataContainer dataContainer)
            {
                SuscribirEventos(userControl);
                Canvas.SetZIndex(userControl, ((int)dataContainer.ZIndex_Base() + dataContainer.zIndex_fromFrames));
                ImagenEnTrabajoCanvas.Children.Add(userControl);
            }
        }

        public void EliminarUserControlDelCanvas(UserControl userControl)
        {
            if (ImagenEnTrabajoCanvas.Children.Contains(userControl))
            {
                ImagenEnTrabajoCanvas.Children.Remove(userControl);
            }
        }

        private void LoadImageToCanvas(string imagePath)
        {
            BitmapImage bitmap = new BitmapImage(new Uri(imagePath, UriKind.Absolute));

            if (imagenDeFondo == null)
            {
                imagenDeFondo = new Image();
                ImagenEnTrabajoCanvas.Children.Add(imagenDeFondo);
            }
            imagenDeFondo.Source = bitmap;
            RenderOptions.SetBitmapScalingMode(imagenDeFondo, BitmapScalingMode.HighQuality);

            // Elimina solo los ROIs, no la imagen de fondo
            for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--)
            {
                if (ImagenEnTrabajoCanvas.Children[i] is not Image)
                {
                    ImagenEnTrabajoCanvas.Children.RemoveAt(i);
                }
            }

            ImagenEnTrabajoCanvas.Width = bitmap.Width;
            ImagenEnTrabajoCanvas.Height = bitmap.Height;

            Canvas.SetLeft(imagenDeFondo, 0);
            Canvas.SetTop(imagenDeFondo, 0);
        }

        private void Canvas_MouseUp_Panning(object sender, MouseButtonEventArgs e)
        {
            if (_isDraggingCanvas)
            {
                _isDraggingCanvas = false;
                ImagenEnTrabajoCanvas.ReleaseMouseCapture();

                if (DataContext is MainViewModel viewModel && viewModel.SelectedItemOsList != null)
                {
                    _objectManager.MakeResizeRectanglesNormal();
                }
                e.Handled = true;
            }
        }

        private void Canvas_MouseDown_Panning(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas)
            {
                // Solo activar el panning si el clic fue directamente en el canvas
                if (e.Source == ImagenEnTrabajoCanvas)
                {
                    _isDraggingCanvas = true;
                    _lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
                    ImagenEnTrabajoCanvas.CaptureMouse();

                    if (DataContext is MainViewModel viewModel)
                    {
                        viewModel.SelectedItemOsList = null;
                        _objectManager.RemoveResizeRectangles();
                    }
                    e.Handled = true;
                }
            }
        }

        private void Canvas_MouseMove_Panning(object sender, MouseEventArgs e)
        {
            if (_isDraggingCanvas && e.LeftButton == MouseButtonState.Pressed)
            {
                var currentPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
                var dx = currentPosition.X - _lastMousePosition.X;
                var dy = currentPosition.Y - _lastMousePosition.Y;

                _objectManager.MakeResizeRectanglesTransparent();
                _objectManager.RemoveHighlightRectangles();

                var transform = (TranslateTransform)((TransformGroup)ImagenEnTrabajoCanvas.RenderTransform)
                    .Children.First(t => t is TranslateTransform);
                transform.X += dx;
                transform.Y += dy;

                _lastMousePosition = currentPosition;
                e.Handled = true;
            }
        }

        private void ImagenEnTrabajoCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            _objectManager.MakeResizeRectanglesTransparent();
            _objectManager.RemoveHighlightRectangles();

            _initialZoomFactor = ((ScaleTransform)((TransformGroup)ImagenEnTrabajoCanvas.RenderTransform)
                .Children.First(t => t is ScaleTransform)).ScaleX;

            double minZoomFactor = Math.Min(
                ImagenEnTrabajoScrollViewer.ViewportWidth / ImagenEnTrabajoCanvas.ActualWidth,
                ImagenEnTrabajoScrollViewer.ViewportHeight / ImagenEnTrabajoCanvas.ActualHeight);

            _targetZoomFactor = e.Delta > 0 ?
                _initialZoomFactor * 1.4 :
                Math.Max(_initialZoomFactor * 0.75, minZoomFactor);

            _zoomCursorPosition = e.GetPosition(ImagenEnTrabajoCanvas);

            RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.LowQuality);

            _ZoomDuration = !_zoomTimer.IsEnabled ? ZoomDuration : ZoomDuration / 3;

            _stopwatch.Restart();
            _zoomTimer.Start();

            e.Handled = true;
        }

        private void ZoomTimer_Tick(object sender, EventArgs e)
        {
            double elapsedMilliseconds = _stopwatch.Elapsed.TotalMilliseconds;

            if (elapsedMilliseconds >= _ZoomDuration)
            {
                _zoomTimer.Stop();
                _stopwatch.Stop();

                RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.HighQuality);

                if (DataContext is MainViewModel viewModel && viewModel.SelectedItemOsList != null)
                {
                    _objectManager.MakeResizeRectanglesNormal();
                }

                return;
            }

            var tg = (TransformGroup)ImagenEnTrabajoCanvas.RenderTransform;
            var st = (ScaleTransform)tg.Children.First(t => t is ScaleTransform);
            var tt = (TranslateTransform)tg.Children.First(t => t is TranslateTransform);

            double t = elapsedMilliseconds / _ZoomDuration;
            double easeOutT = t * (2 - t);
            double zoomFactor = _initialZoomFactor + (_targetZoomFactor - _initialZoomFactor) * easeOutT;

            zoomFactor = Math.Max(zoomFactor, MinZoomScale);

            Point cursorPosition = _zoomCursorPosition;

            var relativeX = cursorPosition.X * st.ScaleX + tt.X;
            var relativeY = cursorPosition.Y * st.ScaleY + tt.Y;

            st.ScaleX = zoomFactor;
            st.ScaleY = zoomFactor;

            tt.X = relativeX - cursorPosition.X * st.ScaleX;
            tt.Y = relativeY - cursorPosition.Y * st.ScaleY;
        }

        private void ListaOs_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            UserControlFactory.LimpiarPropiedadesosDatos(PanelEdicion);

            if (e.AddedItems.Count > 0 && e.AddedItems[0] is osBase selectedObject)
            {
                // Siempre trabajar con selección única para las propiedades
                CargarPropiedadesosDatos(selectedObject);

                // No modificar la selección múltiple aquí, solo actualizar los rectángulos de manipulación
                // si el objeto seleccionado no está en la selección actual
                if (!_objectManager.SelectedObjects.Contains(selectedObject))
                {
                    if (!((MainViewModel)DataContext).IsMultiSelectionActive)
                    {
                        _objectManager.ClearSelection();
                        _objectManager.SelectObject(selectedObject);
                    }
                }
            }
            else
            {
                _objectManager.RemoveResizeRectangles();
            }
        }

        private void MainWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (DataContext is MainViewModel viewModel)
            {
                if (e.Key == Key.Delete)
                {
                    viewModel.EliminarObjetoSeleccionado();
                    e.Handled = true;
                }
                else if (e.Key == Key.Escape)
                {
                    // Limpiar la selección en el ListBox
                    viewModel.SelectedItemOsList = null;
                    
                    // Limpiar la selección múltiple
                    _objectManager.ClearSelection();
                    _objectManager.RemoveResizeRectangles();
                    
                    // Desactivar el modo de selección múltiple
                    viewModel.IsMultiSelectionActive = false;
                    
                    e.Handled = true;
                }
            }
        }

        private void Canvas_MouseEnter(object sender, MouseEventArgs e)
        {
            if (e.OriginalSource == ImagenEnTrabajoCanvas)
            {
                //_objectManager.RemoveResizeRectangles();
            }
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            if (DataContext is MainViewModel viewModel)
            {
                viewModel.ImageSelected -= ViewModel_ImageSelected;
            }
        }

        private void CargarPropiedadesosDatos(osBase selectedObject)
        {
            if (DataContext is MainViewModel viewModel)
                viewModel.CargarPropiedadesosDatos(selectedObject, PanelEdicion, Resources);
        }

        public (float X, float Y) ObtenerCentroCanvasMeters()
        {
            var c = ObtenerCentroCanvasPixels();
            return (PixelToMeter.Instance.calc.PixelsToMeters(c.X),
                   PixelToMeter.Instance.calc.PixelsToMeters(c.Y));
        }

        public (float X, float Y) ObtenerCentroCanvasPixels()
        {
            var tg = (TransformGroup)ImagenEnTrabajoCanvas.RenderTransform;
            var st = (ScaleTransform)tg.Children.First(t => t is ScaleTransform);
            var tt = (TranslateTransform)tg.Children.First(t => t is TranslateTransform);

            double visibleWidth = ImagenEnTrabajoScrollViewer.ViewportWidth;
            double visibleHeight = ImagenEnTrabajoScrollViewer.ViewportHeight;

            double offsetX = ImagenEnTrabajoScrollViewer.HorizontalOffset;
            double offsetY = ImagenEnTrabajoScrollViewer.VerticalOffset;

            double centerX = offsetX + (visibleWidth / 2);
            double centerY = offsetY + (visibleHeight / 2);

            double canvasCenterX = (centerX - tt.X) / st.ScaleX;
            double canvasCenterY = (centerY - tt.Y) / st.ScaleY;

            return ((float)canvasCenterX, (float)canvasCenterY);
        }

        private void ViewModel_ImageSelected(object sender, string imagePath)
        {
            LoadImageToCanvas(imagePath);
        }

        public void DebugWindow()
        {
            var debugWindow = new wDebug
            {
                Data = dataDebug
            };
            debugWindow.Show();
        }

        private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Aceptar el evento si viene del canvas o de la imagen de fondo
            if ((e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo) && DataContext is MainViewModel viewModel)
            {
                e.Handled = true; // Importante: marcar el evento como manejado
                ShowContextMenu(e.GetPosition(ImagenEnTrabajoCanvas));
            }
        }

        private void ShowContextMenu(Point position)
        {
            var contextMenu = new ContextMenu();
            var multiSelectMenuItem = new MenuItem 
            { 
                Header = "Modo Multi-Selección",
                IsCheckable = true,
                StaysOpenOnClick = false  // Cerrar el menú al hacer clic
            };

            if (DataContext is MainViewModel viewModel)
            {
                multiSelectMenuItem.IsChecked = viewModel.IsMultiSelectionActive;
                multiSelectMenuItem.Click += (s, e) => 
                {
                    viewModel.IsMultiSelectionActive = multiSelectMenuItem.IsChecked;
                };
            }

            contextMenu.Items.Add(multiSelectMenuItem);
            contextMenu.PlacementTarget = ImagenEnTrabajoCanvas;
            contextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.MousePoint;
            contextMenu.IsOpen = true;
        }
    }

    public class FloatValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            if (string.IsNullOrEmpty(value?.ToString()))
                return new ValidationResult(false, "El campo no puede estar vacío.");

            if (float.TryParse(value.ToString(), NumberStyles.Float, cultureInfo, out float result))
                return ValidationResult.ValidResult;
            else
                return new ValidationResult(false, "Ingrese un número válido.");
        }
    }
}