using System;
using System.Collections.Generic;
using System.Linq;
using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;
using CounterDrone.Core.Services;
using SQLite;

namespace CounterDrone.Core.Simulation
{
    /// <summary>仿真引擎 — 纯执行器，接收发射计划按时间表执行</summary>
    public class SimulationEngine
    {
        private readonly IScenarioService _scenarioService;
        private readonly FrameDataStore _frameStore;
        private readonly IDamageModel _damageModel;
        private readonly IPathProvider _paths;

        public SimulationState State { get; private set; } = SimulationState.Idle;
        public int FrameIndex { get; private set; }
        public float SimulationTime { get; private set; }
        public float TimeScale { get; set; } = 1f;
        /// <summary>是否录制逐帧数据（回放用）。默认开启。</summary>
        public bool RecordFrames { get; set; } = true;
        private float _tickInterval;

        public IReadOnlyList<DroneEntity> Drones => _drones;
        public IReadOnlyList<CloudEntity> Clouds => _clouds;
        public IReadOnlyList<MunitionEntity> Munitions => _munitions;
        public IReadOnlyList<DetectionEntity> DetectionEntities => _detectionEntities;
        public IReadOnlyList<SimEvent> Events => _allEvents;

        public event Action<MunitionEntity>? OnMunitionLaunched;
        public event Action<CloudEntity>? OnCloudGenerated;
        public event Action<DroneEntity>? OnDroneDestroyed;
        public event Action<DroneEntity>? OnDroneReachedTarget;
        public event Action<DroneEntity, ControlZoneEntity>? OnZoneIntruded;
        public event Action<DroneEntity, DetectionEntity>? OnTargetDetected;
        public event Action? OnSimulationEnded;

        private List<DroneEntity> _drones = new();
        private List<PlatformEntity> _platforms = new();
        private List<DetectionEntity> _detectionEntities = new();
        private List<MunitionEntity> _munitions = new();
        private List<CloudEntity> _clouds = new();
        private List<ControlZoneEntity> _zones = new();
        private CombatScene _scene = new();
        private float _disperseHeight;
        private AmmunitionSpec _ammoSpec = new();
        private int _tickRate = 20;
        private readonly List<FireEvent> _fireSchedule = new();
        private int _nextFireIndex;
        private readonly List<SimEvent> _allEvents = new();
        private string _taskId = string.Empty;
        private readonly IDefensePlanner _planner;
        private int _entityCounter;

        // ── GC 优化：预分配复用池 ──
        private readonly List<EntitySnapshot> _snapshotPool = new();
        private readonly List<SimEvent> _frameEventPool = new();
        private readonly SimulationFrameResult _frameResultPool = new();
        private readonly List<int> _removalIndices = new();
        private readonly List<DroneEntity> _flyingDrones = new();

        public SimulationEngine(IScenarioService scenarioService, FrameDataStore frameStore,
            IDamageModel damageModel, IPathProvider paths, IDefensePlanner planner)
        {
            _scenarioService = scenarioService;
            _frameStore = frameStore;
            _damageModel = damageModel;
            _paths = paths;
            _planner = planner;
        }

        public void SetFireSchedule(List<FireEvent> schedule)
        {
            _fireSchedule.Clear();
            _fireSchedule.AddRange(schedule.OrderBy(f => f.FireTime));
            _nextFireIndex = 0;
        }

