//! Flight state and controls for in-system gameplay.
//!
//! Handles the transition from docked to active flight mode, including
//! ship controls, camera transitions, and flight state management.
//!
//! Navigation is point-and-click tactical mode: select targets and click
//! "Approach" to auto-navigate. No WASD controls.

use bevy::prelude::*;

use crate::camera::{CameraState, CameraMode, OrbitFocusGoal};
use crate::gameplay::movement::components::{Velocity, MoveTarget};
use crate::gameplay::galaxy::Identifiable;
use super::{DockedState, UndockEvent};
use super::scene::{Docked, PlayerShip};

/// Flight state component attached to the player ship when actively flying.
#[derive(Component, Debug, Clone, Default)]
pub struct FlightState {
    pub is_flying: bool,
    pub current_speed: f32,
}

/// Event fired when the player docks at a station.
#[derive(Event, Debug, Clone)]
pub struct DockEvent {
    pub ship: Entity,
    pub station: Entity,
}

/// Plugin for flight controls and state management.
pub struct FlightControlsPlugin;

impl Plugin for FlightControlsPlugin {
    fn build(&self, app: &mut App) {
        app.add_event::<DockEvent>()
            .add_systems(
                Update,
                (
                    handle_undock,
                    handle_docking,
                    flight_input_system,
                ).run_if(in_state(crate::state::AppState::InGame)),
            );
    }
}

/// Handle undock event: transition from docked to flight mode.
fn handle_undock(
    mut commands: Commands,
    mut events: EventReader<UndockEvent>,
    mut docked_state: ResMut<DockedState>,
    mut camera_state: ResMut<CameraState>,
    mut focus_goal: ResMut<OrbitFocusGoal>,
    player_query: Query<Entity, (With<PlayerShip>, With<Docked>)>,
) {
    for event in events.read() {
        bevy::log::info!("Handling undock from station {:?}", event.station_entity);

        // Find player ship
        let Ok(player_entity) = player_query.single() else {
            bevy::log::warn!("No docked player ship found");
            continue;
        };

        // Remove docked component
        commands.entity(player_entity).remove::<Docked>();

        // Add flight state with initial velocity away from station
        let initial_speed = 10.0; // Start with slow drift
        commands.entity(player_entity).insert((
            FlightState {
                is_flying: true,
                current_speed: initial_speed,
            },
            Velocity(Vec3::new(0.0, 0.0, -1.0) * initial_speed),
            MoveTarget(Vec3::new(0.0, 0.0, -50.0)), // Initial target away from station
            super::SelectedTarget {
                entity: Entity::PLACEHOLDER,
                kind: super::TargetKind::Manual,
                name: "None".to_string(),
            },
        ));

        // Update docked state resource
        docked_state.undock();

        // Transition camera to follow mode: a tactical iso view tracking the
        // ship. Arm a focus goal so the distance eases from the docked framing
        // to the follow distance instead of hard-snapping. The orbit target is
        // left to `track_camera_target`, which locks it to the ship.
        camera_state.mode = CameraMode::Follow;
        camera_state.target_entity = Some(player_entity);
        camera_state.follow_distance = 45.0; // Higher for tactical view
        camera_state.follow_height = 35.0; // Isometric angle
        focus_goal.arm(
            None,
            Some(camera_state.follow_distance),
            Some(crate::camera::tactical_rotation()),
        );

        // The flight HUD is spawned reactively by `hud::sync_hud_panels`
        // once it sees the player's new `FlightState` component.

        bevy::log::info!("Transitioned to flight mode");
    }
}

/// Handle docking event: transition from flight to docked mode.
fn handle_docking(
    mut commands: Commands,
    mut events: EventReader<DockEvent>,
    mut docked_state: ResMut<DockedState>,
    mut camera_state: ResMut<CameraState>,
    mut focus_goal: ResMut<OrbitFocusGoal>,
    identifiable_query: Query<&Identifiable>,
) {
    for event in events.read() {
        bevy::log::info!("Handling docking at target {:?}", event.station);

        let Ok(identifiable) = identifiable_query.get(event.station) else {
            bevy::log::warn!("Docking target has no Identifiable component");
            continue;
        };

        // Add docked component and clear all flight components so the
        // reactive HUD swap hides the flight HUD (and the ship stops moving).
        commands.entity(event.ship).insert(Docked {
            station_entity: event.station,
        });
        commands
            .entity(event.ship)
            .remove::<(FlightState, Velocity, MoveTarget, super::SelectedTarget)>();

        // Update docked state resource
        docked_state.dock_at(event.station);

        // Transition camera back to the docked tactical framing (Orbit on the
        // station), easing the distance in.
        camera_state.mode = CameraMode::Orbit;
        camera_state.target_entity = Some(event.station);
        focus_goal.arm(
            None,
            Some(crate::camera::DOCKED_FRAMING_DISTANCE),
            Some(crate::camera::tactical_rotation()),
        );

        // The station info panel is spawned reactively by
        // `hud::sync_hud_panels` once it sees the player's `Docked` component.

        bevy::log::info!("Docked at {}", identifiable.display_name);
    }
}

/// Flight input system: point-and-click navigation only.
///
/// This system handles updating the flight state based on movement.
/// Actual navigation is handled by click-to-move (setting MoveTarget)
/// and the kinematic systems (steer_to_target, integrate_velocity).
///
/// This is a minimal system - the real action happens in the movement systems.
fn flight_input_system(
    mut player_query: Query<(&Velocity, &mut FlightState), With<PlayerShip>>,
    docked_state: Res<DockedState>,
) {
    // Only process flight input when not docked
    if docked_state.is_docked {
        return;
    }

    let Ok((velocity, mut flight_state)) = player_query.single_mut() else {
        return;
    };

    // Update current speed from actual velocity
    flight_state.current_speed = velocity.0.length();
}
