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

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

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

#[derive(Clone, Debug)]
pub struct CBarOptions {
  /// 条码起始x坐标
  pub x: i32,
  /// 条码起始y坐标
  pub y: i32,
  /// 条码内容
  pub content: String,
  /// 条码线宽度
  pub line_width: i32,
  /// 条码高度
  pub height: i32,
  /// 条码类型(默认CODE128)
  pub code_type: Option<CodeType>,
  /// 条码旋转角度(默认不旋转)
  pub code_rotation: Option<CodeRotation>,
}

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

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

impl<T: Into<String>> From<(i32, i32, T, i32, i32)> for CBar {
  fn from((x, y, content, line_width, height): (i32, i32, T, i32, i32)) -> Self {
    Self::new(CBarOptions {
      x,
      y,
      content: content.into(),
      line_width,
      height,
      code_type: None,
      code_rotation: None,
    })
  }
}

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

impl PsdkArgBase<String> for CBar {
  fn header(&self) -> String {
    match &self.options.code_rotation {
      Some(v) => v.command_value(),
      None => CodeRotation::Rotation0.command_value(),
    }
  }

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    let mut ptc = PsdkTextCommand::with_header_format_cpcl(self.header());
    let code_type = self.options.code_type.clone().unwrap_or(CodeType::Code128);
    ptc
      .append(code_type.command_value())
      .append(self.options.line_width)
      .append(2)
      .append(self.options.height)
      .append(self.options.x)
      .append(self.options.y)
      .append(&self.options.content);
    Ok(ptc.clause())
  }
}

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