using System;
using CounterDrone.Core.Models;

namespace CounterDrone.Core.Algorithms
{
    /// <summary>三阶段简化扩散模型</summary>
    /// <remarks>
    /// Phase 1 (0时刻): R₀ = 3.3 × BurstChargeKg^0.32
    /// Phase 2 (0~30s): R(t) = R₀ + TurbulentExpansionK × √t
    /// Phase 3 (30s~):   高斯烟团 (Pasquill-Gifford)
    /// </remarks>
    public class GaussianPuffDispersion : ICloudDispersionModel
    {
        private AmmunitionSpec _ammo = null!;
        private float _elapsed;
        private float _currentRadius;
        private float _currentDensity;
        private Vector3 _center;
        private Vector3 _windVelocity;
        private bool _inPhase3;

        public Vector3 Center => _center;
        public float Radius => _currentRadius;
        public float CoreDensity => _currentDensity;
        public float EffectiveRadius => _currentRadius;
        public ParticleParams Particles { get; } = new();
        public bool IsDissipated { get; private set; }
        public int Phase => _inPhase3 ? 3 : (_elapsed < 0.01f ? 1 : 2);
        public float Elapsed => _elapsed;

        public void Initialize(AmmunitionSpec ammo, CombatScene env, Vector3 releasePos, float releaseTime)
        {
            _ammo = ammo;
            _elapsed = 0f;
            _inPhase3 = false;

            // Phase 1: 爆轰膨胀 → 初始半径
            var w = (float)ammo.BurstChargeKg;
            _currentRadius = 3.3f * (float)Math.Pow(Math.Max(0.01, w), 0.32);
            _currentDensity = (float)ammo.CoreDensity;
            _center = releasePos;
            IsDissipated = false;

            var (vx, vy, vz) = Kinematics.WindToVector((WindDirection)env.WindDirection, (float)env.WindSpeed);
            _windVelocity = new Vector3(vx, vy, vz);
        }

        public void Tick(float deltaTime, float windSpeed, WindDirection windDir)
        {
            if (IsDissipated) return;

            _elapsed += deltaTime;

            var (vx, vy, vz) = Kinematics.WindToVector(windDir, windSpeed);
            _windVelocity = new Vector3(vx, vy, vz);

            // 判断阶段切换
            if (!_inPhase3 && _elapsed >= 30f)
                _inPhase3 = true;

            if (!_inPhase3)
            {
                // Phase 2: 湍流扩散 R(t) = R₀ + k × √t
                var k = (float)_ammo.TurbulentExpansionK;
                _currentRadius = 3.3f * (float)Math.Pow(Math.Max(0.01, (float)_ammo.BurstChargeKg), 0.32)
                    + k * (float)Math.Sqrt(_elapsed);
                // 密度 = 源强 / 体积
                var volume = (4f / 3f) * (float)Math.PI * _currentRadius * _currentRadius * _currentRadius;
                _currentDensity = volume > 0.001f ? (float)_ammo.SourceStrength / volume : 0f;
            }
            else
            {
                // Phase 3: 高斯扩散
                var x = Math.Max(1f, windSpeed * (_elapsed - 30f));
                var cls = Kinematics.GetStabilityClass((WeatherType)0, windSpeed);
                var sY = Kinematics.SigmaY(cls, x);
                var sZ = Kinematics.SigmaZ(cls, x);
                _currentDensity = Kinematics.GaussianPeakConcentration((float)_ammo.SourceStrength, sY, sZ);
                // 有效半径从浓度反推
                var effConc = (float)_ammo.EffectiveConcentration;
                if (_currentDensity > effConc)
                {
                    var sigma = (sY + sZ) / 2f;
                    _currentRadius = sigma * (float)Math.Sqrt(2f * Math.Log(_currentDensity / effConc));
                }
            }

            // 随风漂移
            _center.X += _windVelocity.X * deltaTime;
            _center.Y += _windVelocity.Y * deltaTime;
            _center.Z += _windVelocity.Z * deltaTime;

            // 粒子参数
            Particles.Opacity = Math.Max(0.1f, _currentDensity / (float)_ammo.CoreDensity);
            Particles.SizeMultiplier = _currentRadius / Math.Max(0.5f, 3.3f * (float)Math.Pow(Math.Max(0.01, (float)_ammo.BurstChargeKg), 0.32));

            // 消散
            if (_elapsed >= (float)_ammo.MaxDuration || _currentRadius >= (float)_ammo.MaxRadius)
            {
                IsDissipated = true;
                Particles.Opacity = 0f;
            }
        }
    }
}
