///|
pub enum ValidationIssue {
  EmptyId(String)
  NegativeAmount(String)
  EmptyCustomer(String)
  EmptyAccount(String)
  EmptyCurrency(String)
  EmptyRegion(String)
  InvalidTimestamp(String)
} derive(Eq, Debug)

///|
pub fn validate_transaction(tx : Transaction) -> Array[ValidationIssue] {
  let issues : Array[ValidationIssue] = []
  if tx.id == "" {
    issues.push(EmptyId(tx.id))
  }
  if tx.amount < 0 {
    issues.push(NegativeAmount(tx.id))
  }
  if tx.customer_id == "" {
    issues.push(EmptyCustomer(tx.id))
  }
  if tx.account_id == "" {
    issues.push(EmptyAccount(tx.id))
  }
  if tx.currency == "" {
    issues.push(EmptyCurrency(tx.id))
  }
  if tx.region == "" {
    issues.push(EmptyRegion(tx.id))
  }
  if tx.occurred_at < 0 {
    issues.push(InvalidTimestamp(tx.id))
  }
  issues
}

///|
pub fn validate_batch(
  transactions : Array[Transaction],
) -> Array[ValidationIssue] {
  let issues : Array[ValidationIssue] = []
  for tx in transactions {
    issues.append(validate_transaction(tx))
  }
  issues
}

///|
pub fn is_valid_transaction(tx : Transaction) -> Bool {
  validate_transaction(tx).length() == 0
}

///|
pub fn normalize_region(region : String) -> String {
  region.trim().to_owned().to_upper()
}

///|
pub fn normalize_currency(currency : String) -> String {
  currency.trim().to_owned().to_upper()
}

///|
pub fn normalize_transaction(tx : Transaction) -> Transaction {
  {
    ..tx,
    region: normalize_region(tx.region),
    currency: normalize_currency(tx.currency),
  }
}

///|
pub fn deduplicate_transactions(
  transactions : Array[Transaction],
) -> Array[Transaction] {
  let result : Array[Transaction] = []
  for tx in transactions {
    let mut seen = false
    for old in result {
      if old.id == tx.id {
        seen = true
      }
    }
    if !seen {
      result.push(tx)
    }
  }
  result
}