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

namespace CounterDrone.Core.Tests
{
    /// <summary>边界场景测试</summary>
    public class EdgeCaseTests : IDisposable
    {
        private readonly string _testDir;
        private readonly IScenarioService _scenario;
        private readonly SQLite.SQLiteConnection _db;
        private string _taskId = string.Empty;

        public EdgeCaseTests()
        {
            _testDir = Path.Combine(Path.GetTempPath(), $"cd_edge_{Guid.NewGuid():N}");
            var paths = new TestPathProvider(_testDir);
            var dbm = new DatabaseManager(paths);
            _db = dbm.OpenMainDb();
            foreach (var a in DefaultAmmunition.GetAll()) _db.Insert(a);

            _scenario = new ScenarioService(
                new SimTaskRepository(_db), new CombatSceneRepository(_db),
                new ControlZoneRepository(_db), new TargetConfigRepository(_db),
                new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db),
                new RoutePlanRepository(_db), new WaypointRepository(_db));
        }

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

        [Fact]
        public void EmptyDeployment_EngineRunsWithoutCrash()
        {
            var task = _scenario.CreateTask("空部署", "");
            _taskId = task.Id;

            _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 });
            _scenario.SaveTarget(_taskId, new TargetConfig
            {
                GroupId = "default",
                TargetType = (int)TargetType.Piston,
                Quantity = 1,
                TypicalSpeed = 100,
                TypicalAltitude = 300,
            });
            _scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
            _scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
            _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
                new List<Waypoint>
                {
                    new Waypoint { PosX = 0, PosY = 300, PosZ = 0 },
                    new Waypoint { PosX = 1000, PosY = 300, PosZ = 0 },
                });

            var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
                new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
            engine.Initialize(_taskId);
            engine.TimeScale = 4f;

            for (int i = 0; i < 500; i++)
            {
                var r = engine.Tick(1f / 20f);
                if (r.State == SimulationState.Completed) break;
            }
            engine.Stop();

            Assert.Equal(DroneStatus.ReachedTarget, engine.Drones[0].Status);
        }

        [Fact]
        public void ExtremeWind_DroneStillFlies()
        {
            var task = _scenario.CreateTask("飓风", "");
            _taskId = task.Id;

            _scenario.SaveScene(_taskId, new CombatScene
            {
                WindSpeed = 30, // 最大风速
                WindDirection = (int)WindDirection.E,
            });
            _scenario.SaveTarget(_taskId, new TargetConfig
            {
                GroupId = "default",
                TargetType = (int)TargetType.Piston,
                Quantity = 1,
                TypicalSpeed = 600, // 高速对抗强风
            });
            _scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
            _scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
            _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
                new List<Waypoint>
                {
                    new Waypoint { PosX = 0, PosY = 300, PosZ = 0 },
                    new Waypoint { PosX = 5000, PosY = 300, PosZ = 0 },
                });

            var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
                new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
            engine.Initialize(_taskId);
            engine.TimeScale = 4f;

            for (int i = 0; i < 500; i++)
            {
                var r = engine.Tick(1f / 20f);
                if (r.State == SimulationState.Completed) break;
            }
            engine.Stop();

            // 强风下应偏移到东方（+X）
            Assert.True(engine.Drones[0].PosX > 0);
        }

        [Fact]
        public void LongRoute_CompletesWithoutError()
        {
            var task = _scenario.CreateTask("超长航路", "");
            _taskId = task.Id;

            _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 });
            _scenario.SaveTarget(_taskId, new TargetConfig
            {
                GroupId = "default",
                TargetType = (int)TargetType.HighSpeed,
                Quantity = 1,
                TypicalSpeed = 500,
            });
            _scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
            _scenario.SaveCloudDispersal(_taskId, new CloudDispersal());

            // 500 km/h, 100km 航程
            _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
                new List<Waypoint>
                {
                    new Waypoint { PosX = 0, PosY = 500, PosZ = 0 },
                    new Waypoint { PosX = 100000, PosY = 500, PosZ = 0 },
                });

            var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
                new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
            engine.Initialize(_taskId);
            engine.TimeScale = 4f;

            for (int i = 0; i < 5000; i++)
            {
                var r = engine.Tick(1f / 20f);
                if (r.State == SimulationState.Completed) break;
            }
            engine.Stop();

            Assert.Equal(DroneStatus.ReachedTarget, engine.Drones[0].Status);
        }
    }
}
