use bevy::{ecs::spawn::SpawnWith, prelude::*};
use bevy_ui_text_input::{TextInputMode, TextInputNode, TextInputPrompt};

use crate::game::debug::console::{ConsoleEvent, ConsoleLog};

use super::DebugConsole;

#[derive(Component)]
pub struct Prompt;
#[derive(Component)]
pub struct Content;

pub fn console(data: ConsoleLog, asset_server: AssetServer) -> impl Bundle {
    (
        DebugConsole,
        Node {
            justify_self: JustifySelf::Center,
            width: Val::Percent(85.),
            max_height: Val::Percent(100. / 3.),
            flex_direction: FlexDirection::Column,
            border: UiRect {
                left: Val::Px(2.),
                right: Val::Px(2.),
                top: Val::Px(0.),
                bottom: Val::Px(2.),
            },
            ..default()
        },
        BorderColor(Color::BLACK),
        ZIndex(i32::MAX),
        BackgroundColor(Color::Srgba(Srgba::BLACK.with_alpha(0.2))),
        children![
            (
                Content,
                Node {
                    padding: UiRect::all(Val::Px(10.)),
                    overflow: Overflow::scroll_y(),
                    flex_direction: FlexDirection::Column,
                    ..default()
                },
                Children::spawn(SpawnWith({
                    let asset_server = asset_server.clone();
                    move |parent: &mut ChildSpawner| {
                        for item in data.0 {
                            match item {
                                ConsoleEvent::Input(s) => {
                                    parent.spawn(input(s.to_string(), &asset_server))
                                }
                                ConsoleEvent::Output(s) => {
                                    parent.spawn(output(s.to_string(), &asset_server))
                                }
                                ConsoleEvent::Error(s) => {
                                    parent.spawn(error(s.to_string(), &asset_server))
                                }
                            };
                        }
                    }
                }))
            ),
            (
                Node {
                    width: Val::Percent(100.),
                    padding: UiRect {
                        left: Val::Px(10.),
                        right: Val::Px(10.),
                        top: Val::Px(10.),
                        bottom: Val::Px(10.)
                    },
                    ..default()
                },
                BackgroundColor(Color::Srgba(Srgba::gray(0.2).with_alpha(0.3))),
                children![
                    (
                        Text::new("> "),
                        TextFont {
                            font: asset_server
                                .load("fonts/DepartureMono-1.500/DepartureMono-Regular.otf"),
                            font_size: 14.,
                            ..default()
                        }
                    ),
                    (
                        Prompt,
                        Node {
                            width: Val::Auto,
                            flex_grow: 1.,
                            ..default()
                        },
                        TextInputNode {
                            clear_on_submit: true,
                            mode: TextInputMode::SingleLine,
                            is_enabled: true,
                            focus_on_pointer_down: true,
                            ..default()
                        },
                        TextInputPrompt {
                            text: String::new(),
                            ..default()
                        },
                        TextFont {
                            font: asset_server
                                .load("fonts/DepartureMono-1.500/DepartureMono-Regular.otf"),
                            font_size: 14.,
                            ..default()
                        },
                    )
                ]
            ),
        ],
    )
}

pub fn input(content: String, asset_server: &AssetServer) -> impl Bundle {
    console_output(
        Srgba::GREEN.with_alpha(0.05),
        UiRect::all(Val::Px(1.)),
        Srgba::GREEN,
        format!("> {content}"),
        asset_server,
    )
}
pub fn output(content: String, asset_server: &AssetServer) -> impl Bundle {
    console_output(
        Srgba::WHITE.with_alpha(0.05),
        UiRect::all(Val::ZERO),
        Srgba::NONE,
        content,
        asset_server,
    )
}
pub fn error(content: String, asset_server: &AssetServer) -> impl Bundle {
    console_output(
        Srgba::RED.with_alpha(0.025),
        UiRect::all(Val::Px(2.)),
        Srgba::RED.with_alpha(0.75),
        content,
        asset_server,
    )
}

fn console_output(
    background_color: Srgba,
    border_width: UiRect,
    border_color: Srgba,
    content: String,
    asset_server: &AssetServer,
) -> impl Bundle {
    (
        Node {
            margin: UiRect {
                left: Val::Px(0.),
                right: Val::Px(0.),
                top: Val::Px(0.),
                bottom: Val::Px(10.),
            },
            padding: UiRect::all(Val::Px(7.5)),
            border: border_width,
            ..default()
        },
        BorderRadius::all(Val::Px(7.5)),
        BorderColor(Color::Srgba(border_color)),
        BackgroundColor(Color::Srgba(background_color)),
        Pickable {
            should_block_lower: false,
            ..default()
        },
        children![(
            Text(content),
            TextFont {
                font: asset_server.load("fonts/DepartureMono-1.500/DepartureMono-Regular.otf"),
                font_size: 14.,
                ..default()
            },
            Pickable {
                should_block_lower: false,
                ..default()
            },
        )],
    )
}
