//! A test arena authored with reflectable level components.

use std::f32::consts::PI;

use bevy::prelude::*;
use shared::{ColorDesc, LevelObject, MaterialDesc, PhysicsBody, Primitive};

/// Builds the whole static level when no ground exists yet.
#[unsafe(no_mangle)]
pub fn spawn_level(mut commands: Commands, existing: Query<(), With<LevelObject>>) {
    if !existing.is_empty() {
        return;
    }

    let floor_mat = MaterialDesc::new(ColorDesc::srgb(0.42, 0.45, 0.48), 0.0, 0.92);
    let ramp_mat = MaterialDesc::new(ColorDesc::srgb(0.30, 0.45, 0.70), 0.1, 0.55);
    let stair_mat = MaterialDesc::new(ColorDesc::srgb(0.55, 0.52, 0.48), 0.0, 0.8);
    let pillar_mat = MaterialDesc::new(ColorDesc::srgb(0.85, 0.85, 0.88), 0.0, 0.3);
    let crate_mat = MaterialDesc::new(ColorDesc::srgb(0.72, 0.45, 0.20), 0.0, 0.85);

    let ground_size = Vec3::new(200.0, 1.0, 200.0);
    commands.spawn((
        LevelObject,
        Name::new("Ground"),
        Primitive::cuboid(ground_size),
        floor_mat,
        PhysicsBody::static_cuboid(ground_size),
        Transform::from_xyz(0.0, -0.5, 0.0),
    ));

    for (x, z) in [(-8.0, -6.0), (8.0, -6.0), (-8.0, 6.0), (8.0, 6.0)] {
        spawn_box(
            &mut commands,
            pillar_mat.clone(),
            Vec3::new(1.2, 7.0, 1.2),
            Vec3::new(x, 3.5, z),
            Quat::IDENTITY,
            "Pillar",
        );
    }

    for (x, z, s) in [
        (-3.0, -3.0, 1.0),
        (-1.6, -3.2, 1.0),
        (-2.3, -3.1, 1.0),
        (4.0, 2.0, 1.5),
        (5.4, 2.4, 1.0),
    ] {
        spawn_box(
            &mut commands,
            crate_mat.clone(),
            Vec3::splat(s),
            Vec3::new(x, s * 0.5, z),
            Quat::from_rotation_y(x * 0.7),
            "Crate",
        );
    }

    let ramp_size = Vec3::new(5.0, 0.4, 9.0);
    spawn_box(
        &mut commands,
        ramp_mat,
        ramp_size,
        Vec3::new(-14.0, 1.6, 0.0),
        Quat::from_rotation_x(-PI / 9.0),
        "Ramp",
    );

    let steps = 10;
    let rise = 0.18;
    let depth = 0.5;
    let width = 5.0;
    let start_z = 14.0;
    for i in 0..steps {
        let height = rise * (i + 1) as f32;
        spawn_box(
            &mut commands,
            stair_mat.clone(),
            Vec3::new(width, height, depth),
            Vec3::new(12.0, height * 0.5, start_z - i as f32 * depth),
            Quat::IDENTITY,
            "Stair",
        );
    }

    for (i, roughness) in [0.05, 0.3, 0.6, 0.95].into_iter().enumerate() {
        let metal = MaterialDesc::new(ColorDesc::srgb(0.9, 0.9, 0.92), 1.0, roughness);
        commands.spawn((
            LevelObject,
            Name::new("ShowcaseSphere"),
            Primitive::sphere(0.6),
            metal,
            PhysicsBody::static_sphere(0.6),
            Transform::from_xyz(-8.0 + i as f32 * 2.2, 0.6, 4.0),
        ));
    }
}

fn spawn_box(
    commands: &mut Commands,
    material: MaterialDesc,
    size: Vec3,
    translation: Vec3,
    rotation: Quat,
    name: &'static str,
) {
    commands.spawn((
        LevelObject,
        Name::new(name),
        Primitive::cuboid(size),
        material,
        PhysicsBody::static_cuboid(size),
        Transform::from_translation(translation).with_rotation(rotation),
    ));
}
