use bevy::prelude::*;

use monologue_trees::{debug::*, text::*};

const LOREM: [&str; 5] = [
    "Ullam nostrum aut amet adipisci consequuntur quisquam nemo consequatur. Vel eum et ullam ullam aperiam earum voluptas consequuntur. Blanditiis earum voluptatem voluptas animi dolorum fuga aliquam ea.\n",
    "Velit ratione consequatur modi. Dolores quo quisquam occaecati veniam maxime totam minus et. Laudantium unde optio vel. Et cumque voluptatum dolorem. Odit tempore dolores quibusdam aspernatur vitae labore occaecati. Omnis quia tempora tenetur repellat in.\n",
    "Dolores perspiciatis tempore in consequuntur in minus autem. Voluptatem quas dignissimos quae ut necessitatibus illo ducimus. Quis fuga nisi non ut sunt velit.\n",
    "Sit quia officia alias hic. Incidunt sed vitae optio cumque rerum corrupti perferendis enim. Adipisci necessitatibus illum vero placeat saepe aut et.\n",
    "Velit perspiciatis doloribus consectetur. Doloremque ea non optio itaque. Voluptatem sint voluptatum minus.\n",
];

fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins.set(WindowPlugin {
                primary_window: Some(Window {
                    title: "Text Inspect".into(),
                    resolution: (640., 480.).into(),
                    ..default()
                }),
                ..default()
            }),
            DebugInfoPlugin,
            AnimatedTextPlugin,
        ))
        .add_systems(PreStartup, load_fonts)
        .add_systems(Startup, init_ui)
        .add_systems(
            Update,
            (
                manage_buttons,
                manage_animation_button,
                manage_fonts,
                mouse_cursor,
                manage_animation,
            ),
        )
        .run();
}

#[derive(Resource)]
struct Fonts(Vec<Handle<Font>>);

#[derive(Component)]
struct PreviewText;

#[derive(Component)]
struct ButtonShelf;

#[derive(Component)]
struct FontButton(Handle<Font>);

#[derive(Component)]
struct AnimationButton;

fn load_fonts(mut commands: Commands, server: Res<AssetServer>) {
    let handles = server
        .load_folder("fonts")
        .expect("Load fonts folder")
        .iter()
        .map(|untyped| untyped.clone().typed::<Font>())
        .collect();
    commands.insert_resource(Fonts(handles));
}

fn init_ui(mut commands: Commands) {
    commands.spawn(Camera2dBundle { ..default() });

    commands
        .spawn(NodeBundle {
            style: Style {
                width: Val::Percent(100.0),
                height: Val::Percent(100.0),
                ..default()
            },
            background_color: BackgroundColor(Color::BLACK),
            ..default()
        })
        .with_children(|parent| {
            parent.spawn((
                NodeBundle {
                    style: Style {
                        flex_direction: FlexDirection::Column,
                        align_items: AlignItems::Center,
                        width: Val::Px(200.0),
                        align_content: AlignContent::SpaceEvenly,
                        ..default()
                    },
                    background_color: BackgroundColor(Color::BLACK),
                    ..default()
                },
                ButtonShelf,
            ));

            parent.spawn((
                AnimatedTextBundle {
                    text_bundle: TextBundle {
                        text: Text {
                            sections: LOREM
                                .iter()
                                .map(|&line| TextSection {
                                    value: line.into(),
                                    style: TextStyle {
                                        font_size: 18.0,
                                        color: Color::WHITE,
                                        ..default()
                                    },
                                })
                                .collect(),
                            ..default()
                        },
                        style: Style {
                            width: Val::Px(400.0),
                            ..default()
                        },
                        ..default()
                    },
                    animated_text: AnimatedText::new(TextAnimationType::Typing(12.0)),
                },
                PreviewText,
            ));

            parent
                .spawn((
                    ButtonBundle {
                        style: Style {
                            align_self: AlignSelf::FlexEnd,
                            position_type: PositionType::Absolute,
                            bottom: Val::Px(5.0),
                            left: Val::Px(5.0),
                            width: Val::Px(200.0),
                            ..default()
                        },
                        background_color: BackgroundColor(Color::default().with_a(0.0)),
                        ..default()
                    },
                    AnimationButton,
                ))
                .with_children(|parent| {
                    parent.spawn((
                        TextBundle {
                            text: Text {
                                sections: vec![TextSection {
                                    value: "Toggle Animation".into(),
                                    style: TextStyle {
                                        font_size: 12.0,
                                        color: Color::WHITE,
                                        ..default()
                                    },
                                }],
                                ..default()
                            },
                            ..default()
                        },
                        AnimationButton,
                    ));
                });
        });
}

