using BepuPhysics.Collidables;
using BepuPhysics.Constraints;
using BepuPhysics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;

namespace CtrEditor.Simulacion
{

    public class simBotella : simBase
    {
        public float Radius;
        public float Height; // Altura para la visualización del cilindro en Helix
        private float _mass;
        public bool Descartar = false;
        public int isOnTransports;
        public List<simBase> ListOnTransports;
        public bool isRestricted;
        public bool isNoMoreRestricted;

        public simTransporte ConveyorRestrictedTo;
        public float OverlapPercentage;
        public float _neckRadius;
        public bool isOnBrakeTransport; // Nueva propiedad para marcar si está en un transporte con freno
        public simTransporte CurrentBrakeTransport { get; set; } // ✅ NUEVA: Referencia al transporte de freno actual

        // ✅ NUEVO: Propiedades para control de flotación/presión
        public float? LastTransportCollisionZ { get; set; }
        public bool IsTouchingTransport { get; set; } = false;

        // ✅ NUEVO: Sistema de fricción dinámica con cooldown/heatup
        public float HighSlippery { get; set; } = 0f; // Rango 0-9, donde 9 es máxima presión/deslizamiento
        public float ContactPressure { get; set; } = 0f; // Rango 0-9, donde 9 es mínima presión/deslizamiento
        public float forceScale { get; set; } = 1f; 

        // ✅ NUEVO: Propiedades para la física personalizada
        public float BaseInverseMass { get; private set; }
        public Vector3 InitialPosition3D { get; private set; }

        private List<Action> _deferredActions;

