use bevy::prelude::*;

#[derive(Component, Default)]
struct HeadSelector(pub usize);

#[derive(Component, Default)]
struct HeadImage(pub usize);

#[derive(Resource, Default)]
struct HeadsImages {
    heads: Vec<Handle<Image>>,
}

#[derive(Resource, Default)]
struct ActiveHeads {
    heads: [Option<usize>; 5],
    current_slot: usize,
}

#[derive(Event)]
pub struct HeadChanged(pub usize);

pub fn plugin(app: &mut App) {
    app.add_systems(Startup, setup);
    app.add_systems(Update, (update, toggle_heads));
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    let bg = asset_server.load("ui/head_bg.png");
    let regular = asset_server.load("ui/head_regular.png");
    let selector = asset_server.load("ui/selector.png");

    commands
        .spawn(Node {
            position_type: PositionType::Absolute,
            bottom: Val::Px(20.0),
            right: Val::Px(100.0),
            height: Val::Px(74.0),
            ..default()
        })
        .with_children(|parent| {
            spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 0);
            spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 1);
            spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 2);
            spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 3);
            spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 4);
        });

    let head_01 = asset_server.load("ui/heads/angry demonstrator.png");
    let head_02 = asset_server.load("ui/heads/commando.png");
    let head_03 = asset_server.load("ui/heads/goblin.png");
    let head_04 = asset_server.load("ui/heads/highland hammer thrower.png");
    let head_05 = asset_server.load("ui/heads/legionnaire.png");

    commands.insert_resource(HeadsImages {
        heads: vec![head_01, head_02, head_03, head_04, head_05],
    });

    commands.insert_resource(ActiveHeads {
        heads: [Some(0), Some(1), Some(2), Some(3), Some(4)],
        current_slot: 0,
    });
}

fn spawn_head_ui(
    parent: &mut ChildBuilder,
    bg: Handle<Image>,
    regular: Handle<Image>,
    selector: Handle<Image>,
    head: usize,
) {
    parent
        .spawn((Node {
            position_type: PositionType::Relative,
            justify_content: JustifyContent::Center,
            width: Val::Px(74.0),
            ..default()
        },))
        .with_children(|parent| {
            parent.spawn((
                Node {
                    position_type: PositionType::Absolute,
                    top: Val::Px(-20.0),
                    ..default()
                },
                Visibility::Hidden,
                ImageNode::new(selector),
                HeadSelector(head),
            ));
            parent.spawn((
                Node {
                    position_type: PositionType::Absolute,
                    ..default()
                },
                ImageNode::new(bg),
            ));
            parent.spawn((
                Node {
                    position_type: PositionType::Absolute,
                    left: Val::Px(2.0),
                    right: Val::Px(2.0),
                    top: Val::Px(2.0),
                    bottom: Val::Px(2.0),
                    ..default()
                },
                ImageNode::default(),
                Visibility::Hidden,
                HeadImage(head),
            ));
            parent.spawn((
                Node {
                    position_type: PositionType::Absolute,
                    ..default()
                },
                ImageNode::new(regular),
            ));
        });
}

fn update(
    res: Res<ActiveHeads>,
    heads_images: Res<HeadsImages>,
    mut head_image: Query<(&HeadImage, &mut Visibility, &mut ImageNode), Without<HeadSelector>>,
    mut head_selector: Query<(&HeadSelector, &mut Visibility), Without<HeadImage>>,
) {
    if res.is_changed() {
        for (HeadImage(head), mut vis, mut image) in head_image.iter_mut() {
            if let Some(head) = res.heads[*head] {
                *vis = Visibility::Visible;
                image.image = heads_images.heads[head].clone();
            } else {
                *vis = Visibility::Hidden;
            }
        }
        for (HeadSelector(head), mut vis) in head_selector.iter_mut() {
            *vis = if *head == res.current_slot {
                Visibility::Visible
            } else {
                Visibility::Hidden
            };
        }
    }
}

fn toggle_heads(
    mut commands: Commands,
    mut res: ResMut<ActiveHeads>,
    keys: Res<ButtonInput<KeyCode>>,
) {
    let changed = if keys.just_pressed(KeyCode::KeyE) {
        res.current_slot = (res.current_slot + 1) % 5;
        true
    } else if keys.just_pressed(KeyCode::KeyQ) {
        res.current_slot = (res.current_slot + 4) % 5;
        true
    } else {
        false
    };

    if changed {
        commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap()));
    }
}
