//! Galaxy creation UI: parameter slider panel (left) and selected-system
//! info panel (right).
//!
//! Bevy 0.16 does not ship a native Slider widget, so each parameter is a
//! row of `Label  Value  [-] [+]` buttons. Each `+/-` button carries a
//! [`ParamButton`] marker identifying which field to mutate.

use bevy::prelude::*;

use super::GalaxyCreationSpawned;
use crate::gameplay::galaxy_creation::params::*;

// ── Markers ─────────────────────────────────────────────────────────────────

#[derive(Component)]
pub struct GalaxyControlPanel;

#[derive(Component)]
pub struct GalaxyInfoPanel;

/// Identifies which parameter a `+/-` button mutates and which direction.
#[derive(Component, Clone, Copy)]
pub enum ParamButton {
    SeedDecr,
    SeedIncr,
    CountDecr,
    CountIncr,
    ArmsDecr,
    ArmsIncr,
    VerticalArmsDecr,
    VerticalArmsIncr,
    SizeDecr,
    SizeIncr,
    TwistDecr,
    TwistIncr,
    VerticalTwistDecr,
    VerticalTwistIncr,
    /// Randomize: bump seed by 1 (equivalent to the docs "Regenerate" button).
    Regenerate,
}

// ── Styling constants ───────────────────────────────────────────────────────

const PANEL_BG: Color = Color::srgb(0.05, 0.07, 0.12);
const PANEL_BORDER: Color = Color::srgb(0.25, 0.40, 0.62);
const TEXT_BRIGHT: Color = Color::srgb(0.82, 0.90, 1.0);
const TEXT_DIM: Color = Color::srgb(0.55, 0.65, 0.82);
const BUTTON_BG: Color = Color::srgb(0.10, 0.14, 0.22);

const PANEL_WIDTH: f32 = 280.0;
const PANEL_PADDING: f32 = 14.0;
const TITLE_FONT_SIZE: f32 = 20.0;
const LABEL_FONT_SIZE: f32 = 15.0;
const VALUE_FONT_SIZE: f32 = 15.0;
const BUTTON_FONT_SIZE: f32 = 16.0;
const HELP_FONT_SIZE: f32 = 12.0;

// ── Setup ───────────────────────────────────────────────────────────────────

pub fn setup_galaxy_ui(mut commands: Commands) {
    spawn_control_panel(&mut commands);
    spawn_info_panel_empty(&mut commands);
}

fn spawn_control_panel(commands: &mut Commands) {
    commands
        .spawn((
            Node {
                position_type: PositionType::Absolute,
                left: Val::Px(12.0),
                top: Val::Px(12.0),
                width: Val::Px(PANEL_WIDTH),
                padding: UiRect::all(Val::Px(PANEL_PADDING)),
                flex_direction: FlexDirection::Column,
                row_gap: Val::Px(6.0),
                border: UiRect::all(Val::Px(1.0)),
                ..default()
            },
            BackgroundColor(PANEL_BG),
            BorderColor(PANEL_BORDER),
            BorderRadius::all(Val::Px(8.0)),
            GalaxyControlPanel,
            GalaxyCreationSpawned,
        ))
        .with_children(|parent| {
            parent.spawn((
                Text::new("Galaxy Parameters"),
                TextFont {
                    font_size: TITLE_FONT_SIZE,
                    ..default()
                },
                TextColor(TEXT_BRIGHT),
                Node {
                    margin: UiRect::bottom(Val::Px(8.0)),
                    ..default()
                },
            ));

            // Current params are read at button-press time in `param_button_handler`,
            // so we don't need to thread `Res<GalaxyParams>` through setup.
            spawn_param_row(parent, "Seed", "seed", ParamButton::SeedDecr, ParamButton::SeedIncr);
            spawn_param_row(parent, "Systems", "count", ParamButton::CountDecr, ParamButton::CountIncr);
            spawn_param_row(parent, "Disk Arms", "arms", ParamButton::ArmsDecr, ParamButton::ArmsIncr);
            spawn_param_row(parent, "Vertical Arms", "varms", ParamButton::VerticalArmsDecr, ParamButton::VerticalArmsIncr);
            spawn_param_row(parent, "Size", "size", ParamButton::SizeDecr, ParamButton::SizeIncr);
            spawn_param_row(parent, "Twist", "twist", ParamButton::TwistDecr, ParamButton::TwistIncr);
            spawn_param_row(parent, "Vertical Twist", "vtwist", ParamButton::VerticalTwistDecr, ParamButton::VerticalTwistIncr);

            // Regenerate (randomize seed) button.
            parent
                .spawn((
                    Button,
                    Node {
                        width: Val::Percent(100.0),
                        height: Val::Px(32.0),
                        margin: UiRect::top(Val::Px(8.0)),
                        justify_content: JustifyContent::Center,
                        align_items: AlignItems::Center,
                        border: UiRect::all(Val::Px(1.0)),
                        ..default()
                    },
                    BackgroundColor(BUTTON_BG),
                    BorderColor(PANEL_BORDER),
                    BorderRadius::all(Val::Px(6.0)),
                    ParamButton::Regenerate,
                ))
                .with_children(|btn| {
                    btn.spawn((
                        Text::new("Regenerate"),
                        TextFont {
                            font_size: BUTTON_FONT_SIZE,
                            ..default()
                        },
                        TextColor(TEXT_BRIGHT),
                    ));
                });

            // Help text.
            parent.spawn((
                Text::new("Click a star to inspect • Esc to return"),
                TextFont {
                    font_size: HELP_FONT_SIZE,
                    ..default()
                },
                TextColor(TEXT_DIM),
                Node {
                    margin: UiRect::top(Val::Px(10.0)),
                    ..default()
                },
            ));
        });
}