        public simBotella(Simulation simulation, List<Action> deferredActions, float diameter, Vector2 position, float mass, float neckRadius = 0)
        {
            _simulation = simulation;
            _deferredActions = deferredActions;
            Radius = diameter / 2f;
            Height = diameter; // Altura igual al diámetro para mantener proporciones similares
            _mass = mass;
            _neckRadius = neckRadius;
            ListOnTransports = new List<simBase>();

            // ✅ USAR COORDINATECONVERTER para conversión centralizada
            var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), Radius + zPos_Transporte + zAltura_Transporte);
            Create(position3D);
        }

        public float CenterX
        {
            get
            {
                return GetPosition().X;
            }
            set
            {
                var pos = GetPosition();
                SetPosition(value, pos.Y, pos.Z);
            }
        }

        public float CenterY
        {
            get
            {
                // ✅ USAR COORDINATECONVERTER para conversión centralizada
                return CoordinateConverter.BepuYToWpfY(GetPosition().Y);
            }
            set
            {
                var pos = GetPosition();
                // ✅ USAR COORDINATECONVERTER para conversión centralizada
                SetPosition(pos.X, CoordinateConverter.WpfYToBepuY(value), pos.Z);
            }
        }

        public Vector2 Center
        {
            get
            {
                var pos3D = GetPosition();
                // ✅ USAR COORDINATECONVERTER para conversión centralizada
                return CoordinateConverter.BepuVector3ToWpfVector2(pos3D);
            }
            set
            {
                // Mantener la Z actual, solo cambiar X, Y
                var currentPos = GetPosition();
                // ✅ USAR COORDINATECONVERTER para conversión centralizada
                SetPosition(value.X, CoordinateConverter.WpfYToBepuY(value.Y), currentPos.Z);
            }
        }

        public float Mass
        {
            get
            {
                if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
                {
                    var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle);
                    return 1f / bodyReference.LocalInertia.InverseMass;
                }
                return _mass;
            }
            set
            {
                _mass = value;
                if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
                {
                    var cylinder = new Cylinder(Radius, Height);
                    var inertia = cylinder.ComputeInertia(_mass);

                    // Modificamos el tensor de inercia para evitar que la botella vuelque.
                    var inverseInertia = inertia.InverseInertiaTensor;
                    inverseInertia.XX = 0f; // Resistencia infinita a la rotación en el eje X (vuelco).
                    inverseInertia.YY = 0f; // Resistencia infinita a la rotación en el eje Y (vuelco).
                    // La resistencia en ZZ (eje Z) se mantiene, permitiendo que la botella gire sobre su base.
                    inertia.InverseInertiaTensor = inverseInertia;

                    _simulation.Bodies.SetLocalInertia(BodyHandle, inertia);
                }
            }
        }

        private void Create(Vector3 position)
        {
            RemoverBody();

            var cylinder = new Cylinder(Radius, Height);
            var shapeIndex = _simulation.Shapes.Add(cylinder);

            // 1. Creamos el cuerpo con una inercia por defecto.
            var defaultInertia = cylinder.ComputeInertia(_mass);
            var activityDescription = new BodyActivityDescription(-1f); 
            var bodyDescription = BodyDescription.CreateDynamic(
                new RigidPose(position),
                new BodyVelocity(),
                defaultInertia,
                new CollidableDescription(shapeIndex, 0),
                activityDescription
            );
            BodyHandle = _simulation.Bodies.Add(bodyDescription);
            _bodyCreated = true;

            // 2. Inmediatamente después de crearlo, aplicamos la inercia personalizada.
            // Esto asegura que SetLocalInertia se llame para todos los objetos nuevos.
            var inertia = cylinder.ComputeInertia(_mass);
            var inverseInertia = inertia.InverseInertiaTensor;
            inverseInertia.XX = 0f; 
            inverseInertia.YY = 0f;
            inertia.InverseInertiaTensor = inverseInertia;
            _simulation.Bodies.SetLocalInertia(BodyHandle, inertia);

            // ✅ NUEVO: Almacenar la masa inversa base después de crear el cuerpo
            // Esto nos sirve como referencia para la lógica de masa dinámica.
            var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle);
            this.BaseInverseMass = bodyReference.LocalInertia.InverseMass;

            // ✅ CORREGIDO: Usar el diccionario del SimulationManager y la clave .Value del handle.
            if (_simulationManager != null)
                _simulationManager.CollidableData[BodyHandle.Value] = this;
        }

        public void SetDiameter(float diameter)
        {
            Radius = diameter / 2f;
            Height = diameter; // Mantener altura igual al diámetro para proporciones consistentes

            // ✅ CORREGIDO: Usar ChangeBodyShape para limpiar la forma anterior
            if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
            {
                var cylinder = new Cylinder(Radius, Height);
                var shapeIndex = _simulation.Shapes.Add(cylinder);
                ChangeBodyShape(shapeIndex);
            }
        }

        public void SetHeight(float height)
        {
            Height = height;

            // ✅ CORREGIDO: Usar ChangeBodyShape para limpiar la forma anterior
            if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
            {
                var cylinder = new Cylinder(Radius, Height);
                var shapeIndex = _simulation.Shapes.Add(cylinder);
                ChangeBodyShape(shapeIndex);
            }
        }

        public void SetMass(float mass)
        {
            Mass = mass;
        }

        /// <summary>
        /// Limita la rotación de la botella solo al plano XY (siempre "de pie")
        /// Esto simplifica enormemente la simulación y es más realista para botellas
        /// </summary>
        public void LimitRotationToXYPlane()
        {
            if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
            {
                var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle);

                // Extraer solo la rotación en Z (plano XY) y eliminar las rotaciones en X e Y
                var currentOrientation = bodyReference.Pose.Orientation;

                // Convertir a ángulo en Z solamente
                var rotationZ = GetRotationZ();

                // ✅ CORREGIDO: Calificar explícitamente para evitar ambigüedad de tipos.
                var correctedOrientation = System.Numerics.Quaternion.CreateFromAxisAngle(Vector3.UnitZ, rotationZ);

                // Aplicar la orientación corregida
                bodyReference.Pose.Orientation = correctedOrientation;

                // También limitar la velocidad angular a solo rotación en Z
                var angularVelocity = bodyReference.Velocity.Angular;
                bodyReference.Velocity.Angular = new Vector3(0, 0, angularVelocity.Z);
            }
        }

        public void ApplyLinearVelocity(Vector3 velocity)
        {
            if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
            {
                var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle);
                bodyReference.Velocity.Linear = velocity;
            }
        }

        public Vector3 GetLinearVelocity()
        {
            if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
            {
                var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle);
                return bodyReference.Velocity.Linear;
            }
            return Vector3.Zero;
        }

        public void CenterFixtureOnConveyor()
        {
            // Implementar lógica de centrado si es necesario
        }

        public bool IsOnAnyTransport()
        {
            return isOnTransports > 0;
        }

        /// <summary>
        /// ✅ SIMPLIFICADO: RemoverBody que confía en BEPU para limpiar constraints
        /// </summary>
        public new void RemoverBody()
        {
            base.RemoverBody();
        }

    }

}
