//! AI perception system.
//!
//! Event-based detection system for AI entities to perceive the player
//! and other entities in the game world.

use bevy::prelude::*;

/// Marks an entity as perceptible to AI (can be detected).
#[derive(Component, Debug, Clone)]
pub struct Perceptible {
    /// Detection priority (higher = more likely to be noticed)
    pub priority: f32,
    /// Whether this entity is hostile
    pub is_hostile: bool,
    /// Faction of this entity (for faction-based perception)
    pub faction: Option<String>,
}

impl Default for Perceptible {
    fn default() -> Self {
        Self {
            priority: 1.0,
            is_hostile: false,
            faction: None,
        }
    }
}

/// Perception component for AI entities.
#[derive(Component, Debug, Clone)]
pub struct Perception {
    /// Entities currently perceived by this AI
    pub perceived_entities: Vec<Entity>,
    /// The most threatening perceived entity
    pub primary_threat: Option<Entity>,
    /// The most interesting perceived entity (for non-hostile interactions)
    pub primary_interest: Option<Entity>,
    /// Time since last perception update
    pub time_since_last_update: f32,
}

impl Default for Perception {
    fn default() -> Self {
        Self {
            perceived_entities: Vec::new(),
            primary_threat: None,
            primary_interest: None,
            time_since_last_update: 0.0,
        }
    }
}

/// Event sent when an AI perceives something notable.
#[derive(Event, Debug, Clone)]
pub struct PerceptionEvent {
    /// AI entity that perceived something
    pub observer: Entity,
    /// Entity that was perceived
    pub perceived: Entity,
    /// Type of perception event
    pub event_type: PerceptionEventType,
}

/// Types of perception events.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PerceptionEventType {
    /// Detected a new entity
    Detected,
    /// Lost track of an entity
    Lost,
    /// Entity became hostile
    HostileDetected,
    /// Entity is in trouble (low health, etc.)
    DistressSignal,
    /// Entity has valuable cargo
    ValuableTarget,
}

/// Update perception for all AI entities.
///
/// This system runs every frame and updates each AI's perception
/// based on nearby entities and their perceptible components.
pub fn update_perception(
    mut perception_query: Query<(
        Entity,
        &mut Perception,
        &Transform,
    )>,
    perceptible_query: Query<(Entity, &Perceptible, &Transform)>,
    mut perception_events: EventWriter<PerceptionEvent>,
    time: Res<Time>,
) {
    for (observer_entity, mut perception, observer_transform) in perception_query.iter_mut() {
        perception.time_since_last_update += time.delta_secs();

        // Update perception every 0.5 seconds
        if perception.time_since_last_update < 0.5 {
            continue;
        }

        perception.time_since_last_update = 0.0;
        let previous_entities = std::mem::take(&mut perception.perceived_entities);

        // Find all perceptible entities within range
        for (perceived_entity, perceptible, perceived_transform) in perceptible_query.iter() {
            // Don't perceive ourselves
            if perceived_entity == observer_entity {
                continue;
            }

            let distance = observer_transform
                .translation
                .distance(perceived_transform.translation);

            // Detection range based on priority
            let detection_range = 500.0 * perceptible.priority;

            if distance < detection_range {
                // Entity is perceived
                perception.perceived_entities.push(perceived_entity);

                // Check if this is a newly detected entity
                if !previous_entities.contains(&perceived_entity) {
                    perception_events.send(PerceptionEvent {
                        observer: observer_entity,
                        perceived: perceived_entity,
                        event_type: if perceptible.is_hostile {
                            PerceptionEventType::HostileDetected
                        } else {
                            PerceptionEventType::Detected
                        },
                    });
                }

                // Update primary threat
                if perceptible.is_hostile {
                    if perception.primary_threat.is_none()
                        || distance < observer_transform.translation.distance(
                            // Can't access this easily without another query, simplify for now
                            Vec3::ZERO,
                        )
                    {
                        perception.primary_threat = Some(perceived_entity);
                    }
                } else {
                    perception.primary_interest = Some(perceived_entity);
                }
            }
        }

        // Check for lost entities
        for lost_entity in previous_entities {
            if !perception.perceived_entities.contains(&lost_entity) {
                perception_events.send(PerceptionEvent {
                    observer: observer_entity,
                    perceived: lost_entity,
                    event_type: PerceptionEventType::Lost,
                });
            }
        }
    }
}
