use crate::agc::Agc;
use crate::dc_blocker::DcBlocker;
use crate::fir::Fir;
use crate::fm_demod::{FmDemod, Sample};
use crate::iq_reader::IqSample;
use crate::line_assembler::LineAssembler;
use crate::low_pass::LowPass;
use crate::sync::{SyncEvent, SyncSeparator};

pub trait DspPipelineExt<E>: Iterator<Item = Result<IqSample, E>> + Sized {
    fn agc(self, sample_rate: f32, target_power: f32, min_gain: f32, max_gain: f32) -> Agc<Self> {
        Agc::new(self, sample_rate, target_power, min_gain, max_gain)
    }

    fn fir<const N: usize>(self, taps: [f32; N], decimation_factor: usize) -> Fir<Self, N> {
        Fir::new(self, taps, decimation_factor)
    }

    fn demodulate(self) -> FmDemod<Self> {
        FmDemod::new(self)
    }
}

impl<I, E> DspPipelineExt<E> for I where I: Iterator<Item = Result<IqSample, E>> {}

pub trait AfterDemodPiplineExt<E>: Iterator<Item = Result<Sample, E>> + Sized {
    fn dc_block(self, alpha: f32) -> DcBlocker<Self> {
        DcBlocker::new(self, alpha)
    }

    fn lowpass(self, alpha: f32) -> LowPass<Self> {
        LowPass::new(self, alpha)
    }

    fn sync_separate(self, sample_rate: f32, sync_threshold: f32) -> SyncSeparator<Self> {
        SyncSeparator::new(self, sample_rate, sync_threshold)
    }
}

impl<I, E> AfterDemodPiplineExt<E> for I where I: Iterator<Item = Result<Sample, E>> {}

pub trait SyncPipelineExt<E>: Iterator<Item = Result<SyncEvent, E>> + Sized {
    fn assemble_frames(self) -> LineAssembler<Self> {
        LineAssembler::new(self)
    }
}
impl<I, E> SyncPipelineExt<E> for I where I: Iterator<Item = Result<SyncEvent, E>> {}