/// Build a `[Label ........ value  [-] [+]]` row. The `value_key` is stored in
/// the marker as a label for the value text child; the actual value is read
/// from `GalaxyParams` at button-press time and updated by
/// `refresh_control_panel_values` each frame.
fn spawn_param_row(
    parent: &mut ChildSpawnerCommands,
    label: &str,
    value_key: &str,
    decr: ParamButton,
    incr: ParamButton,
) {
    parent
        .spawn(Node {
            width: Val::Percent(100.0),
            flex_direction: FlexDirection::Row,
            align_items: AlignItems::Center,
            column_gap: Val::Px(6.0),
            ..default()
        })
        .with_children(|row| {
            // Label — fixed width so values align.
            row.spawn((
                Text::new(label),
                TextFont {
                    font_size: LABEL_FONT_SIZE,
                    ..default()
                },
                TextColor(TEXT_DIM),
                Node {
                    width: Val::Px(118.0),
                    ..default()
                },
            ));

            // Value — flexible width, right-aligned textually by spacer below.
            row.spawn((
                Text::new("—"),
                TextFont {
                    font_size: VALUE_FONT_SIZE,
                    ..default()
                },
                TextColor(TEXT_BRIGHT),
                Node {
                    flex_grow: 1.0,
                    ..default()
                },
                ParamValue(value_key.to_string()),
            ));

            // [-] button.
            spawn_icon_button(row, "−", decr);
            // [+] button.
            spawn_icon_button(row, "+", incr);
        });
}

/// Marker on the value Text node so `refresh_control_panel_values` can find
/// and update it. The `String` is the param field name (e.g. "seed", "twist").
#[derive(Component)]
pub(crate) struct ParamValue(pub(crate) String);

fn spawn_icon_button(parent: &mut ChildSpawnerCommands, label: &str, marker: ParamButton) {
    parent
        .spawn((
            Button,
            Node {
                width: Val::Px(26.0),
                height: Val::Px(26.0),
                justify_content: JustifyContent::Center,
                align_items: AlignItems::Center,
                border: UiRect::all(Val::Px(1.0)),
                ..default()
            },
            BackgroundColor(BUTTON_BG),
            BorderColor(PANEL_BORDER),
            BorderRadius::all(Val::Px(4.0)),
            marker,
        ))
        .with_children(|btn| {
            btn.spawn((
                Text::new(label),
                TextFont {
                    font_size: BUTTON_FONT_SIZE,
                    ..default()
                },
                TextColor(TEXT_BRIGHT),
            ));
        });
}

/// Spawn the info panel in its "no selection" state. The selection module
/// replaces its contents whenever [`super::SelectedStar`] changes.
fn spawn_info_panel_empty(commands: &mut Commands) {
    commands
        .spawn((
            Node {
                position_type: PositionType::Absolute,
                right: Val::Px(12.0),
                top: Val::Px(12.0),
                width: Val::Px(PANEL_WIDTH),
                padding: UiRect::all(Val::Px(PANEL_PADDING)),
                flex_direction: FlexDirection::Column,
                row_gap: Val::Px(4.0),
                border: UiRect::all(Val::Px(1.0)),
                ..default()
            },
            BackgroundColor(PANEL_BG),
            BorderColor(PANEL_BORDER),
            BorderRadius::all(Val::Px(8.0)),
            GalaxyInfoPanel,
            GalaxyCreationSpawned,
        ))
        .with_children(|parent| {
            parent.spawn((
                Text::new("Selected System"),
                TextFont {
                    font_size: TITLE_FONT_SIZE,
                    ..default()
                },
                TextColor(TEXT_BRIGHT),
                Node {
                    margin: UiRect::bottom(Val::Px(8.0)),
                    ..default()
                },
            ));
            parent.spawn((
                Text::new("Click a star to inspect."),
                TextFont {
                    font_size: LABEL_FONT_SIZE,
                    ..default()
                },
                TextColor(TEXT_DIM),
            ));
        });
}

