using System.Collections.Generic;
using CounterDrone.Core;
using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;
using CounterDrone.Core.Simulation;
using UnityEngine;
using AVector3 = CounterDrone.Core.Algorithms.Vector3;

namespace CounterDrone.Unity
{
    [ExecuteAlways]
    public class ManagerVerification : MonoBehaviour
    {
        [ContextMenu("Run Full Verification")]
        void Run()
        {
            Debug.Log("===== Manager Verification Start =====");

            var paths = new UnityPathProvider();
            if (System.IO.File.Exists(paths.GetMainDbPath()))
                System.IO.File.Delete(paths.GetMainDbPath());
            if (System.IO.Directory.Exists(paths.GetFramesDir()))
                System.IO.Directory.Delete(paths.GetFramesDir(), true);

            var modelMgr = gameObject.AddComponent<ModelManager>();
            modelMgr.Awake();
            Debug.Log("1. ModelManager OK");

            var scenarioMgr = gameObject.AddComponent<ScenarioManager>();
            scenarioMgr.Awake();
            var task = scenarioMgr.CreateTask("Verification", "");
            var taskId = task.Id;
            Debug.Log($"2. ScenarioManager OK. Task: {taskId}");

            scenarioMgr.SaveScene(taskId, new CombatScene { WindSpeed = 0 });
            scenarioMgr.SaveTarget(taskId, new TargetConfig
            {
                GroupId = "default",
                TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston,
                Quantity = 1, TypicalSpeed = 200, TypicalAltitude = 500,
            });
            scenarioMgr.SaveRoute(taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
                new List<Waypoint>
                {
                    new Waypoint { PosX = 0, PosY = 500, PosZ = 0 },
                    new Waypoint { PosX = 10000, PosY = 500, PosZ = 0 },
                });
            scenarioMgr.UpdateStep(taskId, 3);
            Debug.Log("3. Scenario configured");

            var db = new DatabaseManager(paths).OpenMainDb();
            SqliteConnectionTracker.Track(db);
            foreach (var a in DefaultAmmunition.GetAll()) db.Insert(a);
            var ammoCatalog = db.Table<AmmunitionSpec>().ToList();

            var detail = scenarioMgr.GetDetail(taskId);
            var droneGroup = new DroneGroup
            {
                GroupId = "default",
                Target = detail.Targets[0],
                Route = detail.Routes[0],
                Waypoints = detail.WaypointGroups["default"],
            };
            var fireUnits = new List<FireUnit>();
            for (int i = 0; i < 8; i++)
                fireUnits.Add(new FireUnit
                {
                    Id = $"u{i}",
                    Type = PlatformType.GroundBased,
                    Position = new AVector3(5000 + i * 50, 0, 50),
                    MuzzleVelocity = 800,
                    TotalMunitions = 3,
                    AmmoTypes = new() { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel },
                });
            var result = new DefaultDefensePlanner(ammoCatalog).Plan(fireUnits, new List<DroneGroup> { droneGroup }, detail.Scene);
            scenarioMgr.SaveCloud(taskId, new CloudDispersal
            {
                PositionX = (droneGroup.Waypoints[0].PosX + droneGroup.Waypoints[^1].PosX) / 2,
                PositionY = (droneGroup.Waypoints[0].PosY + droneGroup.Waypoints[^1].PosY) / 2,
                PositionZ = (droneGroup.Waypoints[0].PosZ + droneGroup.Waypoints[^1].PosZ) / 2,
                DisperseHeight = droneGroup.Target.TypicalAltitude,
            });

            var equips = new List<EquipmentDeployment>();
            foreach (var u in fireUnits)
                equips.Add(new EquipmentDeployment
                {
                    EquipmentRole = (int)EquipmentRole.LaunchPlatform,
                    PlatformType = (int)u.Type, Quantity = 1,
                    PositionX = u.Position.X, PositionY = u.Position.Y, PositionZ = u.Position.Z,
                    AerosolType = (int)u.AmmoTypes[0],
                    MunitionCount = u.TotalMunitions, Cooldown = u.Cooldown, MuzzleVelocity = u.MuzzleVelocity,
                    CruiseSpeed = u.CruiseSpeed > 0 ? u.CruiseSpeed : null,
                    ReleaseAltitude = u.ReleaseAltitude > 0 ? u.ReleaseAltitude : null,
                });
            scenarioMgr.SaveDeployment(taskId, equips);
            SqliteConnectionTracker.Untrack(db);
            db.Dispose();
            var plan = result.Best;
            Debug.Log($"4. Plan: {plan.ThreatsEngaged} threats engaged, {plan.MergedSchedule.Count} rounds, prob={plan.OverallProbability:P0}");

            var runner = gameObject.AddComponent<SimulationRunner>();
            runner.Awake();
            runner.LoadAndStart(taskId);
            runner.Engine.TimeScale = 10f;

            float endTime = Time.realtimeSinceStartup + 60f;
            int frameCount = 0;
            float tickDt = 1f / 20f;
            while (runner.Engine.State == SimulationState.Running && Time.realtimeSinceStartup < endTime)
            {
                runner.Engine.Tick(tickDt);
                frameCount++;
            }
            Debug.Log($"5. Simulation done. State={runner.Engine.State}, DroneStatus={runner.Engine.Drones[0].Status}, HP={runner.Engine.Drones[0].Hp:F2}, Frames={frameCount}");
            runner.Stop();

            var reportMgr = gameObject.AddComponent<ReportManager>();
            reportMgr.Awake();
            detail = scenarioMgr.GetDetail(taskId);
            var simEvents = new List<SimEvent>(runner.Engine.Events);
            var status = runner.Engine.Drones.Count > 0 ? runner.Engine.Drones[0].Status.ToString() : "Unknown";
            var report = reportMgr.Generate(taskId, detail, simEvents, status, runner.Engine.SimulationTime);
            var path = reportMgr.Export(report.Id);
            Debug.Log($"6. Report OK. Exported: {path}");

            var replay = gameObject.AddComponent<ReplayController>();
            replay.Awake();
            replay.LoadReplay(taskId);
            Debug.Log($"7. Replay OK. {replay.TotalFrames} frames, {replay.CurrentFrames.Count} records");

            Debug.Log("===== ALL MANAGERS VERIFIED =====");
        }
    }
}