// Add/remove buttons from shelf with font name(s)
fn manage_buttons(
    mut commands: Commands,
    fonts: Res<Fonts>,
    server: Res<AssetServer>,
    shelf_query: Query<Entity, With<ButtonShelf>>,
) {
    if fonts.is_added() || fonts.is_changed() {
        let root = shelf_query.get_single().expect("Fetching root UI node");
        let mut root_cmd = commands.get_entity(root).expect("Root UI node commands");

        root_cmd.clear_children();
        root_cmd.with_children(|root| {
            fonts.0.iter().for_each(|font| {
                let handle_path = server
                    .get_handle_path(font.clone())
                    .expect("Get handle path");
                let path = handle_path.path().to_str().expect("Convert path to str");
                let fname = path
                    .split("/")
                    .last()
                    .expect("Extracting filename")
                    .trim_end_matches(".otf")
                    .trim_end_matches(".ttf");

                let style = TextStyle {
                    font: font.clone(),
                    color: Color::BLACK,
                    font_size: 16.0,
                };

                root.spawn((
                    ButtonBundle {
                        style: Style {
                            align_content: AlignContent::Center,
                            // size: Size {
                            //     width: Val::Undefined,
                            //     height: Val::Undefined,
                            // },
                            padding: UiRect::all(Val::Px(5.0)),
                            ..default()
                        },
                        ..default()
                    },
                    FontButton(font.clone()),
                ))
                .with_children(|parent| {
                    info!("Adding {} button", fname);
                    parent.spawn(TextBundle::from_section(fname, style));
                });
            });
        });
    }
}

fn manage_fonts(
    mut texts: Query<&mut Text, With<PreviewText>>,
    interaction: Query<(&Interaction, &FontButton), Changed<Interaction>>,
) {
    for (i, f) in interaction.iter() {
        match (i, f) {
            (Interaction::Pressed, FontButton(font)) => {
                texts.single_mut().sections.iter_mut().for_each(|section| {
                    section.style.font = font.clone();
                });
            }
            _ => (),
        }
    }
}

fn manage_animation_button(
    mut animation_button: Query<&mut Text, With<AnimationButton>>,
    interaction: Query<(&Interaction, &FontButton), Changed<Interaction>>,
) {
    for (i, f) in interaction.iter() {
        match (i, f) {
            (Interaction::Pressed, FontButton(font)) => {
                animation_button
                    .single_mut()
                    .sections
                    .iter_mut()
                    .for_each(|section| section.style.font = font.clone());
            }
            _ => (),
        }
    }
}

fn mouse_cursor(
    mut windows: Query<&mut Window>,
    interactions: Query<&Interaction, (Changed<Interaction>, With<Button>)>,
) {
    for interaction in interactions.iter() {
        let mut window = windows.single_mut();

        window.cursor.icon = match interaction {
            Interaction::Hovered | Interaction::Pressed => CursorIcon::Hand,
            Interaction::None => CursorIcon::Arrow,
        }
    }
}

fn manage_animation(
    mut animated_texts: Query<&mut AnimatedText, With<PreviewText>>,
    interactions: Query<&Interaction, (Changed<Interaction>, With<AnimationButton>)>,
) {
    for interaction in interactions.iter() {
        match interaction {
            Interaction::Pressed => {
                info!("toggling animation");

                let mut anim = animated_texts
                    .get_single_mut()
                    .expect("Loading animated text");
                anim.toggle();
            }
            _ => (),
        }
    }
}
