use psdk_extension::imagep;
use psdk_extension::imagep::ConvertBitmapOptions;
pub use psdk_extension::imagep::{ThresholdEdgeDitherDepth, ThresholdEdgeDitherMode};
use psdk_father::args::{ArgContext, PsdkArgBase, PsdkEasyArg, Raw};
use psdk_father::command::{CommandClause, Commander, PsdkCommand, PsdkTextCommand};
use psdk_father::errors::{PsdkFatherError, PsdkFatherResult};
use psdk_father::types::psdk_types::PsdkPrinterCommandEnumValue;
use std::sync::{Arc, Mutex};

use crate::marks::TImageMode;

#[derive(Clone, Debug)]
pub struct TImagePixelsOptions {
  // 图片起始x坐标
  pub x: i32,
  // 图片起始y坐标
  pub y: i32,
  // 图片数据
  pub pixels: Vec<u8>,
  // 图片宽度
  pub width: u32,
  // 图片高度
  pub height: u32,
  // 是否压缩
  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,
  // 图片绘制模式
  pub image_mode: TImageMode,
}

#[derive(Clone, Debug)]
pub struct TImagePixels {
  options: TImagePixelsOptions,
  ctx: Arc<Mutex<ArgContext>>,
}

impl TImagePixels {
  pub fn new(options: TImagePixelsOptions) -> Self {
    Self {
      options,
      ctx: Default::default(),
    }
  }
}

impl From<(i32, i32, Vec<u8>, u32, u32)> for TImagePixels {
  fn from((x, y, pixels, width, height): (i32, i32, Vec<u8>, u32, u32)) -> Self {
    Self::new(TImagePixelsOptions {
      x,
      y,
      pixels,
      width,
      height,
      compress: false,
      reverse: false,
      gray_threshold: None,
      smooth_weight: 0,
      edge_dither_mode: None,
      edge_dither_depth: Default::default(),
      image_mode: TImageMode::Overwrite,
    })
  }
}

impl PsdkEasyArg<String> for TImagePixels {
  fn context(&self) -> Arc<Mutex<ArgContext>> {
    self.ctx.clone()
  }
}

impl PsdkArgBase<String> for TImagePixels {
  fn header(&self) -> String {
    "BITMAP".to_string()
  }

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    let cbi = imagep::convert_to_bitmap(ConvertBitmapOptions {
      compress: self.options.compress,
      reverse: self.options.reverse,
      width: self.options.width,
      height: self.options.height,
      pixels: self.options.pixels.clone(),
      gray_threshold: self.options.gray_threshold,
      smooth_weight: self.options.smooth_weight,
      edge_dither_mode: self.options.edge_dither_mode,
      edge_dither_depth: self.options.edge_dither_depth,
    })
    .map_err(|e| PsdkFatherError::Custom(format!("Extension: {:?}", e)))?;

    let height = self.options.height;
    let byte_width = cbi.byte_width;
    let mut converted_bitmap_data = cbi.data;

    let mut commander = Commander::new();
    let mut ptc = PsdkTextCommand::with_header_format_tspl(self.header());
    ptc
      .append(self.options.x)
      .append(self.options.y)
      .append(byte_width)
      .append(height);
    if self.options.compress {
      ptc.append("3").append(converted_bitmap_data.len());
      commander
        .push_clause(ptc.clause(), false)
        .push_text_with_newline(",", false)
        .push_binary_with_newline(&converted_bitmap_data, false);
    } else {
      for byte in &mut converted_bitmap_data {
        *byte = !*byte;
      }
      ptc.append(self.options.image_mode.command_value());
      commander
        .push_clause(ptc.clause(), false)
        .push_text_with_newline(",", false)
        .push_binary_with_newline(&converted_bitmap_data, false);
    }
    let command = commander.command()?;
    Raw::new().push_binary(command.binary()).clause()
  }
}

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