use std::sync::Once;

use magick_rust::{bindings::FilterType_LanczosFilter, magick_wand_genesis, MagickWand};
use napi::{bindgen_prelude::Buffer, Error, Result, Status, Task};

static START: Once = Once::new();

pub struct LiquidRescaleTask {
    input_image: Buffer,
    output_width: usize,
    output_height: usize,
}

impl LiquidRescaleTask {
    #[inline]
    pub fn new(
        input_image: Buffer,
        output_width: usize,
        output_height: usize,
    ) -> LiquidRescaleTask {
        LiquidRescaleTask {
            input_image,
            output_width,
            output_height,
        }
    }

    #[inline]
    pub fn liquid_rescale(input_image: &[u8], width: usize, height: usize) -> Result<Buffer> {
        START.call_once(|| {
            magick_wand_genesis();
        });

        let wand = MagickWand::new();
        wand.read_image_blob(input_image)
            .map_err(|err| Error::new(Status::InvalidArg, format!("{err}")))?;
        let input_width = wand.get_image_width();
        let input_height = wand.get_image_height();
        wand.liquid_rescale_image(width, height, 1.0, 0.0)
            .map_err(|err| Error::new(Status::GenericFailure, format!("{err}")))?;
        wand.resize_image(input_width, input_height, FilterType_LanczosFilter);
        let output_image = wand
            .write_image_blob("JPEG")
            .map_err(|err| Error::new(Status::GenericFailure, format!("{err}")))?;

        Ok(output_image.into())
    }
}

impl Task for LiquidRescaleTask {
    type Output = Buffer;
    type JsValue = Buffer;

    fn compute(&mut self) -> Result<Self::Output> {
        Self::liquid_rescale(&self.input_image, self.output_width, self.output_height)
    }

    fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
        Ok(output)
    }
}
