use beuvy_runtime::input::InputType;
use beuvy_runtime::input::InputValueChangedMessage;
use beuvy_runtime::scroll_container_node;
use beuvy_runtime::text::FontResource;
use beuvy_runtime::text::set_plain_text;
use beuvy_runtime::{AddButton, AddInput, AddSelect, AddSelectOption, AddText, UiKitPlugin};
use bevy::prelude::*;
use bevy::text::TextLayout;

#[derive(Component)]
struct SliderValueText;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                title: "beuvy-runtime basic controls".to_string(),
                resolution: (1280, 860).into(),
                ..default()
            }),
            ..default()
        }))
        .add_plugins(UiKitPlugin)
        .add_systems(Startup, setup)
        .add_systems(Update, sync_slider_value_label)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(Camera2d);
    commands.insert_resource(FontResource::from_handle(
        asset_server.load("fonts/SarasaFixedSC-Regular.ttf"),
    ));

    commands
        .spawn((
            scroll_container_node(Node {
                width: Val::Percent(100.0),
                height: Val::Percent(100.0),
                padding: UiRect::all(Val::Px(24.0)),
                column_gap: Val::Px(20.0),
                align_items: AlignItems::Start,
                ..default()
            }),
            ScrollPosition::default(),
            BackgroundColor(Color::srgb_u8(245, 247, 250)),
        ))
        .with_children(|parent| {
            spawn_column(parent, |parent| {
                spawn_panel(parent, "Text", |parent| {
                    spawn_text(parent, "Display Title", 22.0, Color::srgb_u8(15, 23, 42));
                    spawn_text(
                        parent,
                        "Body copy rendered through the runtime text builder.",
                        15.0,
                        Color::srgb_u8(30, 41, 59),
                    );
                    spawn_text(
                        parent,
                        "Secondary hint text for dense tool UIs.",
                        13.0,
                        Color::srgb_u8(100, 116, 139),
                    );
                });

                spawn_panel(parent, "Text Inputs", |parent| {
                    parent.spawn(AddInput {
                        name: "pilot_name".to_string(),
                        placeholder: "Pilot name".to_string(),
                        size_chars: Some(24),
                        ..default()
                    });
                    parent.spawn(AddInput {
                        name: "callsign".to_string(),
                        value: "ALPHA-7".to_string(),
                        size_chars: Some(16),
                        ..default()
                    });
                    parent.spawn(AddInput {
                        name: "long_note".to_string(),
                        value: "Long single-line value for caret scrolling and selection checks"
                            .to_string(),
                        placeholder: "Long note".to_string(),
                        size_chars: Some(28),
                        ..default()
                    });
                    parent.spawn(AddInput {
                        name: "multiline_note".to_string(),
                        input_type: InputType::Textarea,
                        value: "Textarea value for native multiline wrapping, caret movement,\nand segmented selection checks."
                            .to_string(),
                        placeholder: "Multiline note".to_string(),
                        size_chars: Some(28),
                        rows: Some(4),
                        ..default()
                    });
                    parent.spawn(AddInput {
                        name: "ime_text".to_string(),
                        placeholder: "中文 IME input".to_string(),
                        size_chars: Some(20),
                        ..default()
                    });
                    parent.spawn(AddInput {
                        name: "ime_textarea".to_string(),
                        input_type: InputType::Textarea,
                        placeholder: "中文 IME textarea".to_string(),
                        size_chars: Some(28),
                        rows: Some(3),
                        ..default()
                    });
                    parent.spawn(AddInput {
                        name: "disabled_text".to_string(),
                        value: "Locked field".to_string(),
                        size_chars: Some(18),
                        disabled: true,
                        ..default()
                    });
                });

                spawn_panel(parent, "Numeric Inputs", |parent| {
                    spawn_row(parent, |parent| {
                        parent.spawn(AddInput {
                            name: "count".to_string(),
                            input_type: InputType::Number,
                            value: "12".to_string(),
                            min: Some(0.0),
                            max: Some(64.0),
                            step: Some(1.0),
                            size_chars: Some(8),
                            ..default()
                        });
                        parent.spawn(AddInput {
                            name: "threshold".to_string(),
                            input_type: InputType::Number,
                            value: ".".to_string(),
                            min: Some(0.0),
                            max: Some(1.0),
                            step: Some(0.05),
                            size_chars: Some(8),
                            ..default()
                        });
                    });
                    parent.spawn((
                        SliderValueText,
                        Node {
                            width: Val::Percent(100.0),
                            ..default()
                        },
                        TextLayout::default(),
                        AddText {
                            text: "Volume: 45".to_string(),
                            size: 14.0,
                            color: Color::srgb_u8(71, 85, 105),
                            ..default()
                        },
                    ));
                    parent.spawn(AddInput {
                        name: "volume".to_string(),
                        input_type: InputType::Range,
                        value: "45".to_string(),
                        min: Some(0.0),
                        max: Some(100.0),
                        step: Some(5.0),
                        ..default()
                    });
                });

                spawn_panel(parent, "Form Toggles", |parent| {
                    spawn_labeled_toggle_row(
                        parent,
                        "Checkbox input",
                        AddInput {
                            name: "enable_audio".to_string(),
                            input_type: InputType::Checkbox,
                            checked: true,
                            ..default()
                        },
                    );
                    spawn_labeled_toggle_row(
                        parent,
                        "Radio input (easy)",
                        AddInput {
                            name: "mode".to_string(),
                            input_type: InputType::Radio,
                            value: "easy".to_string(),
                            checked: true,
                            ..default()
                        },
                    );
                    spawn_labeled_toggle_row(
                        parent,
                        "Radio input (hard)",
                        AddInput {
                            name: "mode".to_string(),
                            input_type: InputType::Radio,
                            value: "hard".to_string(),
                            ..default()
                        },
                    );
                    spawn_field(parent, "Password input", |parent| {
                        parent.spawn(AddInput {
                            name: "secret".to_string(),
                            input_type: InputType::Password,
                            value: "hunter2".to_string(),
                            placeholder: "Password".to_string(),
                            size_chars: Some(20),
                            ..default()
                        });
                    });
                });
            });

            spawn_column(parent, |parent| {
                spawn_panel(parent, "Selects", |parent| {
                    parent.spawn(AddSelect {
                        name: "difficulty".to_string(),
                        value: "normal".to_string(),
                        options: vec![
                            option("difficulty_easy", "easy", "Easy"),
                            option("difficulty_normal", "normal", "Normal"),
                            option("difficulty_hard", "hard", "Hard"),
                        ],
                        ..default()
                    });
                    parent.spawn(AddSelect {
                        name: "region".to_string(),
                        value: "us-east".to_string(),
                        options: vec![
                            option("region_use1", "us-east", "US East"),
                            option("region_euw1", "eu-west", "EU West"),
                            AddSelectOption {
                                name: "region_apac".to_string(),
                                value: "apac".to_string(),
                                text: "APAC (disabled)".to_string(),
                                localized_text: None,
                                localized_text_format: None,
                                disabled: true,
                            },
                        ],
                        ..default()
                    });
                });

                spawn_panel(parent, "Buttons", |parent| {
                    spawn_field_label(parent, "Default");
                    spawn_row(parent, |parent| {
                        parent.spawn(AddButton {
                            name: "default_primary".to_string(),
                            text: "Primary Action".to_string(),
                            class: Some("button-root w-[180px]".to_string()),
                            ..default()
                        });
                        parent.spawn(AddButton {
                            name: "default_secondary".to_string(),
                            text: "Secondary Action".to_string(),
                            class: Some("button-root w-[180px]".to_string()),
                            ..default()
                        });
                    });

                    spawn_field_label(parent, "Sizing");
                    spawn_row(parent, |parent| {
                        parent.spawn(AddButton {
                            name: "compact".to_string(),
                            text: "Compact".to_string(),
                            class: Some(
                                "button-root min-h-[30px] w-[120px] px-[8px] py-[4px]".to_string(),
                            ),
                            ..default()
                        });
                        parent.spawn(AddButton {
                            name: "wide".to_string(),
                            text: "Wide Button".to_string(),
                            class: Some("button-root min-h-[48px] w-[220px]".to_string()),
                            ..default()
                        });
                    });

                    spawn_field_label(parent, "Disabled");
                    spawn_row(parent, |parent| {
                        parent.spawn(AddButton {
                            name: "disabled_default".to_string(),
                            text: "Disabled".to_string(),
                            disabled: true,
                            ..default()
                        });
                        parent.spawn(AddButton {
                            name: "disabled_wide".to_string(),
                            text: "Disabled Wide".to_string(),
                            disabled: true,
                            class: Some("button-root min-h-[48px] w-[220px]".to_string()),
                            ..default()
                        });
                    });
                });
            });
        });
}