        public void Initialize(string taskId)
        {
            _taskId = taskId;
            var config = _scenarioService.GetTaskDetail(taskId);
            if (config == null) throw new InvalidOperationException("Task not found");

            _scene = config.Scene;
            _disperseHeight = (float)config.Cloud.DisperseHeight;
            _tickRate = config.Task.TickRate;
            _tickInterval = 1.0f / _tickRate;

            using (var ammoDb = new SQLiteConnection(_paths.GetMainDbPath()))
            {
                _ammoSpec = ammoDb.Table<AmmunitionSpec>()
                    .FirstOrDefault(a => a.AerosolType == config.Cloud.AerosolType);
            }
            if (_ammoSpec == null || _ammoSpec.Id == null)
                _ammoSpec = DefaultData.Load(_paths).Ammunition
                    .First(a => a.AerosolType == config.Cloud.AerosolType);

            _drones.Clear();
            foreach (var target in config.Targets)
            {
                var route = config.Routes.FirstOrDefault(r => r.WaveId == target.WaveId);
                var wps = config.WaypointGroups.GetValueOrDefault(target.WaveId, new List<Waypoint>());
                if (route == null || wps.Count == 0) continue;
                var mode = (FormationMode)route.FormationMode;
                var lateralSpacing = (float)route.LateralSpacing;
                var longSpacing = (float)route.LongitudinalSpacing;
                int latCount = route.LateralCount ?? target.Quantity;
                int longCount = route.LongitudinalCount ?? 1;
                for (int i = 0; i < target.Quantity; i++)
                {
                    int latIdx = i % latCount;
                    int longIdx = i / latCount;
                    _drones.Add(new DroneEntity($"drone_{++_entityCounter}", target.WaveId,
                        target, wps, latIdx, lateralSpacing, longIdx, longSpacing, mode));
                }
            }

            // 平台 ID 从 1 开始，确保与报告映射一致
            _entityCounter = 0;

            _platforms.Clear();
            foreach (var equip in config.Equipment)
                if (equip.EquipmentRole != (int)EquipmentRole.Detection)
                    for (int i = 0; i < equip.Quantity; i++)
                    {
                        int gunCount = equip.GunCount ?? 1;
                        int chPerGun = equip.ChannelsPerGun ?? 1;
                        for (int g = 0; g < gunCount; g++)
                            for (int ch = 0; ch < chPerGun; ch++)
                                _platforms.Add(new PlatformEntity($"plat_{++_entityCounter}", equip));
                    }

            _zones.Clear();
            foreach (var z in config.ControlZones)
                _zones.Add(new ControlZoneEntity(z.Id, z.Name, z.VerticesJson,
                    (float)z.MinAltitude, (float)z.MaxAltitude));

            // 探测设备运行时实体
            _detectionEntities.Clear();
            var detectionSrcs = BuildDetectionSources(config);
            int detIdx = 0;
            foreach (var src in detectionSrcs)
                _detectionEntities.Add(new DetectionEntity($"det_{++detIdx}", src));

            _munitions.Clear();
            _clouds.Clear();
            _allEvents.Clear();
            FrameIndex = 0;
            SimulationTime = 0;
            _entityCounter = 0;
            _nextFireIndex = 0;

            // 自动从 Planner 生成发射计划
            if (_fireSchedule.Count == 0)
            {
                var fireUnits = BuildFireUnits(config);
                var threats = BuildDroneWaves(config);
                if (fireUnits.Count > 0 && threats.Count > 0)
                {
                    var detectionSources = BuildDetectionSources(config);
                    var result = _planner.Plan(fireUnits, threats, _scene, detectionSources);
                    SetFireSchedule(result.Best.MergedSchedule);
                    if (_fireSchedule.Count == 0)
                        _allEvents.Add(new SimEvent
                        {
                            Type = SimEventType.PlanningFailed,
                            OccurredAt = 0,
                            Description = result.Best.Summary,
                        });
                }
            }

            if (RecordFrames)
                _frameStore.BeginRecording(_taskId);
            State = SimulationState.Running;
        }

