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

#[derive(Clone)]
pub struct StereoFlanger {
    sample_rate: f32,
    depth: f32,
    lfo_rate: f32,
    delay_range: f32,
    feedback: f32,
    delay_line: Vec<(f32, f32)>,
    index: usize,
    lfo_phase: f32,
}

impl StereoFlanger {
    pub fn new(
        sample_rate: f32,
        depth: f32,
        lfo_rate: f32,
        delay_range: f32,
        feedback: f32,
        max_delay_samples: usize,
    ) -> Self {
        Self {
            sample_rate,
            depth,
            lfo_rate,
            delay_range,
            feedback,
            delay_line: vec![(0.0, 0.0); max_delay_samples],
            index: 0,
            lfo_phase: 0.0,
        }
    }

    pub fn update(&mut self, sample_rate: f32, depth: f32, lfo_rate: f32, feedback: f32) {
        self.sample_rate = sample_rate;
        self.depth = depth;
        self.lfo_rate = lfo_rate;
        self.feedback = feedback;
    }

    pub fn process(&mut self, left_in: f32, right_in: f32, amount: f32) -> (f32, f32) {
        // Update LFO phase
        self.lfo_phase += 2.0 * PI * self.lfo_rate / self.sample_rate;
        if self.lfo_phase > 2.0 * PI {
            self.lfo_phase -= 2.0 * PI;
        }

        // Calculate modulation depth
        let modulator = self.depth * (0.5 * self.lfo_phase.sin() + 0.5);

        // Calculate delay in samples
        let delay_samples = (self.delay_range * modulator) as usize;

        // Retrieve delayed samples from the delay line
        let delayed_left = self.delay_line[(self.index + delay_samples) % self.delay_line.len()].0;
        let delayed_right = self.delay_line[(self.index + delay_samples) % self.delay_line.len()].1;

        // Apply flanger effect
        let mut left_out = left_in + self.feedback * delayed_left;
        let mut right_out = right_in + self.feedback * delayed_right;

        // Update delay line
        self.delay_line[self.index] = (left_in, right_in);

        // Increment index and wrap around
        self.index = (self.index + 1) % self.delay_line.len();

        // Mix dry and wet signals based on the amount parameter
        left_out = left_in * (1.0 - amount) + left_out * amount;
        right_out = right_in * (1.0 - amount) + right_out * amount;

        (left_out, right_out)
    }
}