fn sync_slider_value_label(
    mut commands: Commands,
    mut events: MessageReader<InputValueChangedMessage>,
    labels: Query<Entity, With<SliderValueText>>,
) {
    let Some(label) = labels.iter().next() else {
        return;
    };
    for event in events.read() {
        if event.name == "volume" {
            set_plain_text(&mut commands, label, format!("Volume: {}", event.value));
        }
    }
}

fn spawn_column(
    parent: &mut ChildSpawnerCommands,
    children: impl FnOnce(&mut ChildSpawnerCommands),
) {
    parent
        .spawn(Node {
            width: Val::Px(600.0),
            row_gap: Val::Px(20.0),
            flex_direction: FlexDirection::Column,
            overflow: Overflow::visible(),
            ..default()
        })
        .with_children(children);
}

fn spawn_panel(
    parent: &mut ChildSpawnerCommands,
    title: &str,
    children: impl FnOnce(&mut ChildSpawnerCommands),
) {
    let mut panel = parent.spawn(Node {
        width: Val::Percent(100.0),
        min_height: Val::Px(200.0),
        padding: UiRect::all(Val::Px(16.0)),
        row_gap: Val::Px(12.0),
        flex_direction: FlexDirection::Column,
        overflow: Overflow::visible(),
        border_radius: BorderRadius::all(Val::Px(12.0)),
        ..default()
    });
    panel.insert(BorderColor::all(Color::srgb_u8(209, 213, 219)));
    panel.insert(BackgroundColor(Color::WHITE));
    panel.with_children(|parent| {
        spawn_text(parent, title, 18.0, Color::srgb_u8(15, 23, 42));
        children(parent);
    });
}

