using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;

namespace CounterDrone.Core.Simulation
{
    public class MunitionEntity
    {
        public string Id { get; }
        public PlatformType LaunchMode { get; }
        public AerosolType AerosolType { get; }
        public float PosX { get; private set; }
        public float PosY { get; private set; }
        public float PosZ { get; private set; }
        public float TargetX { get; }
        public float TargetY { get; }
        public float TargetZ { get; }
        public float ReleaseAltitude { get; }
        public bool HasArrived { get; private set; }
        public float ArrivalTime { get; private set; }

        private readonly float _muzzleVelocity;
        private float _time;
        private readonly float _launchAngle;
        private readonly float _azimuth;
        private readonly float _startX, _startY, _startZ;
        private readonly float _launchTime;
        private float _flightDuration;

        // 空基投放：继承载机速度
        private readonly float _carrierVelX, _carrierVelY, _carrierVelZ;

        private bool _hasExceededReleaseAltitude;

        public MunitionEntity(string id, PlatformType launchMode, AerosolType aerosolType,
            float startX, float startY, float startZ,
            float targetX, float targetY, float targetZ,
            float muzzleVelocity, float releaseAltitude,
            float launchTime,
            float carrierVelX = 0f, float carrierVelY = 0f, float carrierVelZ = 0f)
        {
            Id = id;
            LaunchMode = launchMode;
            AerosolType = aerosolType;
            _startX = startX; _startY = startY; _startZ = startZ;
            PosX = startX; PosY = startY; PosZ = startZ;
            TargetX = targetX; TargetY = targetY; TargetZ = targetZ;
            _muzzleVelocity = muzzleVelocity;
            ReleaseAltitude = releaseAltitude;
            _carrierVelX = carrierVelX;
            _carrierVelY = carrierVelY;
            _carrierVelZ = carrierVelZ;
            _launchTime = launchTime;

            if (launchMode == PlatformType.GroundBased)
            {
                var dx = targetX - startX;
                var dz = targetZ - startZ;
                var horizontalDist = (float)System.Math.Sqrt(dx * dx + dz * dz);
                _azimuth = horizontalDist > 0.001f ? (float)System.Math.Atan2(dx, dz) : 0;
                _launchAngle = Kinematics.CalculateLaunchAngle(horizontalDist, muzzleVelocity, releaseAltitude);
                _flightDuration = Kinematics.ParabolicTimeOfFlight(horizontalDist, _launchAngle, muzzleVelocity);
            }
            else
            {
                _flightDuration = Kinematics.AirDropFallTime(startY, releaseAltitude);
            }
        }

        public void Update(float deltaTime)
        {
            if (HasArrived) return;
            _time += deltaTime;

            if (LaunchMode == PlatformType.GroundBased)
            {
                (float x, float y, float z) = Kinematics.ParabolicPosition(
                    _startX, _startY, _startZ, _launchAngle, _azimuth, _muzzleVelocity, _time);
                PosX = x; PosY = y; PosZ = z;

                if (PosY >= ReleaseAltitude && !_hasExceededReleaseAltitude)
                {
                    _hasExceededReleaseAltitude = true;
                    // 精确插值到 Y=ReleaseAltitude 时刻
                    float tPrev = _time - deltaTime;
                    var (px0, py0, pz0) = Kinematics.ParabolicPosition(
                        _startX, _startY, _startZ, _launchAngle, _azimuth, _muzzleVelocity, tPrev);
                    float frac = (ReleaseAltitude - py0) / System.Math.Max(0.01f, PosY - py0);
                    PosX = px0 + (PosX - px0) * frac;
                    PosY = ReleaseAltitude;
                    PosZ = pz0 + (PosZ - pz0) * frac;
                    HasArrived = true;
                    ArrivalTime = _launchTime + _flightDuration;
                }
            }
            else
            {
                (float x, float y, float z) = Kinematics.AirDropPosition(
                    _startX, _startY, _startZ,
                    _carrierVelX, _carrierVelY, _carrierVelZ,
                    _time);
                PosX = x; PosY = y; PosZ = z;

                if (PosY <= ReleaseAltitude)
                {
                    PosY = ReleaseAltitude;
                    HasArrived = true;
                    ArrivalTime = _launchTime + _flightDuration;
                }
            }
        }
    }
}
