use crate::ecs::behavior::components::{
    BEHAVIOR_BOB, BEHAVIOR_ORBIT, BEHAVIOR_ROTATE, BEHAVIOR_SCALE_PULSE, BEHAVIOR_SINE_WAVE,
    DEFAULT_BOB_HEIGHT, DEFAULT_BOB_SPEED, DEFAULT_ORBIT_RADIUS, DEFAULT_ORBIT_SPEED,
    DEFAULT_ROTATE_SPEED, DEFAULT_SCALE_PULSE_MAX, DEFAULT_SCALE_PULSE_MIN,
    DEFAULT_SCALE_PULSE_SPEED, DEFAULT_SINE_WAVE_AMPLITUDE, DEFAULT_SINE_WAVE_FREQUENCY,
    ENGINE_BEHAVIORS_MASK,
};
use crate::ecs::transform::commands::mark_local_transform_dirty;
use crate::ecs::world::{BEHAVIOR_FLAGS, World};
use nalgebra_glm::Vec3;

pub fn run_behavior_system(world: &mut World) {
    let elapsed_time = world.resources.window.timing.uptime_milliseconds as f32 / 1000.0;
    let entities: Vec<_> = world.query_entities(BEHAVIOR_FLAGS).collect();

    for entity in entities {
        let flags = match world.get_behavior_flags(entity) {
            Some(f) => f.0,
            None => continue,
        };

        let engine_flags = flags & ENGINE_BEHAVIORS_MASK;
        if engine_flags == 0 {
            continue;
        }

        let parent_global_translation = world
            .get_parent(entity)
            .and_then(|p| p.0)
            .and_then(|parent| world.get_global_transform(parent))
            .map(|t| t.translation())
            .unwrap_or_else(Vec3::zeros);

        let transform = match world.get_local_transform_mut(entity) {
            Some(t) => t,
            None => continue,
        };

        if flags & BEHAVIOR_BOB != 0 {
            let offset = (elapsed_time * DEFAULT_BOB_SPEED).sin() * DEFAULT_BOB_HEIGHT;
            transform.translation.y = parent_global_translation.y + offset;
        }

        if flags & BEHAVIOR_SINE_WAVE != 0 {
            let offset =
                (elapsed_time * DEFAULT_SINE_WAVE_FREQUENCY).sin() * DEFAULT_SINE_WAVE_AMPLITUDE;
            transform.translation.y = parent_global_translation.y + offset;
        }

        if flags & BEHAVIOR_ORBIT != 0 {
            let angle = elapsed_time * DEFAULT_ORBIT_SPEED;
            transform.translation.x =
                parent_global_translation.x + angle.cos() * DEFAULT_ORBIT_RADIUS;
            transform.translation.z =
                parent_global_translation.z + angle.sin() * DEFAULT_ORBIT_RADIUS;
        }

        if flags & BEHAVIOR_ROTATE != 0 {
            let angle = elapsed_time * DEFAULT_ROTATE_SPEED;
            transform.rotation = nalgebra_glm::quat_angle_axis(angle, &Vec3::y());
        }

        if flags & BEHAVIOR_SCALE_PULSE != 0 {
            let t = (elapsed_time * DEFAULT_SCALE_PULSE_SPEED).sin() * 0.5 + 0.5;
            let uniform_scale =
                DEFAULT_SCALE_PULSE_MIN + t * (DEFAULT_SCALE_PULSE_MAX - DEFAULT_SCALE_PULSE_MIN);
            transform.scale = Vec3::new(uniform_scale, uniform_scale, uniform_scale);
        }

        mark_local_transform_dirty(world, entity);
    }
}
