//! AI behavior execution systems.
//!
//! Systems that execute specific behaviors for NPCs: patrol, combat,
//! flee, mining, and trading.

use bevy::prelude::*;

use crate::gameplay::ai::{
    AiConfig, AiNavigation, AiState, BehaviorState, CombatState, FactionAiBehavior,
    FleeState, MiningState, PatrolState, StateTransition, TradingState,
};
use crate::gameplay::movement::components::MoveTarget;
use crate::gameplay::ai::perception::{Perception, PerceptionEvent, PerceptionEventType};

/// Update state transitions for all AI entities.
///
/// This system evaluates conditions and triggers state transitions
/// based on AI state, perception, and faction behavior.
pub fn update_state_transitions(
    mut commands: Commands,
    ai_config: Res<AiConfig>,
    mut ai_query: Query<(
        Entity,
        &mut AiState,
        &Perception,
        &FactionAiBehavior,
    )>,
    mut state_events: EventWriter<StateTransition>,
    mut perception_events: EventReader<PerceptionEvent>,
    time: Res<Time>,
) {
    // First, handle perception events that might trigger state changes
    for event in perception_events.read() {
        if let Ok((_, mut ai_state, perception, faction_behavior)) =
            ai_query.get_mut(event.observer)
        {
            match event.event_type {
                PerceptionEventType::HostileDetected => {
                    // Transition to combat if we're not already fleeing
                    if ai_state.behavior != BehaviorState::Combat
                        && ai_state.behavior != BehaviorState::Flee
                    {
                        let old_state = ai_state.behavior;
                        ai_state.behavior = BehaviorState::Combat;
                        ai_state.target_entity = Some(event.perceived);

                        state_events.send(StateTransition {
                            entity: event.observer,
                            from_state: old_state,
                            to_state: BehaviorState::Combat,
                            reason: "Hostile detected".to_string(),
                        });
                    }
                }
                PerceptionEventType::Lost => {
                    // Lost track of target - return to idle or patrol
                    if Some(event.perceived) == ai_state.target_entity {
                        let old_state = ai_state.behavior;

                        // Return to patrol if we have patrol waypoints, else idle
                        ai_state.behavior = BehaviorState::Idle;
                        ai_state.target_entity = None;
                        ai_state.target_position = None;

                        state_events.send(StateTransition {
                            entity: event.observer,
                            from_state: old_state,
                            to_state: BehaviorState::Idle,
                            reason: "Target lost".to_string(),
                        });
                    }
                }
                _ => {}
            }
        }
    }

    // Then, update time-based transitions
    for (entity, mut ai_state, perception, faction_behavior) in ai_query.iter_mut() {
        ai_state.time_in_state += time.delta_secs();

        match ai_state.behavior {
            BehaviorState::Idle => {
                // Check for threats in idle state
                if let Some(threat) = perception.primary_threat {
                    if faction_behavior.aggressiveness > 0.5 {
                        let old_state = ai_state.behavior;
                        ai_state.behavior = BehaviorState::Combat;
                        ai_state.target_entity = Some(threat);

                        state_events.send(StateTransition {
                            entity,
                            from_state: old_state,
                            to_state: BehaviorState::Combat,
                            reason: "Threat detected in idle".to_string(),
                        });
                    }
                }
            }
            BehaviorState::Combat => {
                // Check hull threshold for fleeing
                if ai_state.hull_percentage < faction_behavior.flee_threshold() {
                    let old_state = ai_state.behavior;
                    ai_state.behavior = BehaviorState::Flee;

                    state_events.send(StateTransition {
                        entity,
                        from_state: old_state,
                        to_state: BehaviorState::Flee,
                        reason: "Hull critical".to_string(),
                    });
                }
            }
            BehaviorState::Flee => {
                // Check if we've reached safe distance
                // TODO: Implement distance check from threat
                // For now, NPCs stay in flee until they detect a safe distance
            }
            BehaviorState::Patrol | BehaviorState::Mining | BehaviorState::Trading => {
                // Continue current behavior until interrupted
            }
        }
    }
}

/// Execute patrol behavior for NPCs.
///
/// NPCs with patrol behavior follow waypoints through their assigned area.
pub fn execute_patrol(
    mut commands: Commands,
    mut ai_query: Query<(
        Entity,
        &mut AiState,
        &mut PatrolState,
        &mut AiNavigation,
        &Transform,
    )>,
    time: Res<Time>,
) {
    for (entity, mut ai_state, mut patrol_state, mut navigation, transform) in ai_query.iter_mut()
    {
        // Update time at waypoint if we're waiting
        if navigation.movement_target.is_none() && !patrol_state.waypoints.is_empty() {
            patrol_state.time_at_waypoint += time.delta_secs();

            if patrol_state.time_at_waypoint >= patrol_state.waypoint_wait_time {
                // Move to next waypoint
                patrol_state.time_at_waypoint = 0.0;
                patrol_state.current_waypoint = (patrol_state.current_waypoint + 1)
                    % patrol_state.waypoints.len();

                let target = patrol_state.waypoints[patrol_state.current_waypoint];
                ai_state.target_position = Some(target);

                // Assign movement target
                commands.entity(entity).insert(MoveTarget(target));
                navigation.movement_target = Some(target);
                navigation.is_moving = true;
            }
        }
    }
}

