//! NPC spawning system.
//!
//! Handles spawning of NPC ships based on system security level,
//! faction presence, and gameplay requirements.

use bevy::prelude::*;

use crate::gameplay::ai::{AiState, BehaviorState};
use crate::gameplay::galaxy::{Identifiable, StarSystem};
use crate::gameplay::in_system::ActiveSystem;
use crate::gameplay::movement::components::{MaxSpeed, TurnRate, Velocity};

/// Metadata for spawned NPCs.
#[derive(Component, Debug, Clone)]
pub struct NpcMetadata {
    /// NPC identifier
    pub id: String,
    /// Display name
    pub name: String,
    /// Faction this NPC belongs to
    pub faction: String,
    /// NPC type (patrol, pirate, trader, miner)
    pub npc_type: NpcType,
    /// Spawn level (affects stats)
    pub spawn_level: u32,
}

/// Types of NPCs that can be spawned.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NpcType {
    /// Faction patrol ship
    Patrol,
    /// Pirate / hostile
    Pirate,
    /// Trading vessel
    Trader,
    /// Mining vessel
    Miner,
    /// Station traffic (shuttles, etc.)
    StationTraffic,
}

/// NPC spawner resource.
#[derive(Resource, Debug, Clone)]
pub struct NpcSpawner {
    /// Whether to spawn NPCs in the current system
    pub spawn_enabled: bool,
    /// Maximum NPCs per system
    pub max_npcs_per_system: u32,
    /// Spawn multiplier (for difficulty scaling)
    pub spawn_multiplier: f32,
}

impl Default for NpcSpawner {
    fn default() -> Self {
        Self {
            spawn_enabled: true,
            max_npcs_per_system: 15,
            spawn_multiplier: 1.0,
        }
    }
}

/// Spawn NPCs for the current system when entering gameplay.
///
/// This runs on AppState::InGame enter and spawns appropriate NPCs
/// based on the active system's security level and faction.
pub fn spawn_system_npcs(
    mut commands: Commands,
    active_system: Res<ActiveSystem>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // For now, use a default security level since ActiveSystem doesn't store it
    let security = 0.5; // Default mid-sec
    let faction = "Concord"; // Default faction

    // Determine spawn count based on security level
    let base_spawn_count = match security {
        sec if sec >= 0.8 => 8, // High-sec: more patrols
        sec if sec >= 0.5 => 5, // Mid-sec: moderate
        _ => 3, // Low-sec: fewer but more dangerous
    };

    let spawn_count = (base_spawn_count as f32) * 1.0; // Use spawn multiplier from resource if available

    bevy::log::info!(
        "Spawning {} NPCs for system {} (security: {})",
        spawn_count as u32,
        active_system.system_name,
        security
    );

    // Spawn faction patrols for high-sec systems
    if security >= 0.5 {
        let patrol_count = (spawn_count * 0.6) as u32;
        for i in 0..patrol_count {
            spawn_npc(
                &mut commands,
                &mut meshes,
                &mut materials,
                &active_system.system_name,
                faction,
                NpcType::Patrol,
                i,
            );
        }
    }

    // Spawn pirates for low-sec systems
    if security < 0.5 {
        let pirate_count = (spawn_count * 0.4) as u32 + 1;
        for i in 0..pirate_count {
            spawn_npc(
                &mut commands,
                &mut meshes,
                &mut materials,
                &active_system.system_name,
                faction,
                NpcType::Pirate,
                i,
            );
        }
    }

    // Spawn traders for all systems
    let trader_count = (spawn_count * 0.2) as u32 + 1;
    for i in 0..trader_count {
        spawn_npc(
            &mut commands,
            &mut meshes,
            &mut materials,
            &active_system.system_name,
            faction,
            NpcType::Trader,
            i,
        );
    }

    // Spawn miners for systems with asteroid belts
    let miner_count = (spawn_count * 0.2) as u32 + 1;
    for i in 0..miner_count {
        spawn_npc(
            &mut commands,
            &mut meshes,
            &mut materials,
            &active_system.system_name,
            faction,
            NpcType::Miner,
            i,
        );
    }
}