        public SimulationFrameResult Tick(float deltaTime)
        {
            if (State != SimulationState.Running)
            {
                _frameResultPool.State = State;
                _frameResultPool.FrameIndex = FrameIndex;
                _frameResultPool.SimulationTime = SimulationTime;
                _frameResultPool.EntitySnapshots = null!;
                _frameResultPool.NewEvents = null!;
                return _frameResultPool;
            }

            var scaledDt = deltaTime * TimeScale;
            SimulationTime += scaledDt;
            FrameIndex++;
            _frameEventPool.Clear();

            // 1. 按发射计划执行
            while (_nextFireIndex < _fireSchedule.Count && _fireSchedule[_nextFireIndex].FireTime <= SimulationTime)
            {
                var fe = _fireSchedule[_nextFireIndex++];
                var platform = _platforms.Count > fe.PlatformIndex ? _platforms[fe.PlatformIndex] : null;
                if (platform == null) continue;

                if (platform.PlatformType == Models.PlatformType.AirBased && platform.Ready)
                {
                    // 空基从当前位置直接发射（与地基相同）
                    platform.Release();
                    var m = new MunitionEntity($"mun_{++_entityCounter}",
                        Models.PlatformType.GroundBased,
                        platform.AerosolType ?? Models.AerosolType.InertGas,
                        platform.PosX, platform.PosY, platform.PosZ,
                        fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
                        fe.FireTime, fe.LaunchAngle);
                    _munitions.Add(m);
                    OnMunitionLaunched?.Invoke(m);
                    _frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = fe.FireTime, SourceId = platform.Id, Description = $"空基发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
                }
                else if (platform.Ready)
                {
                    platform.Release();
                    var m = new MunitionEntity($"mun_{++_entityCounter}",
                        platform.PlatformType ?? Models.PlatformType.GroundBased,
                        platform.AerosolType ?? Models.AerosolType.InertGas,
                        platform.PosX, platform.PosY, platform.PosZ,
                        fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
                        fe.FireTime, fe.LaunchAngle);
                    _munitions.Add(m);
                    OnMunitionLaunched?.Invoke(m);
                    _frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = fe.FireTime, SourceId = platform.Id, Description = $"计划发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
                }
            }

            // 2. 弹药飞行 → 云团生成（手动遍历+移除索引，避免 ToList()）
            _removalIndices.Clear();
            for (int i = 0; i < _munitions.Count; i++)
            {
                var m = _munitions[i];
                m.Update(scaledDt);
                if (m.HasArrived)
                {
                    var disp = AlgorithmFactory.Create<ICloudDispersionModel>();
                    disp.Initialize(_ammoSpec, _scene, new Algorithms.Vector3(m.PosX, m.PosY, m.PosZ), m.ArrivalTime);
                    var cloud = new CloudEntity($"cloud_{++_entityCounter}", m.AerosolType, disp, m.ArrivalTime);
                    _clouds.Add(cloud);
                    OnCloudGenerated?.Invoke(cloud);
                    _frameEventPool.Add(new SimEvent { Type = SimEventType.CloudGenerated, OccurredAt = m.ArrivalTime, Description = $"云团生成 @({m.PosX:F0},{m.PosY:F0},{m.PosZ:F0})" });
                    _removalIndices.Add(i);
                }
            }
            for (int i = _removalIndices.Count - 1; i >= 0; i--)
                _munitions.RemoveAt(_removalIndices[i]);

            // 3. 云团演化（手动遍历+移除索引）
            _removalIndices.Clear();
            for (int i = 0; i < _clouds.Count; i++)
            {
                var c = _clouds[i];
                c.Tick(scaledDt, (float)_scene.WindSpeed, (WindDirection)_scene.WindDirection);
                if (c.IsDissipated) _removalIndices.Add(i);
            }
            for (int i = _removalIndices.Count - 1; i >= 0; i--)
                _clouds.RemoveAt(_removalIndices[i]);

            // 4. 无人机：缓存飞行状态列表，避免多次 Where
            _flyingDrones.Clear();
            for (int i = 0; i < _drones.Count; i++)
                if (_drones[i].Status == DroneStatus.Flying)
                    _flyingDrones.Add(_drones[i]);

            for (int i = 0; i < _flyingDrones.Count; i++)
                _flyingDrones[i].SavePreviousPosition();

            for (int i = 0; i < _flyingDrones.Count; i++)
            {
                _flyingDrones[i].Update(scaledDt);
                if (_flyingDrones[i].Status == DroneStatus.ReachedTarget)
                {
                    OnDroneReachedTarget?.Invoke(_flyingDrones[i]);
                    _frameEventPool.Add(new SimEvent { Type = SimEventType.DroneReachedTarget, OccurredAt = SimulationTime, SourceId = _flyingDrones[i].Id, Description = "到达攻击目标" });
                }
            }

            // 5. 实时探测扫描（决策 1/2：离开回退、融合取最早/同刻取精度高）
            if (_detectionEntities.Count > 0)
            {
                float visibility = (float)_scene.Visibility;
                for (int di = 0; di < _flyingDrones.Count; di++)
                {
                    var drone = _flyingDrones[di];
                    DetectionEntity? bestDetector = null;
                    float bestAccuracy = float.MaxValue;

                    for (int ei = 0; ei < _detectionEntities.Count; ei++)
                    {
                        var det = _detectionEntities[ei];
                        bool inRange = det.IsInRange(drone.PosX, drone.PosY, drone.PosZ, visibility, out _);
                        bool? stateChange = det.UpdateState(drone.Id, inRange);

                        if (stateChange == true)
                        {
                            // 决策 2：首次发现，同 tick 取精度最高（Accuracy 最小）
                            if (bestDetector == null || det.Source.Accuracy < bestAccuracy)
                            {
                                bestDetector = det;
                                bestAccuracy = det.Source.Accuracy;
                            }
                        }
                    }

                    if (bestDetector != null)
                    {
                        OnTargetDetected?.Invoke(drone, bestDetector);
                        _frameEventPool.Add(new SimEvent
                        {
                            Type = SimEventType.TargetDetected,
                            OccurredAt = SimulationTime,
                            SourceId = bestDetector.Id,
                            TargetId = drone.Id,
                            Description = $"探测设备 {bestDetector.Id} 发现 drone {drone.Id} @({drone.PosX:F0},{drone.PosY:F0},{drone.PosZ:F0})",
                        });
                    }
                }
            }

            // 6. 毁伤判定：积分路径段在云内的时间（快速排斥：先检查包围盒）
            var (wvx, wvy, wvz) = Kinematics.WindToVector((WindDirection)_scene.WindDirection, (float)_scene.WindSpeed);
            float cloudDx = wvx * scaledDt, cloudDy = wvy * scaledDt, cloudDz = wvz * scaledDt;
            float effectiveConcentration = (float)_ammoSpec.EffectiveConcentration;
            for (int di = 0; di < _flyingDrones.Count; di++)
            {
                var drone = _flyingDrones[di];
                for (int ci = 0; ci < _clouds.Count; ci++)
                {
                    var cloud = _clouds[ci];
                    if (cloud.Dispersion.CoreDensity < effectiveConcentration) continue;
                    // 快速排斥：检查无人机与云团中心的距离是否在 2×有效半径内
                    float effR = cloud.Dispersion.EffectiveRadius;
                    float ccx = cloud.Dispersion.Center.X, ccy = cloud.Dispersion.Center.Y, ccz = cloud.Dispersion.Center.Z;
                    float dx = drone.PosX - ccx, dy = drone.PosY - ccy, dz = drone.PosZ - ccz;
                    float distSq = dx * dx + dy * dy + dz * dz;
                    if (distSq > effR * effR * 4) continue; // 距离 > 2R，不可能穿云
                    float inCloudDistance = DamageAssessment.PathInSphere(
                        drone.PrevX - (ccx - cloudDx), drone.PrevY - (ccy - cloudDy), drone.PrevZ - (ccz - cloudDz),
                        drone.PosX - ccx, drone.PosY - ccy, drone.PosZ - ccz,
                        0f, 0f, 0f, effR);
                    if (inCloudDistance > 0)
                    {
                        float exposureIncrement = inCloudDistance / (drone.CruiseSpeed / 3.6f);
                        drone.ExposureTime += exposureIncrement;
                        var dmg = _damageModel.CalculateDamage(drone.TargetType, drone.PowerType, cloud.AerosolType, cloud.Dispersion.CoreDensity, drone.ExposureTime, exposureIncrement);
                        drone.ApplyDamage(dmg);
                        if (drone.Status == DroneStatus.Destroyed)
                        {
                            OnDroneDestroyed?.Invoke(drone);
                            _frameEventPool.Add(new SimEvent { Type = SimEventType.DroneDestroyed, OccurredAt = SimulationTime, TargetId = drone.Id, Description = $"无人机 {drone.Id} 被摧毁 @({drone.PosX:F0},{drone.PosY:F0},{drone.PosZ:F0})" });
                            break;
                        }
                    }
                }
            }

            // 7. 平台冷却
            for (int i = 0; i < _platforms.Count; i++) _platforms[i].Update(scaledDt);

            // 8. 管控区域
            for (int di = 0; di < _flyingDrones.Count; di++)
            {
                var drone = _flyingDrones[di];
                for (int zi = 0; zi < _zones.Count; zi++)
                {
                    if (_zones[zi].ContainsPoint(drone.PosX, drone.PosY, drone.PosZ))
                    {
                        drone.MarkZoneIntruded();
                        OnZoneIntruded?.Invoke(drone, _zones[zi]);
                        _frameEventPool.Add(new SimEvent { Type = SimEventType.ZoneIntruded, OccurredAt = SimulationTime, SourceId = drone.Id, TargetId = _zones[zi].Id, Description = $"侵入 {_zones[zi].Name}" });
                    }
                }
            }

            // 9. 结束判定
            bool allDone = true;
            for (int i = 0; i < _drones.Count; i++)
                if (_drones[i].Status == DroneStatus.Flying) { allDone = false; break; }
            if (allDone)
            {
                State = SimulationState.Completed;
                OnSimulationEnded?.Invoke();
                _frameEventPool.Add(new SimEvent { Type = SimEventType.SimulationEnd, OccurredAt = SimulationTime });
            }

            _allEvents.AddRange(_frameEventPool);

            if (RecordFrames)
            {
                var snapshots = CollectSnapshots();
                _frameStore.RecordFrame(FrameIndex, SimulationTime, snapshots);
                _frameResultPool.EntitySnapshots = snapshots;
            }
            else
            {
                _frameResultPool.EntitySnapshots = null!;
            }
            _frameResultPool.NewEvents = _frameEventPool;
            _frameResultPool.State = State;
            _frameResultPool.FrameIndex = FrameIndex;
            _frameResultPool.SimulationTime = SimulationTime;
            return _frameResultPool;
        }