fn spawn_field(
    parent: &mut ChildSpawnerCommands,
    label: &str,
    children: impl FnOnce(&mut ChildSpawnerCommands),
) {
    parent
        .spawn(Node {
            width: Val::Percent(100.0),
            row_gap: Val::Px(10.0),
            flex_direction: FlexDirection::Column,
            ..default()
        })
        .with_children(|parent| {
            spawn_field_label(parent, label);
            children(parent);
        });
}

fn spawn_labeled_toggle_row(parent: &mut ChildSpawnerCommands, label: &str, input: AddInput) {
    parent
        .spawn(Node {
            column_gap: Val::Px(12.0),
            align_items: AlignItems::Center,
            ..default()
        })
        .with_children(|row| {
            row.spawn(input);
            spawn_inline_label(row, label);
        });
}

fn spawn_row(parent: &mut ChildSpawnerCommands, children: impl FnOnce(&mut ChildSpawnerCommands)) {
    parent
        .spawn(Node {
            column_gap: Val::Px(10.0),
            row_gap: Val::Px(10.0),
            flex_wrap: FlexWrap::Wrap,
            overflow: Overflow::visible(),
            ..default()
        })
        .with_children(children);
}

fn spawn_field_label(parent: &mut ChildSpawnerCommands, text: &str) {
    parent.spawn((
        Node::default(),
        TextLayout::default(),
        AddText {
            text: text.to_string(),
            size: 13.0,
            color: Color::srgb_u8(75, 85, 99),
            ..default()
        },
    ));
}

fn spawn_inline_label(parent: &mut ChildSpawnerCommands, text: &str) {
    parent.spawn((
        Node::default(),
        TextLayout::default(),
        AddText {
            text: text.to_string(),
            size: 15.0,
            color: Color::srgb_u8(31, 41, 55),
            ..default()
        },
    ));
}

fn spawn_text(parent: &mut ChildSpawnerCommands, text: &str, size: f32, color: Color) {
    parent.spawn((
        Node {
            width: Val::Percent(100.0),
            ..default()
        },
        TextLayout::default(),
        AddText {
            text: text.to_string(),
            size,
            color,
            ..default()
        },
    ));
}

fn option(name: &str, value: &str, text: &str) -> AddSelectOption {
    AddSelectOption {
        name: name.to_string(),
        value: value.to_string(),
        text: text.to_string(),
        localized_text: None,
        localized_text_format: None,
        disabled: false,
    }
}
