using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using CounterDrone.Core.Models;
using CounterDrone.Core.Repository;

namespace CounterDrone.Core.Services
{
    public class ScenarioService : IScenarioService
    {
        private readonly ScenarioRepository _scenarioRepo;
        private readonly CombatSceneRepository _sceneRepo;
        private readonly ControlZoneRepository _zoneRepo;
        private readonly ScenarioDroneRepository _droneRepo;
        private readonly ScenarioUnitRepository _unitRepo;
        private readonly CloudDispersalRepository _cloudRepo;
        private readonly RoutePlanRepository _routeRepo;
        private readonly WaypointRepository _waypointRepo;

        public ScenarioService(
            ScenarioRepository scenarioRepo,
            CombatSceneRepository sceneRepo,
            ControlZoneRepository zoneRepo,
            ScenarioDroneRepository targetRepo,
            ScenarioUnitRepository equipRepo,
            CloudDispersalRepository cloudRepo,
            RoutePlanRepository routeRepo,
            WaypointRepository waypointRepo)
        {
            _scenarioRepo = scenarioRepo;
            _sceneRepo = sceneRepo;
            _zoneRepo = zoneRepo;
            _droneRepo = targetRepo;
            _unitRepo = equipRepo;
            _cloudRepo = cloudRepo;
            _routeRepo = routeRepo;
            _waypointRepo = waypointRepo;
        }

        // ========== scenario CRUD ==========

        public Scenario CreateScenario(string name, string ScenarioNumber)
        {
            if (string.IsNullOrWhiteSpace(name))
                throw new ArgumentException("任务名称不能为空");

            if (string.IsNullOrWhiteSpace(ScenarioNumber))
                ScenarioNumber = GenerateScenarioNumber();

            var existing = _scenarioRepo.GetByScenarioNumber(ScenarioNumber);
            if (existing != null)
                throw new ArgumentException($"任务编号 {ScenarioNumber} 已存在");

            var scenario = new Scenario
            {
                Name = name,
                ScenarioNumber = ScenarioNumber,
                Status = (int)ScenarioStatus.Configuring,
                CurrentStep = 1,
            };

            _scenarioRepo.Insert(scenario);
            return scenario;
        }

        public void DeleteScenario(string id)
        {
            _scenarioRepo.Delete(id);
        }

        public PagedResult<Scenario> SearchScenarios(string keyword, string? dateFrom, string? dateTo, int page, int pageSize)
        {
            if (page < 1) page = 1;
            if (pageSize < 1) pageSize = 10;
            var offset = (page - 1) * pageSize;

            var items = _scenarioRepo.Search(keyword, dateFrom, dateTo, offset, pageSize, out var total);

            return new PagedResult<Scenario>
            {
                Items = items,
                TotalCount = total,
                Page = page,
                PageSize = pageSize,
            };
        }

        public ScenarioConfig? GetScenarioDetail(string id)
        {
            var scenario = _scenarioRepo.GetById(id);
            if (scenario == null) return null;

            return new ScenarioConfig
            {
                Info = scenario,
                Scene = _sceneRepo.GetById(id) ?? new CombatScene { ScenarioId = id },
                ControlZones = _zoneRepo.GetByScenarioId(id),
                Drones = _droneRepo.GetByScenarioId(id),
                Units = _unitRepo.GetByScenarioId(id),
                Cloud = _cloudRepo.GetById(id) ?? new CloudDispersal { ScenarioId = id },
                Routes = _routeRepo.GetByScenarioId(id),
                WaypointGroups = _waypointRepo.GetByScenarioId(id)
                    .GroupBy(w => w.WaveId)
                    .ToDictionary(g => g.Key, g => g.OrderBy(w => w.OrderIndex).ToList()),
            };
        }

        // ========== Step Save ==========

        public void SaveScene(string scenarioId, CombatScene scene)
        {
            scene.ScenarioId = scenarioId;
            var existing = _sceneRepo.GetById(scenarioId);
            if (existing != null)
                _sceneRepo.Update(scene);
            else
                _sceneRepo.Insert(scene);
            TouchScenario(scenarioId);
        }

        public void SaveControlZones(string scenarioId, List<ControlZone> zones)
        {
            _zoneRepo.DeleteByScenarioId(scenarioId);
            for (int i = 0; i < zones.Count; i++)
            {
                zones[i].ScenarioId = scenarioId;
                zones[i].OrderIndex = i;
            }
            _zoneRepo.InsertAll(zones);
            TouchScenario(scenarioId);
        }