/// Execute combat behavior for NPCs.
///
/// NPCs in combat engage their targets with appropriate tactics.
pub fn execute_combat(
    mut commands: Commands,
    ai_config: Res<AiConfig>,
    mut ai_query: Query<(
        Entity,
        &mut AiState,
        &mut CombatState,
        &mut AiNavigation,
        &FactionAiBehavior,
        &Transform,
    )>,
    target_query: Query<&Transform>,
    time: Res<Time>,
) {
    for (entity, mut ai_state, mut combat_state, mut navigation, faction_behavior, transform) in
        ai_query.iter_mut()
    {
        // Get target transform if we have one
        let target_transform = if let Some(target_entity) = combat_state.target {
            target_query.get(target_entity).ok()
        } else if let Some(target_entity) = ai_state.target_entity {
            combat_state.target = Some(target_entity);
            target_query.get(target_entity).ok()
        } else {
            None
        };

        if let Some(target_tf) = target_transform {
            let distance = transform.translation.distance(target_tf.translation);

            // Move to preferred engagement distance
            let preferred_distance = faction_behavior.preferred_engagement_distance();
            let distance_diff = distance - preferred_distance;

            if distance_diff.abs() > 20.0 {
                // Need to adjust distance
                let direction = (target_tf.translation - transform.translation).normalize();
                let target_pos = if distance > preferred_distance {
                    // Move closer
                    transform.translation + direction * (distance - preferred_distance) * 0.5
                } else {
                    // Move away
                    transform.translation - direction * (preferred_distance - distance) * 0.5
                };

                commands.entity(entity).insert(MoveTarget(target_pos));
                navigation.movement_target = Some(target_pos);
                navigation.is_moving = true;
            } else {
                // At optimal distance, stop moving
                navigation.is_moving = false;
                commands.entity(entity).remove::<MoveTarget>();
            }

            // Update attack timing
            combat_state.time_since_last_attack += time.delta_secs();

            if combat_state.time_since_last_attack >= combat_state.attack_cooldown {
                // Attack!
                combat_state.time_since_last_attack = 0.0;
                combat_state.is_attacking = true;

                // In full implementation, this would trigger weapon fire
                bevy::log::debug!("Entity {:?} attacks!", entity);
            } else {
                combat_state.is_attacking = false;
            }
        }
    }
}

/// Execute flee behavior for NPCs.
///
/// NPCs in flee behavior move away from threats at high speed.
pub fn execute_flee(
    mut commands: Commands,
    ai_config: Res<AiConfig>,
    mut ai_query: Query<(
        Entity,
        &mut AiState,
        &mut FleeState,
        &mut AiNavigation,
        &Transform,
    )>,
    threat_query: Query<&Transform>,
) {
    for (entity, mut ai_state, mut flee_state, mut navigation, transform) in ai_query.iter_mut() {
        // Get threat position
        let threat_transform = if let Some(threat_entity) = flee_state.threat {
            threat_query.get(threat_entity).ok()
        } else if let Some(threat_entity) = ai_state.target_entity {
            flee_state.threat = Some(threat_entity);
            threat_query.get(threat_entity).ok()
        } else {
            // No threat - return to idle
            ai_state.behavior = BehaviorState::Idle;
            continue;
        };

        if let Some(threat_tf) = threat_transform {
            // Calculate flee direction (away from threat)
            let away_from_threat = (transform.translation - threat_tf.translation).normalize();
            flee_state.flee_direction = away_from_threat;

            // Move away at high speed
            let flee_distance = ai_config.safe_flee_distance;
            let target_pos = transform.translation + away_from_threat * flee_distance;

            commands.entity(entity).insert(MoveTarget(target_pos));
            navigation.movement_target = Some(target_pos);
            navigation.is_moving = true;
            navigation.speed_factor = 1.2; // 120% speed when fleeing
        }
    }
}

/// Execute mining behavior for NPCs.
///
/// NPCs with mining behavior stay at asteroid belts and mine.
pub fn execute_mining(
    mut ai_query: Query<(
        Entity,
        &mut AiState,
        &mut MiningState,
        &mut AiNavigation,
    )>,
    time: Res<Time>,
) {
    for (entity, mut ai_state, mut mining_state, mut navigation) in ai_query.iter_mut() {
        // Update mining time
        mining_state.mining_time += time.delta_secs();

        // Mining is complete when cargo is full or cycle duration is reached
        if mining_state.mining_time >= mining_state.mining_cycle_duration
            || mining_state.cargo_remaining <= 0.0
        {
            // Mining cycle complete
            mining_state.mining_time = 0.0;

            if mining_state.cargo_remaining > 0.0 {
                // Continue mining
                bevy::log::debug!("Entity {:?} continues mining", entity);
            } else {
                // Cargo full - return to station
                ai_state.behavior = BehaviorState::Trading;
                bevy::log::debug!("Entity {:?} cargo full, returning to station", entity);
            }
        }
    }
}

/// Execute trading behavior for NPCs.
///
/// NPCs with trading behavior travel between stations.
pub fn execute_trading(
    mut commands: Commands,
    mut ai_query: Query<(
        Entity,
        &mut AiState,
        &mut TradingState,
        &mut AiNavigation,
        &Transform,
    )>,
) {
    for (entity, mut ai_state, mut trading_state, mut navigation, transform) in ai_query.iter_mut() {
        // If we have waypoints, follow them
        if !trading_state.trade_route.is_empty() {
            let current_waypoint = trading_state.trade_route[trading_state.current_waypoint];
            let distance = transform.translation.distance(current_waypoint);

            if distance < 20.0 {
                // Reached waypoint - move to next
                trading_state.current_waypoint =
                    (trading_state.current_waypoint + 1) % trading_state.trade_route.len();

                let next_waypoint = trading_state.trade_route[trading_state.current_waypoint];

                commands.entity(entity).insert(MoveTarget(next_waypoint));
                navigation.movement_target = Some(next_waypoint);
                navigation.is_moving = true;
            } else if navigation.movement_target.is_none() {
                // Start moving
                commands.entity(entity).insert(MoveTarget(current_waypoint));
                navigation.movement_target = Some(current_waypoint);
                navigation.is_moving = true;
            }
        }
    }
}