        public void Pause() { if (State == SimulationState.Running) State = SimulationState.Paused; }
        public void Resume() { if (State == SimulationState.Paused) State = SimulationState.Running; }
        public void Stop() { State = SimulationState.Stopped; _frameStore.Flush(); }

        private static List<FireUnit> BuildFireUnits(TaskFullConfig config)
        {
            var units = new List<FireUnit>();
            foreach (var eq in config.Equipment.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform))
            {
                int qty = Math.Max(1, eq.Quantity);
                int gunCount = eq.GunCount ?? 1;
                int chPerGun = eq.ChannelsPerGun ?? 1;
                int channels = gunCount * chPerGun;
                for (int i = 0; i < qty; i++)
                {
                    units.Add(new FireUnit
                    {
                        Id = $"fu{units.Count}",
                        Type = (PlatformType)(eq.PlatformType ?? (int)PlatformType.GroundBased),
                        Position = new Algorithms.Vector3((float)eq.PositionX + i * 50, (float)eq.PositionY, (float)eq.PositionZ),
                        GunCount = gunCount,
                        ChannelsPerGun = chPerGun,
                        ChannelInterval = (float)(eq.ChannelInterval ?? 1),
                        CruiseSpeed = (float)(eq.CruiseSpeed ?? 0f),
                        ReleaseAltitude = (float)(eq.ReleaseAltitude ?? 0f),
                        MuzzleVelocity = (float)(eq.MuzzleVelocity ?? 0f),
                        TotalMunitions = eq.MunitionCount ?? channels,
                        AmmoTypes = new List<AerosolType> { (AerosolType)(eq.AerosolType ?? 0) },
                        Cooldown = (float)eq.Cooldown,
                        // 探测能力（火力单元自带探测，激活原死字段）
                        RadarRange = (float)(eq.RadarRange ?? 0f),
                        EORange = (float)(eq.EORange ?? 0f),
                        IRRange = (float)(eq.IRRange ?? 0f),
                    });
                }
            }
            return units;
        }