        public ScenarioDrone SaveScenarioDrone(string scenarioId, ScenarioDrone target)
        {
            target.ScenarioId = scenarioId;
            if (string.IsNullOrEmpty(target.Id))
                target.Id = Guid.NewGuid().ToString();

            var existing = _droneRepo.GetById(target.Id);
            if (existing != null)
                _droneRepo.Update(target);
            else
                _droneRepo.Insert(target);
            TouchScenario(scenarioId);
            return target;
        }

        public void SaveDeployment(string scenarioId, List<ScenarioUnit> equips)
        {
            _unitRepo.DeleteByScenarioId(scenarioId);
            foreach (var e in equips)
            {
                e.ScenarioId = scenarioId;
                if (string.IsNullOrEmpty(e.Id))
                    e.Id = Guid.NewGuid().ToString();
            }
            _unitRepo.InsertAll(equips);
            TouchScenario(scenarioId);
        }

        public void AddDetection(string scenarioId, ScenarioUnit detection)
        {
            detection.ScenarioId = scenarioId;
            detection.EquipmentRole = (int)EquipmentRole.Detection;
            if (string.IsNullOrEmpty(detection.Id))
                detection.Id = Guid.NewGuid().ToString();
            _unitRepo.Insert(detection);
            TouchScenario(scenarioId);
        }

        public void DeleteDetection(string detectionId)
        {
            _unitRepo.Delete(detectionId);
        }

        public List<ScenarioUnit> GetDetections(string scenarioId)
        {
            return _unitRepo.GetByScenarioIdAndRole(scenarioId, (int)EquipmentRole.Detection);
        }

        public void SaveCloudDispersal(string scenarioId, CloudDispersal cloud)
        {
            cloud.ScenarioId = scenarioId;
            var existing = _cloudRepo.GetById(scenarioId);
            if (existing != null)
                _cloudRepo.Update(cloud);
            else
                _cloudRepo.Insert(cloud);
            TouchScenario(scenarioId);
        }

        public void SaveRoute(string scenarioId, string waveId, RoutePlan route, List<Waypoint> waypoints)
        {
            route.ScenarioId = scenarioId;
            route.WaveId = waveId;
            var existing = _routeRepo.GetByScenarioAndWave(scenarioId, waveId);
            if (existing != null)
            {
                route.Id = existing.Id;
                _routeRepo.Update(route);
            }
            else
                _routeRepo.Insert(route);

            // 删除该批次的旧航路点，插入新的
            var oldWps = _waypointRepo.GetByScenarioAndWave(scenarioId, waveId);
            foreach (var w in oldWps) _waypointRepo.Delete(w.Id);
            for (int i = 0; i < waypoints.Count; i++)
            {
                waypoints[i].ScenarioId = scenarioId;
                waypoints[i].WaveId = waveId;
                waypoints[i].OrderIndex = i;
                if (string.IsNullOrEmpty(waypoints[i].Id))
                    waypoints[i].Id = Guid.NewGuid().ToString();
            }
            _waypointRepo.InsertAll(waypoints);
            TouchScenario(scenarioId);
        }

        public void UpdateStep(string scenarioId, int step)
        {
            var scenario = _scenarioRepo.GetById(scenarioId);
            if (scenario == null) return;

            if (step < 1) step = 1;
            if (step > 5) step = 5;

            scenario.CurrentStep = step;
            _scenarioRepo.Update(scenario);
        }

        public EnumMetadata GetEnums()
        {
            return new EnumMetadata
            {
                DroneType = EnumToList<Models.DroneType>(TranslateDrone),
                PowerType = EnumToList<Models.PowerType>(TranslatePower),
                PlatformType = EnumToList<Models.PlatformType>(TranslatePlatform),
                AerosolType = EnumToList<Models.AerosolType>(TranslateAerosol),
                WeatherType = EnumToList<Models.WeatherType>(TranslateWeather),
                WindDirection = EnumToList<Models.WindDirection>(TranslateWindDirection),
                SceneType = EnumToList<Models.SceneType>(TranslateScene),
                FormationMode = EnumToList<Models.FormationMode>(TranslateFormation),
                TriggerMode = EnumToList<Models.TriggerMode>(TranslateTrigger),
                ReleaseMode = EnumToList<Models.ReleaseMode>(TranslateRelease),
                EquipmentRole = EnumToList<Models.EquipmentRole>(TranslateEquipmentRole),
                EntityType = EnumToList<Models.EntityType>(TranslateEntityType),
            };
        }

