///|
pub enum QuantityMathError {
  InvalidNumber
  IncompatibleUnits
  DivideByZero
} derive(Debug, Eq)

///|
pub fn quantity_math_errors() -> Array[QuantityMathError] {
  [InvalidNumber, IncompatibleUnits, DivideByZero]
}

///|
fn quantity_number(value : String) -> Int? {
  decimal_scaled(value)
}

///|
pub fn add_quantities(
  left : Quantity,
  right : Quantity,
) -> Result[Quantity, QuantityMathError] {
  if left.unit != right.unit {
    return Err(IncompatibleUnits)
  }
  let a = quantity_number(left.value)
  let b = quantity_number(right.value)
  if a is None || b is None {
    return Err(InvalidNumber)
  }
  Ok(quantity(scaled_string(a.unwrap() + b.unwrap()), left.unit))
}

///|
pub fn subtract_quantities(
  left : Quantity,
  right : Quantity,
) -> Result[Quantity, QuantityMathError] {
  if left.unit != right.unit {
    return Err(IncompatibleUnits)
  }
  let a = quantity_number(left.value)
  let b = quantity_number(right.value)
  if a is None || b is None {
    return Err(InvalidNumber)
  }
  Ok(quantity(scaled_string(a.unwrap() - b.unwrap()), left.unit))
}

///|
pub fn scale_quantity(
  value : Quantity,
  factor : String,
) -> Result[Quantity, QuantityMathError] {
  let number = quantity_number(value.value)
  let multiplier = quantity_number(factor)
  if number is None || multiplier is None {
    return Err(InvalidNumber)
  }
  Ok(
    quantity(
      scaled_string(number.unwrap() * multiplier.unwrap() / 1000),
      value.unit,
    ),
  )
}

///|
pub fn divide_quantity(
  value : Quantity,
  divisor : String,
) -> Result[Quantity, QuantityMathError] {
  let number = quantity_number(value.value)
  let denominator = quantity_number(divisor)
  if number is None || denominator is None {
    return Err(InvalidNumber)
  }
  if denominator.unwrap() == 0 {
    return Err(DivideByZero)
  }
  Ok(
    quantity(
      scaled_string(number.unwrap() * 1000 / denominator.unwrap()),
      value.unit,
    ),
  )
}

///|
pub fn quantity_difference(
  left : Quantity,
  right : Quantity,
) -> Result[Quantity, QuantityMathError] {
  match subtract_quantities(left, right) {
    Ok(value) =>
      Ok(
        quantity(
          scaled_string(decimal_scaled(value.value).unwrap().abs()),
          value.unit,
        ),
      )
    Err(error) => Err(error)
  }
}