Documentation
use std::sync::{Arc, Mutex};

use psdk_father::types::psdk_types::PsdkPrinterCommandEnumValue;
use psdk_father::{
  args::{ArgContext, PsdkArgBase, PsdkEasyArg},
  command::{CommandClause, PsdkTextCommand},
  errors::PsdkFatherResult,
};

use crate::marks::{CodeRotation, CorrectLevel};

#[derive(Clone, Debug)]
pub struct CQRCodeOptions {
  /// 二维码起始x坐标
  pub x: i32,
  /// 二维码码起始x坐标
  pub y: i32,
  /// 二维码内容
  pub content: String,
  /// 二维码旋转角度(默认不旋转)
  pub code_rotation: Option<CodeRotation>,
  /// 二维码码起始x坐标
  pub width: i32,
  /// 二维码纠错等级(默认L)
  pub level: Option<CorrectLevel>,
}

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

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

impl<T: Into<String>> From<(i32, i32, T, i32)> for CQRCode {
  fn from((x, y, content, width): (i32, i32, T, i32)) -> Self {
    Self::new(CQRCodeOptions {
      x,
      y,
      content: content.into(),
      code_rotation: None,
      width,
      level: None,
    })
  }
}

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

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

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    let mut ptc = PsdkTextCommand::with_header_format_cpcl_and_charset(self.header(), "utf-8");
    let code_rotation = self
      .options
      .code_rotation
      .clone()
      .unwrap_or(CodeRotation::Rotation0);
    let level = self.options.level.clone().unwrap_or(CorrectLevel::L);
    let level_string = format!(
      "{}\n{}",
      level.get_level_num(),
      code_rotation.command_value()
    );
    let content = self.options.content.replace(['\r', '\n'], " ");
    let level_num_string = format!(
      "{}\n{}A,{}\n{}",
      self.options.width,
      level.get_level(),
      content,
      "ENDQR"
    );
    ptc
      .append(level_string)
      .append("QR")
      .append(self.options.x)
      .append(self.options.y)
      .append("M")
      .append("2")
      .append("U")
      .append(level_num_string);
    Ok(ptc.clause())
  }
}

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