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 SimTaskRepository _taskRepo;
        private readonly CombatSceneRepository _sceneRepo;
        private readonly ControlZoneRepository _zoneRepo;
        private readonly TargetConfigRepository _targetRepo;
        private readonly EquipmentDeploymentRepository _equipRepo;
        private readonly CloudDispersalRepository _cloudRepo;
        private readonly RoutePlanRepository _routeRepo;
        private readonly WaypointRepository _waypointRepo;

        public ScenarioService(
            SimTaskRepository taskRepo,
            CombatSceneRepository sceneRepo,
            ControlZoneRepository zoneRepo,
            TargetConfigRepository targetRepo,
            EquipmentDeploymentRepository equipRepo,
            CloudDispersalRepository cloudRepo,
            RoutePlanRepository routeRepo,
            WaypointRepository waypointRepo)
        {
            _taskRepo = taskRepo;
            _sceneRepo = sceneRepo;
            _zoneRepo = zoneRepo;
            _targetRepo = targetRepo;
            _equipRepo = equipRepo;
            _cloudRepo = cloudRepo;
            _routeRepo = routeRepo;
            _waypointRepo = waypointRepo;
        }

        // ========== Task CRUD ==========

        public SimTask CreateTask(string name, string taskNumber)
        {
            if (string.IsNullOrWhiteSpace(name))
                throw new ArgumentException("任务名称不能为空");

            if (string.IsNullOrWhiteSpace(taskNumber))
                taskNumber = GenerateTaskNumber();

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

            var task = new SimTask
            {
                Name = name,
                TaskNumber = taskNumber,
                Status = (int)TaskStatus.Configuring,
                CurrentStep = 1,
            };

            _taskRepo.Insert(task);
            return task;
        }

        public void DeleteTask(string id)
        {
            _taskRepo.Delete(id);
        }

        public PagedResult<SimTask> SearchTasks(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 = _taskRepo.Search(keyword, dateFrom, dateTo, offset, pageSize, out var total);

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

        public TaskFullConfig? GetTaskDetail(string id)
        {
            var task = _taskRepo.GetById(id);
            if (task == null) return null;

            return new TaskFullConfig
            {
                Task = task,
                Scene = _sceneRepo.GetById(id) ?? new CombatScene { TaskId = id },
                ControlZones = _zoneRepo.GetByTaskId(id),
                Targets = _targetRepo.GetByTaskId(id),
                Equipment = _equipRepo.GetByTaskId(id),
                Cloud = _cloudRepo.GetById(id) ?? new CloudDispersal { TaskId = id },
                Routes = _routeRepo.GetByTaskId(id),
                WaypointGroups = _waypointRepo.GetByTaskId(id)
                    .GroupBy(w => w.GroupId)
                    .ToDictionary(g => g.Key, g => g.OrderBy(w => w.OrderIndex).ToList()),
            };
        }

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

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

        public void SaveControlZones(string taskId, List<ControlZone> zones)
        {
            _zoneRepo.DeleteByTaskId(taskId);
            for (int i = 0; i < zones.Count; i++)
            {
                zones[i].TaskId = taskId;
                zones[i].OrderIndex = i;
            }
            _zoneRepo.InsertAll(zones);
            TouchTask(taskId);
        }

        public void SaveTarget(string taskId, TargetConfig target)
        {
            target.TaskId = taskId;
            if (string.IsNullOrEmpty(target.Id))
                target.Id = Guid.NewGuid().ToString();

            var existing = _targetRepo.GetById(target.Id);
            if (existing != null)
                _targetRepo.Update(target);
            else
                _targetRepo.Insert(target);
            TouchTask(taskId);
        }

        public void SaveDeployment(string taskId, List<EquipmentDeployment> equips)
        {
            _equipRepo.DeleteByTaskId(taskId);
            foreach (var e in equips)
            {
                e.TaskId = taskId;
                if (string.IsNullOrEmpty(e.Id))
                    e.Id = Guid.NewGuid().ToString();
            }
            _equipRepo.InsertAll(equips);
            TouchTask(taskId);
        }

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

        public void SaveRoute(string taskId, string groupId, RoutePlan route, List<Waypoint> waypoints)
        {
            route.TaskId = taskId;
            route.GroupId = groupId;
            var existing = _routeRepo.GetByTaskAndGroup(taskId, groupId);
            if (existing != null)
            {
                route.Id = existing.Id;
                _routeRepo.Update(route);
            }
            else
                _routeRepo.Insert(route);

            // 删除该编队的旧航路点，插入新的
            var oldWps = _waypointRepo.GetByTaskAndGroup(taskId, groupId);
            foreach (var w in oldWps) _waypointRepo.Delete(w.Id);
            for (int i = 0; i < waypoints.Count; i++)
            {
                waypoints[i].TaskId = taskId;
                waypoints[i].GroupId = groupId;
                waypoints[i].OrderIndex = i;
                if (string.IsNullOrEmpty(waypoints[i].Id))
                    waypoints[i].Id = Guid.NewGuid().ToString();
            }
            _waypointRepo.InsertAll(waypoints);
            TouchTask(taskId);
        }

        public void UpdateStep(string taskId, int step)
        {
            var task = _taskRepo.GetById(taskId);
            if (task == null) return;

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

            task.CurrentStep = step;
            _taskRepo.Update(task);
        }

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

        private void TouchTask(string taskId)
        {
            var task = _taskRepo.GetById(taskId);
            if (task != null)
            {
                task.UpdatedAt = DateTime.UtcNow.ToString("o");
                _taskRepo.Update(task);
            }
        }

        private static int _counter;

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