using System;
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 float _time;
        public float LaunchAngle { get; }
        public float Azimuth { get; }
        public float MuzzleVelocity { get; }
        public float FlightDuration { get; private set; }
        private readonly float _startX, _startY, _startZ;
        private readonly float _launchTime;

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

        // 地基：标记是否已超过释放高度
        private bool _hasExceededReleaseAltitude;
        // 发射点高于释放高度时，炮弹下降到达
        private bool _arrivesDescending;

        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? launchAngle = null,
            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)
            {
                if (muzzleVelocity <= 0)
                    throw new InvalidOperationException($"地基炮弹 {Id}: MuzzleVelocity={muzzleVelocity} 必须 > 0");
                if (!launchAngle.HasValue)
                    throw new InvalidOperationException($"地基炮弹 {Id}: LaunchAngle 不能为空，发射角度必须来自方案");

                var dx = targetX - startX;
                var dz = targetZ - startZ;
                Azimuth = (float)System.Math.Atan2(dx, dz);
                float heightDiff = releaseAltitude - startY;

                LaunchAngle = launchAngle.Value;
                var (_, tof) = Kinematics.ComputeParabolicRange(muzzleVelocity, LaunchAngle, heightDiff);
                FlightDuration = tof;
                // 发射点高于释放高度 → 下降到达；否则上升到达
                _arrivesDescending = heightDiff < 0;
            }
            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 (((y >= ReleaseAltitude && !_arrivesDescending) || (y <= ReleaseAltitude && _arrivesDescending)) && !_hasExceededReleaseAltitude)
                {
                    _hasExceededReleaseAltitude = true;
                    float tPrev = _time - deltaTime;
                    var (px0, py0, pz0) = Kinematics.ParabolicPosition(
                        _startX, _startY, _startZ, LaunchAngle, Azimuth, MuzzleVelocity, tPrev);
                    float frac = (ReleaseAltitude - py0) / (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;
                }
            }
        }
    }
}
