using System;
using CounterDrone.Core.Models;

namespace CounterDrone.Core.Algorithms
{
    /// <summary>云团膨胀模型——根据弹药和环境参数计算各阶段半径、密度、膨胀时间</summary>
    public class CloudExpansionModel
    {
        private readonly AmmunitionSpec _ammo;
        private readonly CombatScene _env;

        public CloudExpansionModel(AmmunitionSpec ammo, CombatScene env)
        {
            _ammo = ammo;
            _env = env;
        }

        /// <summary>Phase 1 爆轰初始半径 (m)</summary>
        public float InitialRadius => 3.3f * (float)Math.Pow(Math.Max(0.01, (float)_ammo.BurstChargeKg), 0.32f);
        /// <summary>Phase 2 结束时的有效半径（30s 湍流膨胀）</summary>
        public float TurbulentRadius => RadiusAt(30f);

        /// <summary>湍流膨胀系数 k</summary>
        public float TurbulentExpansionK => (float)_ammo.TurbulentExpansionK;

        /// <summary>指定时刻湍流膨胀半径 R(t) = R₀ + k√t</summary>
        public float RadiusAt(float elapsedSeconds)
        {
            if (elapsedSeconds <= 0) return InitialRadius;
            bool inPhase3 = elapsedSeconds > 30f;
            if (!inPhase3)
                return InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(elapsedSeconds);

            // Phase 3: 高斯扩散
            float windSpeed = (float)_env.WindSpeed;
            float x = Math.Max(1f, windSpeed * (elapsedSeconds - 30f));
            var cls = Kinematics.GetStabilityClass((WeatherType)_env.WeatherType, windSpeed);
            float sY = Kinematics.SigmaY(cls, x);
            float sZ = Kinematics.SigmaZ(cls, x);
            float peakC = Kinematics.GaussianPeakConcentration((float)_ammo.SourceStrength, sY, sZ);
            float effConc = (float)_ammo.EffectiveConcentration;
            if (peakC <= effConc) return InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(30f);
            float sigma = (sY + sZ) / 2f;
            float rPhase2 = InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(30f);
            return rPhase2 + sigma * (float)Math.Sqrt(2f * Math.Log(peakC / effConc));
        }

        /// <summary>指定时刻中心浓度</summary>
        public float DensityAt(float elapsedSeconds)
        {
            float r = RadiusAt(elapsedSeconds);
            float volume = (4f / 3f) * (float)Math.PI * r * r * r;
            return volume > 0.001f ? (float)_ammo.SourceStrength / volume : (float)_ammo.CoreDensity;
        }


        /// <summary>覆盖指定距离需要的云团数量</summary>
        /// <param name="requiredCoverage">需要覆盖的距离 (m)</param>
        /// <param name="spacing">相邻云团中心间距 (m)，默认=2R(相切)。重叠时由调用方传入更小值。</param>
        public int RoundsNeeded(float requiredCoverage, float? spacing = null)
        {
            float s = spacing ?? 2f * TurbulentRadius;
            return Math.Max(1, (int)Math.Ceiling(requiredCoverage / s));
        }

        /// <summary>达到指定半径所需时间 (s)</summary>
        public float TimeToReach(float radius)
        {
            float r0 = InitialRadius;
            if (radius <= r0) return 0;
            float k = TurbulentExpansionK;
            return (radius - r0) * (radius - r0) / (k * k);
        }
    }
}