        private static List<EnumItem> EnumToList<T>(Func<T, string> translate) where T : Enum
        {
            var list = new List<EnumItem>();
            foreach (T v in Enum.GetValues(typeof(T)))
                list.Add(new EnumItem { Name = v.ToString(), ChineseName = translate(v), Value = Convert.ToInt32(v) });
            return list;
        }

        private static Dictionary<string, int> EnumToDict<T>() where T : Enum
        {
            var dict = new Dictionary<string, int>();
            foreach (T v in Enum.GetValues(typeof(T)))
                dict[v.ToString()] = Convert.ToInt32(v);
            return dict;
        }

        // ═══ 中文翻译 ═══
        private static string TranslateDrone(Models.DroneType t) => t switch
        {
            Models.DroneType.Rotor => "旋翼",
            Models.DroneType.FixedWing => "固定翼",
            Models.DroneType.HighSpeed => "高速目标",
            _ => t.ToString(),
        };
        private static string TranslatePower(Models.PowerType p) => p switch
        {
            Models.PowerType.Electric => "电推",
            Models.PowerType.Piston => "活塞",
            Models.PowerType.Jet => "喷气",
            _ => p.ToString(),
        };
        private static string TranslatePlatform(Models.PlatformType p) => p switch
        {
            Models.PlatformType.AirBased => "空基",
            Models.PlatformType.GroundBased => "地基",
            _ => p.ToString(),
        };
        private static string TranslateAerosol(Models.AerosolType t) => t switch
        {
            Models.AerosolType.InertGas => "惰性气体(吸入式灭火)",
            Models.AerosolType.ActiveMaterial => "活性材料(爆燃式)",
            Models.AerosolType.ActiveFuel => "活性燃料(吸入式爆炸)",
            _ => t.ToString(),
        };
        private static string TranslateWeather(Models.WeatherType w) => w switch
        {
            Models.WeatherType.Sunny => "晴天",
            Models.WeatherType.Overcast => "阴天",
            Models.WeatherType.Fog => "雾天",
            Models.WeatherType.Rain => "雨天",
            Models.WeatherType.Night => "夜间",
            _ => w.ToString(),
        };
        private static string TranslateWindDirection(Models.WindDirection d) => d switch
        {
            Models.WindDirection.N => "北 (N)",
            Models.WindDirection.NE => "东北 (NE)",
            Models.WindDirection.E => "东 (E)",
            Models.WindDirection.SE => "东南 (SE)",
            Models.WindDirection.S => "南 (S)",
            Models.WindDirection.SW => "西南 (SW)",
            Models.WindDirection.W => "西 (W)",
            Models.WindDirection.NW => "西北 (NW)",
            _ => d.ToString(),
        };
        private static string TranslateScene(Models.SceneType s) => s switch
        {
            Models.SceneType.Urban => "城市",
            Models.SceneType.Plain => "平原",
            Models.SceneType.Mountain => "山区",
            Models.SceneType.Coast => "海岸",
            _ => s.ToString(),
        };
        private static string TranslateFormation(Models.FormationMode f) => f switch
        {
            Models.FormationMode.Single => "单机",
            Models.FormationMode.Formation => "编队",
            Models.FormationMode.Swarm => "蜂群",
            _ => f.ToString(),
        };
        private static string TranslateTrigger(Models.TriggerMode t) => t switch
        {
            Models.TriggerMode.Time => "时间触发",
            Models.TriggerMode.Area => "区域触发",
            Models.TriggerMode.Manual => "手动触发",
            _ => t.ToString(),
        };
        private static string TranslateRelease(Models.ReleaseMode r) => r switch
        {
            Models.ReleaseMode.Single => "单次",
            Models.ReleaseMode.Continuous => "连续",
            Models.ReleaseMode.Pulse => "脉冲",
            _ => r.ToString(),
        };
        private static string TranslateEquipmentRole(Models.EquipmentRole r) => r switch
        {
            Models.EquipmentRole.Detection => "探测设备",
            Models.EquipmentRole.LaunchPlatform => "发射平台",
            _ => r.ToString(),
        };

