using BepuPhysics;
using BepuPhysics.Collidables;
using BepuPhysics.Trees;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace CtrEditor.Simulacion
{
    /// <summary>
    /// ✅ CORREGIDO: RayHitHandler personalizado para simBarrera
    /// Calcula la distancia mínima del rayo al centro de cada botella
    /// </summary>
    public struct BarreraRayHitHandler : IRayHitHandler
    {
        private simBarrera _barrera;
        private List<simBotella> _detectedBottles;
        private SimulationManagerBEPU _simulationManager;
        private float _minDistance;
        private bool _neckDetected;
        private bool _fullDetected;
        private Vector3 _rayOrigin;
        private Vector3 _rayDirection;

        internal BarreraRayHitHandler(simBarrera barrera, SimulationManagerBEPU simulationManager, Vector3 rayOrigin, Vector3 rayDirection)
        {
            _barrera = barrera;
            _simulationManager = simulationManager;
            _detectedBottles = new List<simBotella>();
            _minDistance = float.MaxValue;
            _neckDetected = false;
            _fullDetected = false;
            _rayOrigin = rayOrigin;
            _rayDirection = rayDirection;
        }

        public bool AllowTest(CollidableReference collidable)
        {
            // Solo testear botellas dinámicas
            if (collidable.Mobility == CollidableMobility.Dynamic)
            {
                var bottle = _simulationManager?.GetSimBaseFromBodyHandle(collidable.BodyHandle) as simBotella;
                return bottle != null;
            }
            return false;
        }

        public bool AllowTest(CollidableReference collidable, int childIndex)
        {
            // Para botellas (esferas), childIndex siempre es 0
            return AllowTest(collidable);
        }

        public void OnRayHit(in RayData ray, ref float maximumT, float t, Vector3 normal, CollidableReference collidable, int childIndex)
        {
            try
            {
                // Obtener la botella que fue hit
                var bottle = _simulationManager?.GetSimBaseFromBodyHandle(collidable.BodyHandle) as simBotella;
                if (bottle == null) return;

                // Obtener posición del centro de la botella
                var bottleCenter = bottle.GetPosition();

                // ✅ CORREGIDO: Calcular la distancia mínima del rayo (línea) al centro de la botella
                var minDistanceToCenter = CalculateMinimumDistanceFromRayToPoint(_rayOrigin, _rayDirection, bottleCenter);

                // Actualizar distancia mínima global
                if (minDistanceToCenter < _minDistance)
                {
                    _minDistance = minDistanceToCenter;
                }

                // ✅ CORREGIDO: Verificar detección completa usando distancia mínima del rayo al centro
                if (minDistanceToCenter <= bottle.Radius)
                {
                    _fullDetected = true;
                    if (!_detectedBottles.Contains(bottle))
                    {
                        _detectedBottles.Add(bottle);
                    }
                }

                // ✅ CORREGIDO: Verificar detección de cuello usando circunferencia imaginaria con radio/2
                if (_barrera.DetectNeck && minDistanceToCenter <= (bottle.Radius / 2f))
                {
                    _neckDetected = true;
                }

                // System.Diagnostics.Debug.WriteLine($"[BarreraRayHitHandler] Hit: Botella={bottle.BodyHandle}, distanciaMinima={minDistanceToCenter:F3}, radio={bottle.Radius:F3}");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"[BarreraRayHitHandler] Error en OnRayHit: {ex.Message}");
            }
        }

        /// <summary>
        /// ✅ NUEVO: Calcula la distancia mínima de un rayo (línea) a un punto
        /// </summary>
        private float CalculateMinimumDistanceFromRayToPoint(Vector3 rayOrigin, Vector3 rayDirection, Vector3 point)
        {
            // Vector desde el origen del rayo al punto
            var rayToPoint = point - rayOrigin;

            // Proyección del vector rayToPoint sobre la dirección del rayo
            var projection = Vector3.Dot(rayToPoint, rayDirection);

            // Punto más cercano en el rayo al punto dado
            var closestPointOnRay = rayOrigin + rayDirection * projection;

            // Distancia mínima del rayo al punto
            return Vector3.Distance(closestPointOnRay, point);
        }

        // ✅ NUEVO: Método para obtener los resultados del raycast
        public void GetResults(out bool luzCortada, out bool luzCortadaNeck, out float distancia, out List<simBotella> botellas)
        {
            luzCortada = _fullDetected;
            luzCortadaNeck = _neckDetected;
            distancia = _minDistance == float.MaxValue ? 0f : _minDistance;
            botellas = new List<simBotella>(_detectedBottles);
        }
    }


    /// <summary>
    /// Estructura para datos de barrera que se exponen a WPF
    /// </summary>
    public struct BarreraData
    {
        public bool LuzCortada;
        public bool LuzCortadaNeck;

        public BarreraData(bool luzCortada, bool luzCortadaNeck)
        {
            LuzCortada = luzCortada;
            LuzCortadaNeck = luzCortadaNeck;
        }
    }

    public class simBarrera : simBase
    {
        internal bool LuzCortada;
        internal bool LuzCortadaNeck;
        public List<simBotella> ListSimBotellaContact;
        public float Width { get; set; }
        public float Height { get; set; }
        public bool DetectNeck { get; set; }

        // ✅ NUEVO: Propiedades para raycast
        private SimulationManagerBEPU _simulationManager;

        // ✅ CORREGIDO: Almacenar ángulo internamente como radianes BEPU (como simCurve)
        private float _angleRadians; // ✅ SIEMPRE en radianes BEPU (ya convertido desde WPF)

        internal simBarrera(Simulation simulation, float width, float height, Vector3 bepuPosition, float bepuRadians = 0, bool detectectNeck = false, SimulationManagerBEPU simulationManager = null)
        {
            _simulation = simulation;
            _simulationManager = simulationManager;
            Width = width;
            Height = height;
            DetectNeck = detectectNeck;
            ListSimBotellaContact = new List<simBotella>();

            // ✅ CREAR POSICIÓN SIN BODY FÍSICO usando parámetros BEPU internos
            CreatePosition(width, height, bepuPosition, bepuRadians);
        }

        internal void Update(float width, float height, Vector3 bepuPosition, float bepuRadians = 0)
        {
            Width = width;
            Height = height;
            ListSimBotellaContact = new List<simBotella>();

            // ✅ CREAR POSICIÓN SIN BODY FÍSICO usando parámetros BEPU internos
            CreatePosition(width, height, bepuPosition, bepuRadians);
        }


        // ✅ NUEVO: Variables para almacenar pose sin crear body físico
        private Vector3 _position;
        private Quaternion _orientation;
        private bool _poseInitialized = false;

        // ✅ NUEVO: Propiedad pública para acceder a la posición
        public Vector3 Position
        {
            get => _poseInitialized ? _position : Vector3.Zero;
            set
            {
                _position = value;
                _poseInitialized = true;
            }
        }

        // ✅ NUEVO: Propiedad pública para acceder al ángulo en radianes BEPU
        public float AngleRadians
        {
            get => _poseInitialized ? _angleRadians : 0f;
            set
            {
                _angleRadians = value;
                UpdateOrientationFromInternalAngle();
                _poseInitialized = true;
            }
        }

        // ✅ NUEVO: Método interno para actualizar orientación desde ángulo interno
        private void UpdateOrientationFromInternalAngle()
        {
            // ✅ CREAR QUATERNION DESDE RADIANES BEPU INTERNOS
            _orientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, _angleRadians);
        }

        /// <summary>
        /// ✅ INTERNO: Actualiza posición y rotación desde parámetros BEPU internos
        /// </summary>
        internal void Update(Vector3 bepuPosition, float bepuRadians)
        {
            Position = bepuPosition;
            AngleRadians = bepuRadians;
        }

        public void SetDimensions(float width, float height)
        {
            Width = width;
            Height = height;
        }

        /// <summary>
        /// ✅ INTERNO: Crea la posición usando parámetros BEPU internos
        /// </summary>
        internal void CreatePosition(float width, float height, Vector3 bepuPosition, float bepuRadians)
        {
            Width = width;
            Height = height;

            // ✅ ALMACENAR DIRECTAMENTE parámetros BEPU internos
            Position = bepuPosition;
            AngleRadians = bepuRadians;

            // ✅ NO CREAR BODY FÍSICO - solo almacenar datos
            _bodyCreated = false;
        }

        /// <summary>
        /// ✅ CORREGIDO: Realiza raycast para detectar botellas usando coordenadas BEPU internas
        /// </summary>
        public void PerformRaycast()
        {
            try
            {
                // Resetear flags
                LuzCortada = false;
                LuzCortadaNeck = false;
                ListSimBotellaContact?.Clear();

                // Validar que tenemos simulación y manager
                if (_simulation == null || _simulationManager == null || !_poseInitialized)
                {
                    System.Diagnostics.Debug.WriteLine("[PerformRaycast] Simulación, manager o pose no inicializados");
                    return;
                }

                // ✅ CORREGIDO: Usar coordenadas BEPU internas para cálculos
                var bepuPosition = Position;
                var Orientation = _orientation;

                // ✅ CORREGIDO: Crear puntos del ray a la altura correcta
                var halfWidth = Width / 2f;
                var rayStartLocal = new Vector3(-halfWidth, 0, 0);
                var rayEndLocal = new Vector3(halfWidth, 0, 0);

                // ✅ CORREGIDO: Ajustar la posición de la barrera para que el ray esté a la altura correcta
                var barreraPosition = new Vector3(bepuPosition.X, bepuPosition.Y, bepuPosition.Z);

                // ✅ TRANSFORMAR PUNTOS LOCALES A COORDENADAS MUNDIALES A LA ALTURA CORRECTA
                var worldStart = barreraPosition + Vector3.Transform(rayStartLocal, Orientation);
                var worldEnd = barreraPosition + Vector3.Transform(rayEndLocal, Orientation);

                // ✅ CALCULAR DIRECCIÓN Y DISTANCIA DEL RAY
                var rayDirection = worldEnd - worldStart;
                var rayDistance = rayDirection.Length();

                if (rayDistance < 0.001f)
                {
                    System.Diagnostics.Debug.WriteLine("[PerformRaycast] Ray demasiado corto");
                    return;
                }

                rayDirection = Vector3.Normalize(rayDirection);

                // ✅ CORREGIDO: CREAR HANDLER PARA PROCESAR HITS con parámetros correctos
                var rayHandler = new BarreraRayHitHandler(this, _simulationManager, worldStart, rayDirection);

                // ✅ REALIZAR RAYCAST
                _simulation.RayCast(worldStart, rayDirection, rayDistance, ref rayHandler);

                // ✅ OBTENER RESULTADOS
                rayHandler.GetResults(out bool luzCortada, out bool luzCortadaNeck, out float distancia, out List<simBotella> botellas);

                // ✅ ASIGNAR RESULTADOS
                LuzCortada = luzCortada;
                LuzCortadaNeck = luzCortadaNeck;

                if (ListSimBotellaContact != null)
                {
                    ListSimBotellaContact.Clear();
                    ListSimBotellaContact.AddRange(botellas);
                }

                //System.Diagnostics.Debug.WriteLine($"[PerformRaycast] {worldStart} - {worldEnd} - {rayDistance} - {rayDirection} ");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"[PerformRaycast] Error: {ex.Message}");
            }
        }

        /// <summary>
        /// ✅ INTERNO: Métodos Create que trabajan solo con parámetros BEPU internos
        /// </summary>
        internal void Create(float width, float height, Vector3 bepuPosition, float bepuRadians = 0, bool detectectNeck = false)
        {
            CreatePosition(width, height, bepuPosition, bepuRadians);
        }

        /// <summary>
        /// ✅ OVERRIDE: RemoverBody no hace nada porque no hay body físico
        /// </summary>
        public new void RemoverBody()
        {
            // ✅ NO HAY BODY FÍSICO QUE REMOVER
            _bodyCreated = false;
            _poseInitialized = false;
        }

    }

}
