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 WaveId { get; }
        public TargetType TargetType { get; }
        public PowerType PowerType { get; }
        public float Wingspan { get; }
        public float CruiseSpeed { get; }
        public List<Waypoint> Route { get; }
        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; }
        /// <summary>上一帧位置（路径积分用）</summary>
        public float PrevX { get; private set; }
        public float PrevY { get; private set; }
        public float PrevZ { get; private set; }
        /// <summary>沿航路已飞行弧长（米），由 RouteGeometry 驱动</summary>
        private float _traveledArc;
        /// <summary>航路总弧长（米），构造时一次性算好（航路静态，无需每帧重算）</summary>
        private readonly float _totalArc;
        /// <summary>每段段长（米），_segLen[i] = Route[i]→Route[i+1]</summary>
        private readonly float[] _segLen;
        /// <summary>每段终点累积弧长（米），_cumArc[i] = sum(_segLen[0..i])。
        /// 查找弧长 s 所在段：最大的 i 使 _cumArc[i] >= s。</summary>
        private readonly float[] _cumArc;

        public DroneEntity(string id, string waveId, TargetConfig config, List<Waypoint> route,
            int formationIndex, float lateralSpacing, int longitudinalIndex, float longitudinalSpacing, FormationMode mode)
        {
            Id = id;
            WaveId = waveId;
            TargetType = (TargetType)config.TargetType;
            PowerType = (PowerType)config.PowerType;
            Wingspan = (float)config.Wingspan;
            float spd = (float)route[0].Speed;
            if (spd <= 0) throw new InvalidOperationException($"无人机 {id}: 航路点速度必须 > 0");
            CruiseSpeed = spd;
            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;
            }

            // 预计算航路几何缓存：航路在构造后静态不变，避免每帧重算总弧长与各段段长
            int segCount = Math.Max(0, offsetRoute.Count - 1);
            _segLen = new float[segCount];
            _cumArc = new float[segCount];
            float accum = 0f;
            for (int i = 0; i < segCount; i++)
            {
                float sl = Kinematics.Distance3D(
                    (float)offsetRoute[i].PosX, (float)offsetRoute[i].PosY, (float)offsetRoute[i].PosZ,
                    (float)offsetRoute[i + 1].PosX, (float)offsetRoute[i + 1].PosY, (float)offsetRoute[i + 1].PosZ);
                _segLen[i] = sl;
                accum += sl;
                _cumArc[i] = accum;
            }
            _totalArc = accum;
        }

        public void SavePreviousPosition()
        {
            PrevX = PosX; PrevY = PosY; PrevZ = PosZ;
        }

        public void Update(float deltaTime)
        {
            if (Status != DroneStatus.Flying) return;
            if (Route.Count == 0) return;

            // 运动模型统一在 RouteGeometry：弧长推进 + 位置查询。
            // 无人机严格按航路匀速飞行。无人机不受风偏影响（真实无人机有飞控修正航向），
            // 但云团受风偏影响（见 SimulationEngine 毁伤判定的云团参考系修正）。
            // 航路几何在构造时已缓存为 _totalArc / _segLen / _cumArc，此处不再重算。
            if (_totalArc <= 0f)
            {
                Status = DroneStatus.ReachedTarget;
                return;
            }

            float speedMs = CruiseSpeed / 3.6f;
            _traveledArc += speedMs * deltaTime;

            if (_traveledArc >= _totalArc)
            {
                var end = Route[^1];
                PosX = (float)end.PosX;
                PosY = (float)end.PosY;
                PosZ = (float)end.PosZ;
                Status = DroneStatus.ReachedTarget;
                return;
            }

            // 在缓存的累积弧长数组中定位所在段（线性扫描：航点数通常 ≤10）
            int segIdx = 0;
            while (segIdx < _cumArc.Length - 1 && _traveledArc > _cumArc[segIdx])
                segIdx++;

            float segStartArc = segIdx > 0 ? _cumArc[segIdx - 1] : 0f;
            float segLen = _segLen[segIdx];
            float t = segLen > 0.0001f ? (_traveledArc - segStartArc) / segLen : 0f;
            var a = Route[segIdx];
            var b = Route[segIdx + 1];
            PosX = (float)(a.PosX + (b.PosX - a.PosX) * t);
            PosY = (float)(a.PosY + (b.PosY - a.PosY) * t);
            PosZ = (float)(a.PosZ + (b.PosZ - a.PosZ) * t);
        }

        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;
        }
    }
}