        /// <summary>构建统一信息网络的探测源列表。
        /// 独立探测设备（EquipmentRole.Detection）+ 火力单元自带探测能力。</summary>
        private static List<DetectionSource> BuildDetectionSources(TaskFullConfig config)
        {
            var sources = new List<DetectionSource>();
            foreach (var eq in config.Equipment)
            {
                // 只要有任何探测字段非 null 且 > 0，就是有效探测源（无论是否独立探测设备）
                bool hasDetection = (eq.RadarRange ?? 0) > 0 || (eq.EORange ?? 0) > 0 || (eq.IRRange ?? 0) > 0;
                if (!hasDetection) continue;
                int qty = Math.Max(1, eq.Quantity);
                for (int i = 0; i < qty; i++)
                {
                    sources.Add(new DetectionSource
                    {
                        Position = new Algorithms.Vector3((float)eq.PositionX + i * 50, (float)eq.PositionY, (float)eq.PositionZ),
                        RadarRange = (float)(eq.RadarRange ?? 0f),
                        EORange = (float)(eq.EORange ?? 0f),
                        IRRange = (float)(eq.IRRange ?? 0f),
                        Accuracy = (float)(eq.DetectionAccuracy ?? 0f),
                        // 3D 球冠几何：缺失时退化为无限制（等价 2D），保证存量数据平滑过渡
                        MinElevation = (float)(eq.MinElevation ?? float.MaxValue),
                        MaxElevation = (float)(eq.MaxElevation ?? float.MaxValue),
                        MinDetectAlt = (float)(eq.MinDetectAlt ?? float.MaxValue),
                        MaxDetectAlt = (float)(eq.MaxDetectAlt ?? float.MaxValue),
                    });
                }
            }
            return sources;
        }

