use super::AlphaMulDiv;
use crate::cpu_extensions::CpuExtensions;
use crate::pixels::U8x2;
use crate::{ImageError, ImageView, ImageViewMut};

#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
#[cfg(target_arch = "aarch64")]
mod neon;
#[cfg(target_arch = "x86_64")]
mod sse4;
#[cfg(target_arch = "wasm32")]
mod wasm32;

type P = U8x2;

impl AlphaMulDiv for P {
    fn multiply_alpha(
        src_view: &impl ImageView<Pixel = Self>,
        dst_view: &mut impl ImageViewMut<Pixel = Self>,
        cpu_extensions: CpuExtensions,
    ) -> Result<(), ImageError> {
        process_two_images! {
            multiple(src_view, dst_view, cpu_extensions);
        }
        Ok(())
    }

    fn multiply_alpha_inplace(
        image_view: &mut impl ImageViewMut<Pixel = Self>,
        cpu_extensions: CpuExtensions,
    ) -> Result<(), ImageError> {
        process_one_images! {
            multiply_inplace(image_view, cpu_extensions);
        }
        Ok(())
    }

    fn divide_alpha(
        src_view: &impl ImageView<Pixel = Self>,
        dst_view: &mut impl ImageViewMut<Pixel = Self>,
        cpu_extensions: CpuExtensions,
    ) -> Result<(), ImageError> {
        process_two_images! {
            divide(src_view, dst_view, cpu_extensions);
        }
        Ok(())
    }

    fn divide_alpha_inplace(
        image_view: &mut impl ImageViewMut<Pixel = Self>,
        cpu_extensions: CpuExtensions,
    ) -> Result<(), ImageError> {
        process_one_images! {
            divide_inplace(image_view, cpu_extensions);
        }
        Ok(())
    }
}

fn multiple(
    src_view: &impl ImageView<Pixel = P>,
    dst_view: &mut impl ImageViewMut<Pixel = P>,
    cpu_extensions: CpuExtensions,
) {
    match cpu_extensions {
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Avx2 => unsafe { avx2::multiply_alpha(src_view, dst_view) },
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Sse4_1 => unsafe { sse4::multiply_alpha(src_view, dst_view) },
        #[cfg(target_arch = "aarch64")]
        CpuExtensions::Neon => unsafe { neon::multiply_alpha(src_view, dst_view) },
        #[cfg(target_arch = "wasm32")]
        CpuExtensions::Simd128 => unsafe { wasm32::multiply_alpha(src_view, dst_view) },
        _ => native::multiply_alpha(src_view, dst_view),
    }
}

fn multiply_inplace(image_view: &mut impl ImageViewMut<Pixel = P>, cpu_extensions: CpuExtensions) {
    match cpu_extensions {
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Avx2 => unsafe { avx2::multiply_alpha_inplace(image_view) },
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Sse4_1 => unsafe { sse4::multiply_alpha_inplace(image_view) },
        #[cfg(target_arch = "aarch64")]
        CpuExtensions::Neon => unsafe { neon::multiply_alpha_inplace(image_view) },
        #[cfg(target_arch = "wasm32")]
        CpuExtensions::Simd128 => unsafe { wasm32::multiply_alpha_inplace(image_view) },
        _ => native::multiply_alpha_inplace(image_view),
    }
}

fn divide(
    src_view: &impl ImageView<Pixel = P>,
    dst_view: &mut impl ImageViewMut<Pixel = P>,
    cpu_extensions: CpuExtensions,
) {
    match cpu_extensions {
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Avx2 => unsafe { avx2::divide_alpha(src_view, dst_view) },
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Sse4_1 => unsafe { sse4::divide_alpha(src_view, dst_view) },
        #[cfg(target_arch = "aarch64")]
        CpuExtensions::Neon => unsafe { neon::divide_alpha(src_view, dst_view) },
        #[cfg(target_arch = "wasm32")]
        CpuExtensions::Simd128 => unsafe { wasm32::divide_alpha(src_view, dst_view) },
        _ => native::divide_alpha(src_view, dst_view),
    }
}

fn divide_inplace(image_view: &mut impl ImageViewMut<Pixel = P>, cpu_extensions: CpuExtensions) {
    match cpu_extensions {
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Avx2 => unsafe { avx2::divide_alpha_inplace(image_view) },
        #[cfg(target_arch = "x86_64")]
        CpuExtensions::Sse4_1 => unsafe { sse4::divide_alpha_inplace(image_view) },
        #[cfg(target_arch = "aarch64")]
        CpuExtensions::Neon => unsafe { neon::divide_alpha_inplace(image_view) },
        #[cfg(target_arch = "wasm32")]
        CpuExtensions::Simd128 => unsafe { wasm32::divide_alpha_inplace(image_view) },
        _ => native::divide_alpha_inplace(image_view),
    }
}
