//! Player-specific behavior.

use bevy::{
    image::{ImageLoaderSettings, ImageSampler},
    prelude::*,
};
use bevy_ecs_ldtk::prelude::*;

use crate::{
    AppSystems, PausableSystems,
    asset_tracking::LoadResource,
    demo::{
        // animation::PlayerAnimation,
        movement::MovementController,
    },
    screens::Screen,
};

pub(super) fn plugin(app: &mut App) {
    app.register_type::<Player>();

    app.register_type::<PlayerAssets>();
    app.load_resource::<PlayerAssets>();
    app.register_ldtk_entity::<PlayerBundle>("Player");

    // Record directional input as movement controls.
    app.add_systems(
        Update,
        record_player_directional_input
            .in_set(AppSystems::RecordInput)
            .in_set(PausableSystems),
    );
    app.add_systems(Update, process_player);
}

/// The player character.
// pub fn player(
//     max_speed: f32,
//     player_assets: &PlayerAssets,
//     texture_atlas_layouts: &mut Assets<TextureAtlasLayout>,
// ) -> impl Bundle {
//     // A texture atlas is a way to split a single image into a grid of related images.
//     // You can learn more in this example: https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs
//     let layout =
//         TextureAtlasLayout::from_grid(UVec2::new(64, 64), 9, 54, Some(UVec2::splat(1)), None);
//     let texture_atlas_layout = texture_atlas_layouts.add(layout);
//     let player_animation = PlayerAnimation::new();
//
//     (
//         Name::new("Player"),
//         Player,
//         Sprite {
//             image: player_assets.ducky.clone(),
//             texture_atlas: Some(TextureAtlas {
//                 layout: texture_atlas_layout,
//                 index: player_animation.get_atlas_index(),
//             }),
//             ..default()
//         },
//         // Transform::from_scale(Vec2::splat(1.0).extend(1.0)),
//         MovementController {
//             max_speed,
//             ..default()
//         },
//         ScreenWrap,
//         player_animation,
//     )
// }

#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Default, Reflect)]
#[reflect(Component)]
pub struct Player;

#[derive(Default, Bundle, LdtkEntity)]
struct PlayerBundle {
    #[sprite_sheet]
    sprite_sheet: Sprite,
    #[worldly]
    worldly: Worldly,
    #[grid_coords]
    grid_coords: GridCoords,
    // non-ecsldtk-related components
    player_comp: Player,
    movement: MovementController,
}

fn record_player_directional_input(
    input: Res<ButtonInput<KeyCode>>,
    mut controller_query: Query<&mut MovementController, With<Player>>,
) {
    // Collect directional input.
    let mut intent = Vec2::ZERO;
    // TODO: example ldkt has down -1 and up +1... but here the opposite happens?!
    // additionally: why the heck the Player is offsetted by 25 y?
    // why the player is displayed at its set location but then is teleported the first time I
    // update its GridCoords?
    if input.just_pressed(KeyCode::KeyW) || input.pressed(KeyCode::ArrowUp) {
        intent.y += 1.0;
    }
    if input.just_pressed(KeyCode::KeyS) || input.pressed(KeyCode::ArrowDown) {
        intent.y -= 1.0;
    }
    if input.just_pressed(KeyCode::KeyA) || input.pressed(KeyCode::ArrowLeft) {
        intent.x -= 1.0;
    }
    if input.just_pressed(KeyCode::KeyD) || input.pressed(KeyCode::ArrowRight) {
        intent.x += 1.0;
    }

    // Normalize intent so that diagonal movement is the same speed as horizontal / vertical.
    // This should be omitted if the input comes from an analog stick instead.
    let intent = intent.normalize_or_zero();

    // Apply movement intent to controllers.
    for mut controller in &mut controller_query {
        controller.intent = intent;
    }
}

#[derive(Resource, Asset, Clone, Reflect)]
#[reflect(Resource)]
pub struct PlayerAssets {
    #[dependency]
    ducky: Handle<Image>,
    #[dependency]
    pub steps: Vec<Handle<AudioSource>>,
}

impl FromWorld for PlayerAssets {
    fn from_world(world: &mut World) -> Self {
        let assets = world.resource::<AssetServer>();
        Self {
            ducky: assets.load_with_settings(
                "spritesheets/researcher.png",
                |settings: &mut ImageLoaderSettings| {
                    // Use `nearest` image sampling to preserve pixel art style.
                    settings.sampler = ImageSampler::nearest();
                },
            ),
            steps: vec![
                assets.load("audio/sound_effects/step1.ogg"),
                assets.load("audio/sound_effects/step2.ogg"),
                assets.load("audio/sound_effects/step3.ogg"),
                assets.load("audio/sound_effects/step4.ogg"),
            ],
        }
    }
}

fn process_player(
    mut commands: Commands,
    new_players: Query<(Entity, &GridCoords), Added<Player>>,
) {
    for (player_entity, player_coords) in new_players.iter() {
        info!(
            "Spawned new player: {:?} at {:?}",
            player_entity, player_coords
        );
        commands
            .entity(player_entity)
            .insert(StateScoped(Screen::Gameplay));
    }
}
