use fast_image_resize::{images::Image, Resizer, ResizeOptions, ResizeAlg, FilterType};

use crate::error::{PixstripError, Result};
use crate::types::Dimensions;

use super::{ResizeConfig, ResizeAlgorithm};

pub fn resize_image(
    src: &image::DynamicImage,
    config: &ResizeConfig,
) -> Result<image::DynamicImage> {
    resize_image_with_algorithm(src, config, ResizeAlgorithm::default())
}

pub fn resize_image_with_algorithm(
    src: &image::DynamicImage,
    config: &ResizeConfig,
    algorithm: ResizeAlgorithm,
) -> Result<image::DynamicImage> {
    let original = Dimensions {
        width: src.width(),
        height: src.height(),
    };
    let target = config.target_for(original);

    if target.width == original.width && target.height == original.height {
        return Ok(src.clone());
    }

    let src_rgba = src.to_rgba8();
    let (src_w, src_h) = (src_rgba.width(), src_rgba.height());

    let src_image = Image::from_vec_u8(
        src_w,
        src_h,
        src_rgba.into_raw(),
        fast_image_resize::PixelType::U8x4,
    )
    .map_err(|e| PixstripError::Processing {
        operation: "resize".into(),
        reason: format!("Failed to create source image: {}", e),
    })?;

    let mut dst_image = Image::new(
        target.width,
        target.height,
        fast_image_resize::PixelType::U8x4,
    );

    let mut resizer = Resizer::new();
    let alg = match algorithm {
        ResizeAlgorithm::Lanczos3 => ResizeAlg::Convolution(FilterType::Lanczos3),
        ResizeAlgorithm::CatmullRom => ResizeAlg::Convolution(FilterType::CatmullRom),
        ResizeAlgorithm::Bilinear => ResizeAlg::Convolution(FilterType::Bilinear),
        ResizeAlgorithm::Nearest => ResizeAlg::Nearest,
    };
    let options = ResizeOptions::new().resize_alg(alg);

    resizer
        .resize(&src_image, &mut dst_image, &options)
        .map_err(|e| PixstripError::Processing {
            operation: "resize".into(),
            reason: format!("Resize failed: {}", e),
        })?;

    let result_buf: image::RgbaImage =
        image::ImageBuffer::from_raw(target.width, target.height, dst_image.into_vec())
            .ok_or_else(|| PixstripError::Processing {
                operation: "resize".into(),
                reason: "Failed to create output image buffer".into(),
            })?;

    Ok(image::DynamicImage::ImageRgba8(result_buf))
}