/// Spawn a single NPC ship.
fn spawn_npc(
    commands: &mut Commands,
    meshes: &mut Assets<Mesh>,
    materials: &mut Assets<StandardMaterial>,
    system_name: &str,
    faction: &str,
    npc_type: NpcType,
    index: u32,
) {
    // Determine faction and appearance based on NPC type
    let (npc_faction, color, name_prefix) = match npc_type {
        NpcType::Patrol => (
            faction.to_string(),
            get_faction_color(faction),
            "PATROL",
        ),
        NpcType::Pirate => (
            "Pirates".to_string(),
            [0.8, 0.2, 0.2], // Red
            "PIRATE",
        ),
        NpcType::Trader => (
            "Commerce".to_string(),
            [0.2, 0.6, 0.8], // Blue
            "TRADER",
        ),
        NpcType::Miner => (
            "MiningGuild".to_string(),
            [0.6, 0.6, 0.2], // Yellow
            "MINER",
        ),
        NpcType::StationTraffic => (
            "Station".to_string(),
            [0.5, 0.5, 0.5], // Gray
            "TRAFFIC",
        ),
    };

    // Generate spawn position (random position within system bounds)
    let angle = (index as f32) * 0.5; // Spread out spawns
    let radius = 150.0 + (index as f32) * 50.0;
    let spawn_pos = Vec3::new(
        angle.cos() * radius,
        0.0,
        angle.sin() * radius,
    );

    // Create NPC entity
    let npc_id = format!("npc-{}-{}", name_prefix, index);
    let npc_name = format!("{} {}", name_prefix, index + 1);

    let mut entity = commands.spawn((
        // Transform
        Transform::from_translation(spawn_pos),
        Visibility::default(),
        InheritedVisibility::default(),

        // NPC metadata
        NpcMetadata {
            id: npc_id.clone(),
            name: npc_name.clone(),
            faction: npc_faction.clone(),
            npc_type,
            spawn_level: 1,
        },

        // AI state
        AiState {
            behavior: match npc_type {
                NpcType::Patrol => BehaviorState::Patrol,
                NpcType::Pirate => BehaviorState::Idle,
                NpcType::Trader => BehaviorState::Trading,
                NpcType::Miner => BehaviorState::Mining,
                NpcType::StationTraffic => BehaviorState::Idle,
            },
            ..default()
        },

        // Identifiable for targeting system
        Identifiable {
            id: npc_id,
            display_name: npc_name.clone(),
            classification: crate::gameplay::galaxy::Classification::Ship,
        },

        // Movement components
        MaxSpeed(50.0),
        TurnRate(2.0),
        Velocity::default(),

        // Visual representation (simple cone for now)
        Mesh3d(meshes.add(Cone::new(2.0, 8.0).mesh())),
        MeshMaterial3d(materials.add(StandardMaterial {
            base_color: Color::srgb(color[0], color[1], color[2]),
            emissive: LinearRgba::new(color[0] * 0.3, color[1] * 0.3, color[2] * 0.3, 1.0),
            ..default()
        })),
    ));

    // Add state-specific components
    match npc_type {
        NpcType::Patrol => {
            entity.insert(crate::gameplay::ai::PatrolState::default());
        }
        NpcType::Pirate => {
            // Pirates don't have special state - they use base AiState
        }
        NpcType::Trader => {
            entity.insert(crate::gameplay::ai::TradingState::default());
        }
        NpcType::Miner => {
            entity.insert(crate::gameplay::ai::MiningState::default());
        }
        NpcType::StationTraffic => {
            // Traffic is idle most of the time
        }
    }

    bevy::log::debug!("Spawned NPC: {} at {:?}", npc_name.clone(), spawn_pos);
}

/// Spawn station traffic (NPCs that dock/undock at stations).
pub fn spawn_station_traffic(
    commands: &mut Commands,
    meshes: &mut Assets<Mesh>,
    materials: &mut Assets<StandardMaterial>,
    active_system: &ActiveSystem,
) {
    // Spawn 2-3 traffic NPCs per station
    let traffic_count = 3;
    let faction = "Concord"; // Default faction

    for i in 0..traffic_count {
        spawn_npc(
            commands,
            meshes,
            materials,
            &active_system.system_name,
            faction,
            NpcType::StationTraffic,
            i,
        );
    }
}

/// Get the color for a faction.
fn get_faction_color(faction: &str) -> [f32; 3] {
    match faction {
        "Concord" => [0.13, 0.83, 0.93],  // cyan
        "Amarr" => [0.96, 0.62, 0.04],    // amber
        "Minmatar" => [0.94, 0.27, 0.27], // red
        "Gallente" => [0.66, 0.33, 0.97], // purple
        "Caldari" => [0.22, 0.74, 0.97],  // blue
        _ => [0.5, 0.5, 0.5],            // gray (default)
    }
}
