using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using CtrEditor.Siemens;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Binding = System.Windows.Data.Binding;
using Label = System.Windows.Controls.Label;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using TextBox = System.Windows.Controls.TextBox;
using UserControl = System.Windows.Controls.UserControl;
using CheckBox = System.Windows.Controls.CheckBox;
using Orientation = System.Windows.Controls.Orientation;
using ListBox = System.Windows.Controls.ListBox;
using CtrEditor.ObjetosSim;


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;

        // Para los UserControl
        private Point _startPointUserControl;
        private UserControl _currentDraggingControl;
        private bool _isRotatingUserControl = false;
        private bool _isResizingUserControl = false;
        private bool _isDraggingUserControl = false;
        private bool _isMovingUserControl = false;
        private double _initialAngleUserControl;
        private TextBlock _angleDisplayTextBlock;

        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
            ImagenEnTrabajoScrollViewer.PreviewMouseWheel += ImagenEnTrabajoCanvas_MouseWheel;
            ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown_Panning;
            ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove_Panning;
            ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning;
        }
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            if (DataContext is MainViewModel viewModel)
            {
                viewModel.MainWindow = this;
                viewModel.ImageSelected += ViewModel_ImageSelected;                         
                viewModel?.LoadInitialData(); // Carga la primera imagen por defecto una vez cargada la ventana principal
                viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas;
                viewModel.MainCanvas = ImagenEnTrabajoCanvas;
            }
        }

        public (float X, float Y) ObtenerCentroCanvasPixels()
        {
            var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform;
            float scaleX = (float)(scaleTransform?.ScaleX ?? 1.0);
            float scaleY = (float)(scaleTransform?.ScaleY ?? 1.0);

            // Obtiene el área visible del ScrollViewer
            float visibleWidth = (float)ImagenEnTrabajoScrollViewer.ViewportWidth;
            float visibleHeight = (float)ImagenEnTrabajoScrollViewer.ViewportHeight;

            // Obtiene la posición actual del desplazamiento ajustada por el zoom
            float offsetX = (float)ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX;
            float offsetY = (float)ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY;

            // Calcula el centro visible ajustado
            float centerX = offsetX + (visibleWidth / scaleX) / 2;
            float centerY = offsetY + (visibleHeight / scaleY) / 2;

            return (centerX, centerY);
        }

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

        public void SuscribirEventos(UserControl userControl)
        {
            userControl.MouseEnter += UserControl_MouseEnter;
            userControl.MouseLeave += UserControl_MouseLeave;

            // Suscribir a eventos de mouse para panning
            userControl.MouseLeftButtonDown += UserControl_MouseLeftButtonDown;
            userControl.MouseLeftButtonUp += UserControl_MouseLeftButtonUp;
            userControl.MouseMove += UserControl_MouseMove;
        }

        public void AgregarRegistrarUserControlCanvas(UserControl userControl)
        {
            if (userControl is IDataContainer dataContainer)
            {
                SuscribirEventos(userControl);

                // Añade el UserControl al Canvas
                Canvas.SetZIndex(userControl, dataContainer.ZIndex());
                ImagenEnTrabajoCanvas.Children.Add(userControl);
            }
        }

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

        private void UserControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!_isDrawingCanvas)
            {
                var userControl = sender as UserControl;                
                _currentDraggingControl = userControl;
                userControl.CaptureMouse(); // Importante para recibir eventos de movimiento incluso fuera del control
                _isMovingUserControl = true;

                if (sender is UserControl control && control.DataContext is osBase datos)
                {
                    var viewModel = DataContext as MainViewModel;
                    if (viewModel != null)
                    {
                        viewModel.SelectedItemOsList = datos; // Esto desencadenará ListaOs_SelectionChanged
                    }
                }

                // ROTACION
                if (Keyboard.IsKeyDown(Key.LeftShift))
                {
                    // Inicializar la rotación
                    _isRotatingUserControl = true;
                    RotateTransform rotateTransform = userControl.RenderTransform as RotateTransform;
                    if (rotateTransform == null)
                    {
                        rotateTransform = new RotateTransform();
                        userControl.RenderTransform = rotateTransform;
                    }
                    _initialAngleUserControl = rotateTransform.Angle;

                    // Establecer el punto inicial de referencia para el cálculo de rotación
                    _startPointUserControl = new Point(rotateTransform.CenterX, rotateTransform.CenterY);

                    // Ajusta el punto inicial al espacio del Canvas
                    _startPointUserControl = userControl.TranslatePoint(_startPointUserControl, ImagenEnTrabajoCanvas);

                    // Crear y configurar el TextBlock si no existe
                    if (_angleDisplayTextBlock == null)
                    {
                        _angleDisplayTextBlock = new TextBlock
                        {
                            Foreground = Brushes.Black,
                            Background = Brushes.White,
                            Opacity = 0.8,
                            Padding = new Thickness(5)
                        };
                        ImagenEnTrabajoCanvas.Children.Add(_angleDisplayTextBlock);
                    }

                    PositionAngleDisplay(userControl);
                    _angleDisplayTextBlock.Visibility = Visibility.Visible;
                    Canvas.SetZIndex(_angleDisplayTextBlock, 15);
                }
                // TAMANO
                else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                {
                    // Inicializar el cambio de tamaño
                    _isResizingUserControl = true;
                }
                // MOVIMIENTO
                else
                {
                    // Inicializar el movimiento/panning
                    _isDraggingUserControl = true;
                    _startPointUserControl = e.GetPosition(ImagenEnTrabajoCanvas);
                }
            }
        }

        private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_isMovingUserControl)
            {
                var userControl = sender as UserControl;
                
                userControl.ReleaseMouseCapture();
                _currentDraggingControl = null;
                _isResizingUserControl = _isRotatingUserControl = _isDraggingUserControl = false ;
                _isMovingUserControl = false;
                // Ocultar el TextBlock de ángulo
                if (_angleDisplayTextBlock != null)
                {
                    _angleDisplayTextBlock.Visibility = Visibility.Collapsed;
                }
            }
        }

        private void UserControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (_isMovingUserControl && _currentDraggingControl != null)
            {
                var currentPosition = e.GetPosition(ImagenEnTrabajoCanvas);

                if (_isDraggingUserControl)
                {
                    // Código para mover el control
                    var dx = currentPosition.X - _startPointUserControl.X;
                    var dy = currentPosition.Y - _startPointUserControl.Y;
                    var newX = Canvas.GetLeft(_currentDraggingControl) + dx;
                    var newY = Canvas.GetTop(_currentDraggingControl) + dy;

                    if (_currentDraggingControl is IDataContainer dataContainer)
                        dataContainer.Move((float)newX,(float) newY);

                    _startPointUserControl = currentPosition;  // Actualiza el punto inicial para el siguiente movimiento
                }
                else if (_isRotatingUserControl)
                {
                    // Código para rotar el control
                    RotateControl(_currentDraggingControl, currentPosition);
                }
                else if (_isResizingUserControl)
                {
                    // Código para cambiar el tamaño del control
                    ResizeControl(_currentDraggingControl, currentPosition);
                }
                
            }
        }

        private void RotateControl(UserControl control, Point currentPosition)
        {
            double deltaX = currentPosition.X - _startPointUserControl.X;
            double deltaY = currentPosition.Y - _startPointUserControl.Y;
            double angle = Math.Atan2(deltaY, deltaX) * (180 / Math.PI);

            //RotateTransform rotateTransform = control.RenderTransform as RotateTransform;
            //rotateTransform.Angle = angle; // - _initialAngleUserControl;  // Asegúrate de ajustar esta parte según cómo calcules el ángulo inicial

            if (control is IDataContainer dataContainer)
                dataContainer.Rotate((float)angle);

            // Actualizar el ángulo mostrado
            _angleDisplayTextBlock.Text = $"Ángulo: {angle:F2}°";
            PositionAngleDisplay(control);
        }

        private void PositionAngleDisplay(UserControl control)
        {
            // Posicionar el TextBlock sobre el control
            Canvas.SetLeft(_angleDisplayTextBlock, Canvas.GetLeft(control));
            Canvas.SetTop(_angleDisplayTextBlock, Canvas.GetTop(control));
        }

        private void ResizeControl(UserControl control, Point currentPosition)
        {
            // Calcular la diferencia en la posición X desde el punto de inicio
            double widthChange = currentPosition.X - _startPointUserControl.X;

            // Calcular la diferencia en la posición Y desde el punto de inicio
            double heightChange = currentPosition.Y - _startPointUserControl.Y;

            // Actualizar el ancho del control
            double newWidth = Math.Max(control.ActualWidth + widthChange, control.MinWidth);

            // Actualizar la altura del control
            double newHeight = Math.Max(control.ActualHeight + heightChange, control.MinHeight);

            // Asegurar que el nuevo tamaño no sea menor que los mínimos
            control.Width = newWidth;
            control.Height = newHeight;

            if (control is IDataContainer dataContainer)
            {
                dataContainer.Resize((float)newWidth, (float)newHeight);
            }

            // Actualizar el punto de inicio para el próximo evento de movimiento
            _startPointUserControl = currentPosition;
        }


        private void UserControl_MouseEnter(object sender, MouseEventArgs e)
        {
            if (sender is UserControl userControl)
                if (userControl is IDataContainer dataContainer)
                    dataContainer.Highlight(true);
        }

        private void UserControl_MouseLeave(object sender, MouseEventArgs e)
        {
            if (sender is UserControl userControl)
                if (userControl is IDataContainer dataContainer)
                    dataContainer.Highlight(false);
        }

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

        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);
                }
            }

            // Ajusta el tamaño del Canvas a la imagen, si es necesario
            ImagenEnTrabajoCanvas.Width = bitmap.Width;
            ImagenEnTrabajoCanvas.Height = bitmap.Height;

            // Posiciona la imagen correctamente dentro del Canvas
            Canvas.SetLeft(imagenDeFondo, 0);
            Canvas.SetTop(imagenDeFondo, 0);

        }

        private void Canvas_MouseUp_Panning(object sender, MouseButtonEventArgs e)
        {
            if (_isDraggingCanvas)
            {
                _isDraggingCanvas = false;
                ImagenEnTrabajoScrollViewer.ReleaseMouseCapture(); // Finaliza la captura del ratón
            }
        }

        private void Canvas_MouseDown_Panning(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas && !_isMovingUserControl)
            {
                // Indica que se inicia el panning
                _isDraggingCanvas = true;
                // Guarda la posición actual del ratón
                _lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
                //ImagenEnTrabajoScrollViewer.CaptureMouse(); // Importante para capturar el movimiento
            }
        }

        private void Canvas_MouseMove_Panning(object sender, MouseEventArgs e)
        {
            if (_isDraggingCanvas && !_isDrawingCanvas)
            {
                // Calcula el nuevo desplazamiento basado en el movimiento del ratón
                var currentPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
                var dx = currentPosition.X - _lastMousePosition.X;
                var dy = currentPosition.Y - _lastMousePosition.Y;

                // Ajusta el desplazamiento del ScrollViewer
                ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(ImagenEnTrabajoScrollViewer.HorizontalOffset - dx);
                ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(ImagenEnTrabajoScrollViewer.VerticalOffset - dy);

                // Actualiza la posición del ratón para el próximo movimiento
                _lastMousePosition = currentPosition;
            }
        }

        private void ImagenEnTrabajoCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            var st = (ScaleTransform)ImagenEnTrabajoCanvas.LayoutTransform;
            double zoomFactor = e.Delta > 0 ? 1.1 : 0.9;
            Point cursorPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);

            // Calcular el punto focal del zoom relativo al contenido del ScrollViewer
            var absoluteX = ImagenEnTrabajoScrollViewer.HorizontalOffset  + cursorPosition.X;
            var absoluteY = ImagenEnTrabajoScrollViewer.VerticalOffset  + cursorPosition.Y;

            // Aplicar el zoom
            st.ScaleX *= zoomFactor;
            st.ScaleY *= zoomFactor;

            // Calcular el nuevo desplazamiento para que el zoom se centre en la posición del cursor
            ImagenEnTrabajoScrollViewer.UpdateLayout(); // Asegurarse de que el layout del ScrollViewer esté actualizado
            var newHorizontalOffset = absoluteX * zoomFactor - cursorPosition.X;
            var newVerticalOffset = absoluteY * zoomFactor - cursorPosition.Y;

            // Aplicar el nuevo desplazamiento
            ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(newHorizontalOffset);
            ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(newVerticalOffset);

            e.Handled = true; // Evita el procesamiento adicional del evento
        }

        private void ListaOs_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //PanelEdicion.Children.Clear();  // Limpiar el panel existente
            UserControlFactory.LimpiarPropiedadesosDatos(PanelEdicion);

            if (e.AddedItems.Count > 0 && e.AddedItems[0] is osBase selectedObject)
                CargarPropiedadesosDatos(selectedObject);
        }

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

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

    }

    public class FloatValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            // Comprobamos si el valor es nulo o está vacío
            if (string.IsNullOrEmpty(value?.ToString()))
                return new ValidationResult(false, "El campo no puede estar vacío.");

            // Intentamos convertir el valor a un tipo float
            if (float.TryParse(value.ToString(), NumberStyles.Float, cultureInfo, out float result))
                return ValidationResult.ValidResult; // La validación es exitosa
            else
                return new ValidationResult(false, "Ingrese un número válido.");
        }
    }

}