//! Force field management for GPU physics.

use dreamwell_engine::physics::{ForceFieldDescriptor, ForceFieldKind};

#[repr(C)]
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct GpuForceField {
    pub position: [f32; 3],
    pub kind: u32,
    pub direction: [f32; 3],
    pub strength: f32,
    pub radius: f32,
    pub falloff: f32,
    pub noise_frequency: f32,
    pub noise_amplitude: f32,
}

pub struct ForceFieldPass {
    fields: Vec<GpuForceField>,
}

impl ForceFieldPass {
    pub fn new(_device: &wgpu::Device) -> Self {
        Self { fields: Vec::new() }
    }

    pub fn add_field(&mut self, desc: &ForceFieldDescriptor) -> usize {
        let kind = match desc.kind {
            ForceFieldKind::Gravity => 0,
            ForceFieldKind::Drag => 1,
            ForceFieldKind::Damping => 2,
            ForceFieldKind::Directional => 3,
            ForceFieldKind::Radial => 4,
            ForceFieldKind::Attractor => 5,
            ForceFieldKind::Repulsor => 6,
            ForceFieldKind::Vortex => 7,
            ForceFieldKind::Orbital => 8,
            ForceFieldKind::Turbulence => 9,
            ForceFieldKind::CurlNoise => 10,
            ForceFieldKind::Wind => 11,
            ForceFieldKind::Buoyancy => 12,
            ForceFieldKind::CustomVectorField => 13,
        };

        let idx = self.fields.len();
        self.fields.push(GpuForceField {
            position: desc.position,
            kind,
            direction: desc.direction,
            strength: desc.strength,
            radius: desc.radius,
            falloff: desc.falloff,
            noise_frequency: desc.noise_frequency,
            noise_amplitude: desc.noise_amplitude,
        });
        idx
    }

    pub fn upload(&self, queue: &wgpu::Queue, buffer: &wgpu::Buffer) {
        if !self.fields.is_empty() {
            queue.write_buffer(buffer, 0, bytemuck::cast_slice(&self.fields));
        }
    }

    pub fn clear(&mut self) {
        self.fields.clear();
    }

    pub fn len(&self) -> usize {
        self.fields.len()
    }

    pub fn is_empty(&self) -> bool {
        self.fields.is_empty()
    }
}
