Documentation
use psdk_father::args::{ArgContext, PsdkArgBase, PsdkEasyArg};
use psdk_father::command::CommandClause;
use psdk_father::errors::{PsdkFatherError, PsdkFatherResult};
use std::sync::{Arc, Mutex};
use tiny_skia::Pixmap;

use super::CImagePixels;
use psdk_extension::imagep::{ThresholdEdgeDitherDepth, ThresholdEdgeDitherMode};

#[derive(Clone, Debug)]
pub struct CImageBytesOptions {
  /// 图片起始x坐标
  pub x: i32,
  /// 图片起始y坐标
  pub y: i32,
  /// 图片数据
  pub bytes: Vec<u8>,
  /// 是否压缩
  pub compress: bool,
  /// 是否反色
  pub reverse: bool,
  /// 二值化0-255(默认190)
  pub gray_threshold: Option<i32>,
  /// 平滑权重(默认0)
  pub smooth_weight: i32,
  /// 边缘抖动模式
  pub edge_dither_mode: Option<ThresholdEdgeDitherMode>,
  /// 边缘抖动深度
  pub edge_dither_depth: ThresholdEdgeDitherDepth,
}

#[derive(Clone, Debug)]
pub struct CImageBytes {
  image_pixels: CImagePixels,
}

impl CImageBytes {
  pub fn new(options: CImageBytesOptions) -> PsdkFatherResult<Self> {
    let pixmap =
      Pixmap::decode_png(&options.bytes).map_err(|e| PsdkFatherError::Image(format!("{:?}", e)))?;
    let width = pixmap.width();
    let height = pixmap.height();
    Ok(Self {
      image_pixels: CImagePixels::new(super::CImagePixelsOptions {
        x: options.x,
        y: options.y,
        pixels: pixmap.take(),
        width,
        height,
        compress: options.compress,
        reverse: options.reverse,
        gray_threshold: options.gray_threshold,
        smooth_weight: options.smooth_weight,
        edge_dither_mode: options.edge_dither_mode,
        edge_dither_depth: options.edge_dither_depth,
      }),
    })
  }
}

impl TryFrom<(i32, i32, Vec<u8>)> for CImageBytes {
  type Error = PsdkFatherError;

  fn try_from((x, y, bytes): (i32, i32, Vec<u8>)) -> Result<Self, Self::Error> {
    Self::new(CImageBytesOptions {
      x,
      y,
      bytes,
      compress: false,
      reverse: false,
      gray_threshold: None,
      smooth_weight: 0,
      edge_dither_mode: None,
      edge_dither_depth: Default::default(),
    })
  }
}

impl PsdkEasyArg<String> for CImageBytes {
  fn context(&self) -> Arc<Mutex<ArgContext>> {
    self.image_pixels.context()
  }
}

impl PsdkArgBase<String> for CImageBytes {
  fn header(&self) -> String {
    self.image_pixels.header()
  }

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    self.image_pixels.clause()
  }
}

psdk_father::impl_psdk_arg_to_easy_arg!(String, CImageBytes, true);