using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;
using CounterDrone.Core.Simulation;
using Xunit;

namespace CounterDrone.Core.Tests
{
    public class MunitionEntityTests
    {
        [Fact]
        public void GroundBased_DoesNotArriveImmediately()
        {
            var m = new MunitionEntity("m1", PlatformType.GroundBased,
                AerosolType.InertGas,
                startX: 0, startY: 0, startZ: 0,
                targetX: 5000, targetY: 300, targetZ: 0,
                muzzleVelocity: 500f, releaseAltitude: 300f, launchTime: 0f);

            m.Update(0.05f);
            Assert.False(m.HasArrived, "炮弹不能第一帧就到达");
        }

        [Fact]
        public void GroundBased_ArrivesNearTarget_WithInterpolation()
        {
            // 大 tick 步长也应到达目标附近
            var m = new MunitionEntity("m2", PlatformType.GroundBased,
                AerosolType.InertGas,
                startX: 5000, startY: 0, startZ: 50,
                targetX: 10000, targetY: 500, targetZ: 0,
                muzzleVelocity: 800f, releaseAltitude: 500f, launchTime: 143.69f);

            float time = Kinematics.ParabolicShellTime(5000.25f, 500f, 800f);
            for (float t = 0; t < time + 1f; t += 0.4f)
            {
                m.Update(0.4f);
                if (m.HasArrived) break;
            }
            Assert.True(m.HasArrived, "应到达");
            Assert.Equal(500f, m.PosY, 5f);
            Assert.True(System.Math.Abs(m.PosX - 10000) < 200f, $"X={m.PosX:F1} 应≈10000");
        }

        [Fact]
        public void GroundBased_LaunchAngle_ReachesReleaseAltitude()
        {
            // 验证运动学：给定距离和初速，弹道能达到释放高度
            var range = 5000f;
            var v0 = 500f;
            var releaseAlt = 300f;
            var angle = Kinematics.CalculateLaunchAngle(range, v0, releaseAlt);

            // 弹道顶点高度 >= 释放高度
            var peakH = v0 * v0 * (float)System.Math.Sin(angle) * (float)System.Math.Sin(angle) / (2f * 9.81f);
            Assert.True(peakH >= releaseAlt,
                $"弹道顶点 {peakH:F0}m ≥ 释放高度 {releaseAlt}m, angle={angle * 180 / System.Math.PI:F1}°");
        }

        [Fact]
        public void GroundBased_MovesForwardOverTime()
        {
            var m = new MunitionEntity("m1", PlatformType.GroundBased,
                AerosolType.InertGas,
                startX: 0, startY: 0, startZ: 0,
                targetX: 1000, targetY: 300, targetZ: 0,
                muzzleVelocity: 500f, releaseAltitude: 300f, launchTime: 0f);

            m.Update(1f);
            var dist = System.Math.Sqrt(m.PosX * m.PosX + m.PosZ * m.PosZ);
            Assert.True(dist > 100f, "1秒后炮弹应水平移动 > 100m");
        }

        [Fact]
        public void AirBased_DropsToReleaseAltitude()
        {
            var m = new MunitionEntity("m1", PlatformType.AirBased,
                AerosolType.InertGas,
                startX: 0, startY: 500, startZ: 0,
                targetX: 1000, targetY: 300, targetZ: 0,
                muzzleVelocity: 0, releaseAltitude: 300f, launchTime: 0f);

            // 空基投放：自由落体 500m → 300m = 200m 下落
            // h = 0.5*g*t² → t = sqrt(2*200/9.81) ≈ 6.4s
            for (int i = 0; i < 500; i++)
            {
                m.Update(0.05f);
                if (m.HasArrived) break;
            }

            Assert.True(m.HasArrived, "空基弹药应到达释放高度");
            Assert.True(m.PosY <= 300f + 1f);
        }
    }
}