        private static List<DroneWave> BuildDroneWaves(TaskFullConfig config)
        {
            var groups = new List<DroneWave>();
            foreach (var t in config.Targets)
            {
                var route = config.Routes.FirstOrDefault(r => r.WaveId == t.WaveId);
                var wps = config.WaypointGroups.GetValueOrDefault(t.WaveId, new List<Waypoint>());
                groups.Add(new DroneWave
                {
                    WaveId = t.WaveId,
                    Target = t,
                    Route = route ?? new RoutePlan(),
                    Waypoints = wps,
                });
            }
            return groups;
        }

        private List<EntitySnapshot> CollectSnapshots()
        {
            _snapshotPool.Clear();
            for (int i = 0; i < _drones.Count; i++)
            {
                var d = _drones[i];
                _snapshotPool.Add(new EntitySnapshot { EntityId = d.Id, EntityType = Models.EntityType.Drone, PosX = d.PosX, PosY = d.PosY, PosZ = d.PosZ, DamageStage = (int)_damageModel.GetDamageStage(1 - d.Hp), Hp = d.Hp });
            }
            for (int i = 0; i < _platforms.Count; i++)
            {
                var p = _platforms[i];
                if (p.PlatformType != Models.PlatformType.AirBased) continue;
                _snapshotPool.Add(new EntitySnapshot { EntityId = p.Id, EntityType = Models.EntityType.Platform, PosX = p.PosX, PosY = p.PosY, PosZ = p.PosZ, PlatformStateStr = p.State.ToString() });
            }
            for (int i = 0; i < _clouds.Count; i++)
            {
                var c = _clouds[i];
                _snapshotPool.Add(new EntitySnapshot { EntityId = c.Id, EntityType = Models.EntityType.Cloud, PosX = c.Dispersion.Center.X, PosY = c.Dispersion.Center.Y, PosZ = c.Dispersion.Center.Z, CloudRadius = c.Dispersion.Radius, CloudOpacity = c.Dispersion.Particles.Opacity, CloudPhase = c.Dispersion.Phase, CloudElapsed = c.Dispersion.Elapsed });
            }
            return _snapshotPool;
        }
    }
}
