use crate::marks::{Font, Rotation};
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};

#[derive(Clone, Debug)]
pub struct TTextBoxOptions {
  /// 文字起始x坐标
  pub x: i32,
  /// 文字起始y坐标
  pub y: i32,
  // 打印的文本内容
  pub content: String,
  // 文本框宽度
  pub width: i32,
  /// 文字字体(默认TSS16)
  pub font: Option<Font>,
  /// 文字旋转角度(默认不旋转)
  pub rotation: Option<Rotation>,
  /// 文字横向放大倍数
  pub x_multi: Option<i32>,
  /// 文字纵向放大倍数
  pub y_multi: Option<i32>,
  /// 行间距
  pub line_space: i32,
  /// false: 旋转每一个字 true：整体旋转(false)
  pub rotation_type: bool,
  /// 文字是否加粗(默认不加粗)
  pub bold: Option<bool>,
}

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

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

impl<T: Into<String>> From<(i32, i32, i32, i32, i32, i32, bool, T)> for TTextBox {
  fn from(
    (x, y, x_multi, y_multi, width, line_space, bold, content): (
      i32,
      i32,
      i32,
      i32,
      i32,
      i32,
      bool,
      T,
    ),
  ) -> Self {
    Self::new(TTextBoxOptions {
      x,
      y,
      content: content.into(),
      width,
      font: None,
      rotation: None,
      x_multi: Some(x_multi),
      y_multi: Some(y_multi),
      line_space,
      rotation_type: false,
      bold: Some(bold),
    })
  }
}

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

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

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    let font = self.options.font.clone().unwrap_or(Font::TSS16);
    let rotation = self.options.rotation.clone().unwrap_or(Rotation::Rotation0);
    let bold = self.options.bold.unwrap_or(false);
    let x_multi = self.options.x_multi.unwrap_or(1);
    let y_multi = self.options.y_multi.unwrap_or(1);
    let mut ptc = PsdkTextCommand::with_header_format_tspl(self.header());
    ptc
      .append(self.options.x)
      .append(self.options.y)
      .append_with_quote(font.command_value())
      .append(rotation.command_value())
      .append(x_multi)
      .append(y_multi)
      .append(self.options.width);
    if self.options.line_space > 0 {
      ptc.append("L".to_string() + &*self.options.line_space.to_string());
    }
    if bold {
      ptc.append("B1");
    }
    if self.options.rotation_type {
      ptc.append(format!("D{}", dart_rotation_name(&rotation)));
    }
    ptc.append_with_quote(&self.options.content);

    Ok(ptc.clause())
  }
}

fn dart_rotation_name(rotation: &Rotation) -> &'static str {
  match rotation {
    Rotation::Rotation0 => "TRotation.rotation_0",
    Rotation::Rotation90 => "TRotation.rotation_90",
    Rotation::Rotation180 => "TRotation.rotation_180",
    Rotation::Rotation270 => "TRotation.rotation_270",
  }
}

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