use num_complex::Complex;
use num_traits::{Float, FromPrimitive, One, Zero};

use crate::spectrum::{SpectrumError, factory::DefaultFFTFactory};

pub trait FFTApply<T> where
    T: Float + FromPrimitive + Zero + Clone + One + 'static,
{
    fn apply(&self, data: &Vec<T>) -> Result<Vec<Complex<T>>, SpectrumError>;
}

pub trait IFFTApply<T> where
    T: Float + FromPrimitive + Zero + Clone + One + 'static,
{
    fn apply(&self, data: &mut Vec<Complex<T>>) -> Result<Vec<T>, SpectrumError>;
}

pub trait FFTFactory<T>
where
    T: Float + FromPrimitive + Clone + Zero + One + 'static,
{
    fn create_fft(&self) -> Box<dyn FFTApply<T>>;
    fn create_ifft(&self) -> Box<dyn IFFTApply<T>>;
}

pub fn spectrum_factory<T>() -> Box<dyn FFTFactory<T>>
where
    T: Float + FromPrimitive + Clone + Zero + One + 'static,
{
    Box::new(DefaultFFTFactory)
}

pub fn fft<T: Float + FromPrimitive + Clone + Zero + One + 'static>(
    data: &Vec<T>,
) -> Result<Vec<Complex<T>>, SpectrumError> {
    let fft = spectrum_factory::<T>().create_fft();
    fft.apply(data)
}

pub fn ifft<T: Float + FromPrimitive + Clone + Zero + One + 'static>(
    data: &mut Vec<Complex<T>>,
) -> Result<Vec<T>, SpectrumError> {
    let ifft = spectrum_factory::<T>().create_ifft();
    ifft.apply(data)
}
