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

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

#[derive(Clone, Debug)]
pub struct TQRCodeOptions {
  /// 二维码起始x坐标
  pub x: i32,
  /// 二维码起始y坐标
  pub y: i32,
  /// 二维码小黑点宽度(2-20)
  pub cell_width: i32,
  /// 二维码旋转角度(默认不旋转)
  pub rotation: Option<Rotation>,
  /// 纠错等级
  pub ecc_level: Option<ECCLevel>,
  /// 二维码版本
  pub version: Option<String>,
  /// 二维码内容
  pub content: String,
}

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

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

impl<C: Into<String>, V: Into<String>> From<(i32, i32, i32, C, V)> for TQRCode {
  fn from((x, y, cell_width, content, version): (i32, i32, i32, C, V)) -> Self {
    Self::new(TQRCodeOptions {
      x,
      y,
      cell_width,
      rotation: None,
      ecc_level: None,
      version: Some(version.into()),
      content: content.into(),
    })
  }
}

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

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

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    let mut ptc = PsdkTextCommand::with_header_format_tspl_and_charset(self.header(), "utf-8");
    let ecc = self.options.ecc_level.clone().unwrap_or(ECCLevel::LevelL);
    let rotation = self.options.rotation.clone().unwrap_or(Rotation::Rotation0);
    ptc
      .append(self.options.x)
      .append(self.options.y)
      .append(ecc.command_value())
      .append(self.options.cell_width)
      .append("A")
      .append(rotation.command_value())
      .append("M2")
      .append("S7");
    ptc.append(format!(
      "V{}",
      self.options.version.as_deref().unwrap_or_default()
    ));
    ptc.append_with_quote(
      self
        .options
        .content
        .replace(['\r', '\n'], " ")
        .replace('"', "\\[\"]"),
    );
    Ok(ptc.clause())
  }
}

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