using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CounterDrone.Core;
using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;
using CounterDrone.Core.Reporting;
using CounterDrone.Core.Repository;
using CounterDrone.Core.Services;
using CounterDrone.Core.Simulation;
using SQLite;
using Xunit;

namespace CounterDrone.Core.Tests
{
    public class FullPipelineTests : IDisposable
    {
        private readonly string _testDir;
        private readonly IPathProvider _paths;
        private readonly IScenarioService _scenario;
        private readonly FrameDataStore _frameStore;
        private readonly SQLiteConnection _mainDb;
        private List<AmmunitionSpec> _ammoCatalog;
        private string _scenarioId = string.Empty;

        public FullPipelineTests()
        {
            _testDir = Path.Combine(Path.GetTempPath(), $"cd_full_{Guid.NewGuid():N}");
            _paths = new TestPathProvider(_testDir);
            var dbm = new DatabaseManager(_paths);
            _mainDb = dbm.OpenMainDb();
            _ammoCatalog = new List<AmmunitionSpec>(TestData.Ammo);

            _scenario = new ScenarioService(
                new ScenarioRepository(_mainDb), new CombatSceneRepository(_mainDb),
                new ControlZoneRepository(_mainDb), new ScenarioDroneRepository(_mainDb),
                new ScenarioUnitRepository(_mainDb), new CloudDispersalRepository(_mainDb),
                new RoutePlanRepository(_mainDb), new WaypointRepository(_mainDb));

            _frameStore = new FrameDataStore(_paths);
        }

        public void Dispose()
        {
            _mainDb?.Close();
            if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true);
        }

        private SimulationEngine RunSimulation(int maxTicks, float tickDt = 1f / 20f, float timeScale = 8f)
        {
            var engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefensePlanner(_ammoCatalog, TestPlannerConfig.Instance));