// ── Button handler ──────────────────────────────────────────────────────────

pub fn param_button_handler(
    mut params: ResMut<GalaxyParams>,
    query: Query<(&Interaction, &ParamButton), Changed<Interaction>>,
) {
    for (interaction, button) in &query {
        let &Interaction::Pressed = interaction else {
            continue;
        };
        match button {
            ParamButton::SeedDecr => {
                params.seed = params.seed.wrapping_sub(SEED_STEP);
                params.bump_generation();
            }
            ParamButton::SeedIncr => {
                params.seed = params.seed.wrapping_add(SEED_STEP);
                params.bump_generation();
            }
            ParamButton::CountDecr => {
                params.count = params.count.saturating_sub(COUNT_STEP).max(COUNT_MIN);
                params.bump_generation();
            }
            ParamButton::CountIncr => {
                params.count = (params.count + COUNT_STEP).min(COUNT_MAX);
                params.bump_generation();
            }
            ParamButton::ArmsDecr => {
                params.arms = params.arms.saturating_sub(1).max(ARMS_MIN);
                params.bump_generation();
            }
            ParamButton::ArmsIncr => {
                params.arms = params.arms.saturating_add(1).min(ARMS_MAX);
                params.bump_generation();
            }
            ParamButton::VerticalArmsDecr => {
                params.vertical_arms = params.vertical_arms.saturating_sub(1);
                params.bump_generation();
            }
            ParamButton::VerticalArmsIncr => {
                params.vertical_arms = params
                    .vertical_arms
                    .saturating_add(1)
                    .min(VERTICAL_ARMS_MAX);
                params.bump_generation();
            }
            ParamButton::SizeDecr => {
                params.size = (params.size - SIZE_STEP).max(SIZE_MIN);
                params.bump_generation();
            }
            ParamButton::SizeIncr => {
                params.size = (params.size + SIZE_STEP).min(SIZE_MAX);
                params.bump_generation();
            }
            ParamButton::TwistDecr => {
                params.twist = (params.twist - TWIST_STEP).max(TWIST_MIN);
                params.bump_generation();
            }
            ParamButton::TwistIncr => {
                params.twist = (params.twist + TWIST_STEP).min(TWIST_MAX);
                params.bump_generation();
            }
            ParamButton::VerticalTwistDecr => {
                params.vertical_twist = (params.vertical_twist - VERTICAL_TWIST_STEP).max(VERTICAL_TWIST_MIN);
                params.bump_generation();
            }
            ParamButton::VerticalTwistIncr => {
                params.vertical_twist = (params.vertical_twist + VERTICAL_TWIST_STEP).min(VERTICAL_TWIST_MAX);
                params.bump_generation();
            }
            ParamButton::Regenerate => params.reseed_and_bump(),
        }
    }
}

/// Refresh the displayed parameter values every frame so the UI stays in sync.
/// Bevy UI has no native data binding, so we manually patch the `Text` children
/// — cheap (≤14 nodes) and avoids re-spawning the whole panel.
pub fn refresh_control_panel_values(
    params: Res<GalaxyParams>,
    mut values: Query<(&ParamValue, &mut Text)>,
) {
    for (marker, mut text) in &mut values {
        let new = match marker.0.as_str() {
            "seed" => format!("{}", params.seed),
            "count" => format!("{}", params.count),
            "arms" => format!("{}", params.arms),
            "varms" => format!("{}", params.vertical_arms),
            "size" => format!("{:.0}", params.size),
            "twist" => format!("{:.1}", params.twist),
            "vtwist" => format!("{:.1}", params.vertical_twist),
            _ => continue,
        };
        if text.0 != new {
            text.0 = new;
        }
    }
}

// ── State wiring ────────────────────────────────────────────────────────────
//
// `setup_galaxy_ui` runs on OnEnter(GalaxyCreation) via the plugin in `mod.rs`.
// Despawning happens through the shared `GalaxyCreationSpawned` marker in the
// plugin's OnExit handler — no separate UI cleanup needed.
