using System;
using System.Collections.Generic;
using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;

namespace CounterDrone.Core.Simulation
{
    public class DroneEntity
    {
        public string Id { get; }
        public string GroupId { get; }
        public TargetType TargetType { get; }
        public PowerType PowerType { get; }
        public float Wingspan { get; }
        public float TypicalSpeed { get; }
        public List<Waypoint> Route { get; }
        public int CurrentWaypointIndex { get; private set; }
        public float PosX { get; private set; }
        public float PosY { get; private set; }
        public float PosZ { get; private set; }
        public float Hp { get; private set; } = 1.0f;
        public DroneStatus Status { get; private set; } = DroneStatus.Flying;
        public float ExposureTime { get; set; }
        public float FormationOffsetX { get; set; }
        public float FormationOffsetY { get; set; }

        public DroneEntity(string id, string groupId, TargetConfig config, List<Waypoint> route,
            int formationIndex, float lateralSpacing, int longitudinalIndex, float longitudinalSpacing, FormationMode mode)
        {
            Id = id;
            GroupId = groupId;
            TargetType = (TargetType)config.TargetType;
            PowerType = (PowerType)config.PowerType;
            Wingspan = (float)config.Wingspan;
            TypicalSpeed = (float)config.TypicalSpeed;
            Route = route;

            // 编队偏移应用到航点上（每架独立航路）
            float latOffset = 0, longOffset = 0;
            switch (mode)
            {
                case FormationMode.Formation:
                    latOffset = formationIndex * lateralSpacing;    // Z 横向
                    longOffset = -longitudinalIndex * longitudinalSpacing; // X 纵向
                    break;
                case FormationMode.Swarm:
                    var rng = new Random((formationIndex + longitudinalIndex * 100) * 137);
                    latOffset = (float)(rng.NextDouble() - 0.5) * lateralSpacing * 3;
                    longOffset = (float)(rng.NextDouble() - 0.5) * lateralSpacing * 3;
                    break;
            }

            // 克隆航点并加偏移
            var offsetRoute = new List<Waypoint>();
            foreach (var wp in route)
            {
                offsetRoute.Add(new Waypoint
                {
                    PosX = wp.PosX + longOffset,
                    PosY = wp.PosY,
                    PosZ = wp.PosZ + latOffset,
                    Altitude = wp.Altitude,
                    Speed = wp.Speed,
                });
            }
            Route = offsetRoute;

            if (offsetRoute.Count > 0)
            {
                PosX = (float)offsetRoute[0].PosX;
                PosY = (float)offsetRoute[0].PosY;
                PosZ = (float)offsetRoute[0].PosZ;
            }
        }

        private void ApplyFormationOffset(int latIdx, float latSpacing, int longIdx, float longSpacing, FormationMode mode)
        {
            if (latIdx == 0 && longIdx == 0) return;
            switch (mode)
            {
                case FormationMode.Formation:
                    FormationOffsetY = latIdx * latSpacing;
                    FormationOffsetX = -longIdx * longSpacing;
                    break;
                case FormationMode.Swarm:
                    var rng = new Random((latIdx + longIdx * 100) * 137);
                    FormationOffsetX = (float)(rng.NextDouble() - 0.5) * latSpacing * 3;
                    FormationOffsetY = (float)(rng.NextDouble() - 0.5) * latSpacing * 3;
                    break;
            }
        }

        public void Update(float deltaTime, float windSpeed, WindDirection windDir)
        {
            if (Status != DroneStatus.Flying) return;
            if (Route.Count == 0) return;
            if (CurrentWaypointIndex >= Route.Count - 1)
            {
                Status = DroneStatus.ReachedTarget;
                return;
            }

            var target = Route[CurrentWaypointIndex + 1];
            var speedMs = TypicalSpeed / 3.6f;
            var dx = (float)(target.PosX - PosX);
            var dy = (float)(target.PosY - PosY);
            var dz = (float)(target.PosZ - PosZ);
            var dist = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
            var step = speedMs * deltaTime;

            if (dist < 1.0f || step >= dist)
            {
                PosX = (float)target.PosX;
                PosY = (float)target.PosY;
                PosZ = (float)target.PosZ;
                CurrentWaypointIndex++;
                if (CurrentWaypointIndex >= Route.Count - 1)
                    Status = DroneStatus.ReachedTarget;
                return;
            }

            var ratio = step / dist;
            PosX += dx * ratio;
            PosY += dy * ratio;
            PosZ += dz * ratio;

            (float wx, float wy, float wz) = Kinematics.WindToVector(windDir, windSpeed);
            PosX += wx * deltaTime;
            PosY += wy * deltaTime;
            PosZ += wz * deltaTime;
        }

        public void ApplyDamage(float damage)
        {
            if (Status != DroneStatus.Flying) return;
            Hp -= damage;
            if (Hp <= 0)
            {
                Hp = 0;
                Status = DroneStatus.Destroyed;
            }
        }

        public void MarkZoneIntruded()
        {
            Status = DroneStatus.ZoneIntruded;
        }
    }
}