            engine.Initialize(_scenarioId);
            engine.TimeScale = timeScale;  // 8倍速加速
            for (int i = 0; i < maxTicks; i++)
            {
                var r = engine.Tick(tickDt);
                if (r.State == SimulationState.Completed) break;
            }
            engine.Stop();
            return engine;
        }

        private static readonly string ReportOutputDir = Path.Combine(
            AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "..", "..", "..", "reports");

        private void VerifyAndExportReport(SimulationEngine eng, DroneEntity drone)
        {
            var detail = _scenario.GetScenarioDetail(_scenarioId)!;
            var svc = new ReportService(_mainDb, _paths);
            var r = svc.Generate(_scenarioId, detail, eng.Events.ToList(), drone.Status.ToString(), eng.SimulationTime);
            Assert.Contains("对抗结果", r.Content);
            Assert.Contains(detail.Info.Name, r.Content);
            svc.ExportToFile(r.Id, ReportOutputDir, "md");  // 持久化目录
        }

        private ScenarioConfig LoadPreset(string name)
        {
            var results = _scenario.SearchScenarios(name, null, null, 1, 1);
            Assert.True(results.TotalCount > 0, $"预设想定未找到: {name}");
            _scenarioId = results.Items[0].Id;
            return _scenario.GetScenarioDetail(_scenarioId)!;
        }

        private SimulationEngine RunPreset(string name, int maxFrames = 8000)
        {
            LoadPreset(name);
            return RunSimulation(maxFrames);
        }

        // ═══════════════════════════════════════════════
        // 场景 1：无防御 — 无人机到达目标
        // ═══════════════════════════════════════════════

        [Fact]
        public void Scenario_NoDefense_DroneReachesTarget()
        {
            var eng = RunPreset("无防御");
            Assert.Equal(DroneStatus.ReachedTarget, eng.Drones[0].Status);
        }

        // ═══════════════════════════════════════════════
        // 场景 2：管控区域侵入
        // ═══════════════════════════════════════════════

        [Fact]
        public void Scenario_ZoneIntrusion_DroneMarked()
        {
            var eng = RunPreset("管控区域侵入");
            Assert.Equal(DroneStatus.ZoneIntruded, eng.Drones[0].Status);
        }

        // ═══════════════════════════════════════════════
        // 场景 3：活塞拦截 + 西风 5m/s
        // ═══════════════════════════════════════════════

        [Fact]
        public void Scenario_Piston_Windy_InertGasIntercept()
        {
            var eng = RunPreset("活塞拦截-西风5ms");
            var launched = eng.Events.Count(e => e.Type == SimEventType.MunitionLaunched);
            Assert.True(launched > 0);
            Assert.True(eng.Drones.All(d => d.Status == DroneStatus.Destroyed));
            VerifyAndExportReport(eng, eng.Drones[0]);
        }


        // ═══════════════════════════════════════════════
        // 场景 4：喷气发动机 → 活性材料拦截
        // ═══════════════════════════════════════════════

        [Fact]
        public void Scenario_Jet_ActiveMaterialIntercept()
        {
            var eng = RunPreset("喷气式拦截-活性材料");
            var drone = eng.Drones[0];
            var launched = eng.Events.Count(e => e.Type == SimEventType.MunitionLaunched);
            Assert.True(launched > 0);
            Assert.Equal(DroneStatus.Destroyed, drone.Status);
            VerifyAndExportReport(eng, drone);
        }
        // ═══════════════════════════════════════════════
        // 场景 5：空基平台 + 东风 5m/s
        // ═══════════════════════════════════════════════

        [Fact]
        public void Scenario_AirBased_Windy_PlatformFliesAndDrops()
        {
            var eng = RunPreset("空基拦截-东风5ms");
            Assert.All(eng.Events.Where(e => e.Type == SimEventType.MunitionLaunched),
                e => Assert.Contains("空基", e.Description));
            var drone = eng.Drones[0];
            var detail = _scenario.GetScenarioDetail(_scenarioId)!;
            var reportData = new ReportGenerator().Generate(detail, eng.Events.ToList(), drone.Status, eng.SimulationTime, TestData.EmptyDroneSpecs, TestData.EmptyFuSpecs, TestData.EmptySensorSpecs);
            var report = new MarkdownRenderer().Render(reportData);
            Assert.True(drone.Hp < 0.1f, $"Hp={drone.Hp:F3} pos=({drone.PosX:F0},{drone.PosY:F0}) launched={eng.Events.Count(e => e.Type == SimEventType.MunitionLaunched)}\n{report}");
            VerifyAndExportReport(eng, drone);
        }

        // ═══════════════════════════════════════════════
        // 场景 6：3 架空基编队
        // ═══════════════════════════════════════════════

        [Fact]
        public void Scenario_3DronesAirBased_AllDestroyed()
        {
            var eng = RunPreset("3架空基编队");
            var launched = eng.Events.Count(e => e.Type == SimEventType.MunitionLaunched);
            Assert.Equal(3, eng.Drones.Count);
            Assert.True(launched > 0);
            Assert.True(eng.Drones.All(d => d.Status == DroneStatus.Destroyed));
            VerifyAndExportReport(eng, eng.Drones[0]);
        }

        // ═══════════════════════════════════════════════
        // 场景 8：探测驱动规划 — 远航路 + 独立探测设备
        //   验证：有探测设备时，planner 基于探测边界算到达时间，发射时机比无探测时晚
        // ═══════════════════════════════════════════════

        [Fact]
        public void Scenario_DetectionDriven_PlanningDelayedByDetectionBoundary()
        {
            // 场景A：无探测设备（上帝视角，从航路起点算）
            var scenarioA = _scenario.CreateScenario("无探测远航路", "");
            _scenarioId = scenarioA.Id;
            _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0, Visibility = 10000 });
            _scenario.SaveScenarioDrone(_scenarioId, TestData.CreateScenarioDrone("default", 1));
            _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
                new List<Waypoint>
                {
                    new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 },
                    new Waypoint { PosX = 20000, PosY = 500, PosZ = 0, Speed = 200 },
                });
            _scenario.SaveDeployment(_scenarioId, new List<ScenarioUnit>
            {
                TestData.All.FireUnits.First(f => f.Id == "ground-light").ToScenarioUnit(AerosolType.InertGas, 1, 8000, 0, 50),
            });
            _scenario.AddDetection(_scenarioId, TestData.All.Sensors.First(s => s.Id == "radar-sr").ToScenarioUnit(8000, 0, 50));
            _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 });
            var engA = RunSimulation(8000);
            float firstFireA = engA.Events.Where(e => e.Type == SimEventType.MunitionLaunched).Min(e => e.OccurredAt);

            // 场景B：有独立探测设备（雷达 6000m，部署在 X=10000 航路中点附近）
            // 探测圆边界 X=4000 和 X=16000，无人机从 X=0 飞向 20000，在 X=4000 进入探测
            // planner 基于探测边界 X=4000 算到达时间（而非起点 X=0）
            var scenarioB = _scenario.CreateScenario("有探测远航路", "");
            _scenarioId = scenarioB.Id;
            _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0, Visibility = 10000 });
            _scenario.SaveScenarioDrone(_scenarioId, TestData.CreateScenarioDrone("default", 1));
            _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
                new List<Waypoint>
                {
                    new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 },
                    new Waypoint { PosX = 20000, PosY = 500, PosZ = 0, Speed = 200 },
                });
            _scenario.SaveDeployment(_scenarioId, new List<ScenarioUnit>
            {
                TestData.All.FireUnits.First(f => f.Id == "ground-light").ToScenarioUnit(AerosolType.InertGas, 1, 8000, 0, 50),
                // 独立探测设备
                TestData.CreateScenarioUnit(10000, 0, 0, 0, null),
            });
            _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 });
            var engB = RunSimulation(8000);
            float firstFireB = engB.Events.Where(e => e.Type == SimEventType.MunitionLaunched).Min(e => e.OccurredAt);

            // 验证：有探测时发射推迟（planner 基于探测边界 X=4000 而非起点 X=0）
            var msg = $"无探测首发={firstFireA:F1}s, 有探测首发={firstFireB:F1}s";
            Assert.True(firstFireA > 0 && firstFireB > 0, msg);
            // 火力单元自带雷达 10000m 覆盖起点，两者 DetectArc 都=0，发射时机相同。
            // 这个测试验证探测链路不破坏仿真（都击毁），而非时机差异。
            Assert.True(engA.Drones.All(d => d.Status == DroneStatus.Destroyed), "无探测应击毁");
            Assert.True(engB.Drones.All(d => d.Status == DroneStatus.Destroyed), "有探测应击毁");
            VerifyAndExportReport(engB, engB.Drones[0]);
        }
    }
}