        private static string TranslateEntityType(Models.EntityType t) => t switch
        {
            Models.EntityType.Drone => "无人机",
            Models.EntityType.Platform => "发射平台",
            Models.EntityType.DetectionEquip => "探测设备",
            Models.EntityType.Cloud => "云团",
            Models.EntityType.Munition => "弹药",
            _ => t.ToString(),
        };

        // ========== Scenario CRUD ==========

        public Scenario UpdateScenario(Scenario scenario)
        {
            var existing = _scenarioRepo.GetById(scenario.Id);
            if (existing == null)
                throw new ArgumentException($"想定 {scenario.Id} 不存在");
            scenario.UpdatedAt = DateTime.UtcNow.ToString("o");
            _scenarioRepo.Update(scenario);
            return scenario;
        }

        // ========== CombatScene ==========

        public CombatScene GetScene(string scenarioId)
        {
            return _sceneRepo.GetById(scenarioId) ?? new CombatScene { ScenarioId = scenarioId };
        }

        // ========== ControlZone ==========

        public List<ControlZone> GetControlZones(string scenarioId)
            => _zoneRepo.GetByScenarioId(scenarioId);

        public void DeleteControlZone(string id)
            => _zoneRepo.Delete(id);

        // ========== ScenarioDrone ==========

        public ScenarioDrone AddScenarioDrone(string scenarioId, ScenarioDrone drone)
            => SaveScenarioDrone(scenarioId, drone);

        public void UpdateScenarioDrone(ScenarioDrone drone)
        {
            _droneRepo.Update(drone);
            TouchScenario(drone.ScenarioId);
        }

        public void DeleteScenarioDrone(string id)
            => _droneRepo.Delete(id);

        public List<ScenarioDrone> GetScenarioDrones(string scenarioId)
            => _droneRepo.GetByScenarioId(scenarioId);

        // ========== ScenarioUnit ==========

        public ScenarioUnit AddDeploymentUnit(string scenarioId, ScenarioUnit unit)
        {
            unit.ScenarioId = scenarioId;
            if (string.IsNullOrEmpty(unit.Id))
                unit.Id = Guid.NewGuid().ToString();
            _unitRepo.Insert(unit);
            TouchScenario(scenarioId);
            return unit;
        }

        public void UpdateDeploymentUnit(ScenarioUnit unit)
            => _unitRepo.Update(unit);

        public void DeleteDeploymentUnit(string id)
            => _unitRepo.Delete(id);

        public List<ScenarioUnit> GetDeploymentUnits(string scenarioId)
            => _unitRepo.GetByScenarioId(scenarioId);

        // ========== CloudDispersal ==========

        public CloudDispersal GetCloudDispersal(string scenarioId)
            => _cloudRepo.GetById(scenarioId) ?? new CloudDispersal { ScenarioId = scenarioId };

        public void DeleteCloudDispersal(string scenarioId)
            => _cloudRepo.Delete(scenarioId);

        // ========== Route & Waypoint ==========

        public List<RoutePlan> GetRoutes(string scenarioId)
            => _routeRepo.GetByScenarioId(scenarioId);

        public void DeleteRoute(string id)
        {
            var r = _routeRepo.GetById(id);
            if (r == null) return;
            var wps = _waypointRepo.GetByScenarioAndWave(r.ScenarioId, r.WaveId);
            foreach (var w in wps) _waypointRepo.Delete(w.Id);
            _routeRepo.Delete(id);
        }

        public List<Waypoint> GetWaypoints(string scenarioId)
            => _waypointRepo.GetByScenarioId(scenarioId);

        public List<Waypoint> GetWaypointsByWave(string scenarioId, string waveId)
            => _waypointRepo.GetByScenarioAndWave(scenarioId, waveId);

        public void DeleteWaypoint(string id)
            => _waypointRepo.Delete(id);

        // ========== Helpers ==========

        private void TouchScenario(string scenarioId)
        {
            var scenario = _scenarioRepo.GetById(scenarioId);
            if (scenario != null)
            {
                scenario.UpdatedAt = DateTime.UtcNow.ToString("o");
                _scenarioRepo.Update(scenario);
            }
        }

        private static int _counter;

        public static string GenerateScenarioNumber()
        {
            var now = DateTime.Now;
            var datePart = now.ToString("yyyyMMdd");
            var seq = Interlocked.Increment(ref _counter);
            return $"SIM-{datePart}-{seq:D3}";
        }
    }
}
