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

use crate::marks::{CodeType, Rotation, ShowType};

#[derive(Clone, Debug)]
pub struct TBarCodeOptions {
  /// 起始x坐标
  pub x: i32,
  /// 起始y坐标
  pub y: i32,
  /// 条码高度
  pub height: i32,
  /// 条码类型
  pub code_type: Option<CodeType>,
  /// 文字显示方式
  pub show_type: Option<ShowType>,
  /// 条码旋转角度
  pub rotation: Option<Rotation>,
  /// 窄条码宽度
  pub cell_width: i32,
  /// 宽条码和窄条码的比率
  pub ratio: Option<i32>,
  /// 条码内容
  pub content: String,
}

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

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

impl<T: Into<String>> From<(i32, i32, i32, i32, T)> for TBarCode {
  fn from((x, y, height, cell_width, content): (i32, i32, i32, i32, T)) -> Self {
    Self::new(TBarCodeOptions {
      x,
      y,
      height,
      code_type: None,
      show_type: None,
      rotation: None,
      cell_width,
      ratio: None,
      content: content.into(),
    })
  }
}

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

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

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    let mut ptc = PsdkTextCommand::with_header_format_tspl(self.header());
    let code_type = self.options.code_type.clone().unwrap_or(CodeType::Code128);
    let show_type = self.options.show_type.clone().unwrap_or(ShowType::ShowNone);
    let rotation = self.options.rotation.clone().unwrap_or(Rotation::Rotation0);
    let ratio = self.options.ratio.unwrap_or(1);
    ptc
      .append(self.options.x)
      .append(self.options.y)
      .append_with_quote(code_type.command_value())
      .append(self.options.height)
      .append(show_type.command_value())
      .append(rotation.command_value())
      .append(self.options.cell_width)
      .append(self.options.cell_width * ratio)
      .append_with_quote(&self.options.content);
    Ok(ptc.clause())
  }
}

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