//! hello_quad, rebuilt on the App facade (learning path step 8 milestone).
//!
//! Same window, same cornflower blue, same white 64x64 quad, same arrow
//! keys as examples/hello_quad.rs. What changed is WHERE things live:
//! state moved from a struct's fields into World components, and behavior
//! moved from trait methods into registered systems. Compare the two files
//! side by side; that comparison is the whole lesson.
//!
//! Run: cargo run --example hello_quad_ecs

use mawida::math::Vec3;
use mawida::{App, AppConfig, AudioModule, Color, InputState, Key, OrthographicCamera,
             RenderQueue, Result, Sprite, Transform, World};

// Components are YOUR plain structs. The engine never sees their types;
// they live in the World's columns like any other data.
struct Quad {
    w: f32,
    h: f32,
    color: Color,
}

struct Player {
    speed: f32,
}

/// Runs once against the fresh World (FnOnce): the scene-population code.
fn setup(world: &mut World) {
    let e = world.spawn();
    world.insert(e, Transform::from_xy(100.0, 100.0));
    world.insert(
        e,
        Quad { w: 64.0, h: 64.0, color: Color::WHITE },
    );
    world.insert(e, Player { speed: 300.0 });
}

/// System 1: input -> motion. Same math as hello_quad's update(); the input
/// arrives as a World resource (plain data), not through a Context.
fn movement(world: &mut World, dt: f32) {
    let input = world.resource::<InputState>().clone();
    let (xforms, players) = world.columns_mut::<Transform, Player>();
    for (t, p) in xforms.iter_mut().zip(players.iter()) {
        if let (Some(t), Some(p)) = (t, p) {
            let mut d = Vec3::ZERO;
            if input.is_down(Key::Left) {
                d.x -= 1.0;
            }
            if input.is_down(Key::Right) {
                d.x += 1.0;
            }
            if input.is_down(Key::Up) {
                d.y -= 1.0; // y-down screen space
            }
            if input.is_down(Key::Down) {
                d.y += 1.0;
            }
            t.translation += d * p.speed * dt;
        }
    }
}

/// System 2: the render system. Same fn(&mut World, f32) shape as movement;
/// it does not touch wgpu. It records WHAT to draw through WHICH camera into
/// the RenderQueue resource; the runner replays that between begin_frame and
/// end_frame. Seam 3: a sprite stays mesh + material + transform.
fn render_sprites(world: &mut World, _dt: f32) {
    let camera = *world.resource::<OrthographicCamera>();
    let mut frame = Vec::new();
    let (xforms, quads) = world.columns_mut::<Transform, Quad>();
    for (t, q) in xforms.iter().zip(quads.iter()) {
        if let (Some(t), Some(q)) = (t, q) {
            let mut s = Sprite::solid(q.color, t.translation.x, t.translation.y, q.w, q.h);
            s.transform.rotation = t.rotation; // carry the full 3D transform
            frame.push((s, camera));
        }
    }
    world.resource_mut::<RenderQueue>().sprites = frame;
}

// The payoff of "systems compose": spin knows nothing about movement and
// touches zero existing lines. Uncomment it and its .add_system line, and
// the quad rotates while you steer it. Moving that line before movement is
// your first scheduler-ordering experiment.
//
// fn spin(world: &mut World, dt: f32) {
//     use mawida::Quat;
//     for t in world.column_mut::<Transform>().iter_mut().flatten() {
//         t.rotation *= Quat::from_rotation_z(1.5 * dt); // seam 1: math is 3D
//     }
// }

fn main() -> Result<()> {
    App::new(AppConfig {
        title: "Mawida - hello_quad_ecs (step 8)".to_string(),
        ..Default::default()
    })
    // A module that nothing asks anything of changes nothing: the quad
    // moves exactly as before. Additive, demonstrated (step 9 milestone).
    // Spawn one PlaySound component in setup and you get sound with zero
    // new API: world.insert(e, PlaySound { bytes });
    .add_module(AudioModule::default())
    .spawn_with(setup)
    .add_system(movement)
    // .add_system(spin)
    .add_system(render_sprites) // movement first, so draws see this frame
    .run()
}
