///|
priv struct PreparedLinkageInputs {
  left : Array[LinkRecord]
  right : Array[LinkRecord]
  right_index : NameIndex
}

///|
fn linkage_record_order(left : LinkRecord, right : LinkRecord) -> Int {
  left.id.lexical_compare(right.id)
}

///|
fn validate_linkage_record_ids(
  records : Array[LinkRecord],
  side : LinkageSide,
) -> Result[Unit, LinkageError] {
  for record in records {
    if record.id.length() == 0 {
      return Err(EmptyLinkageRecordId(side))
    }
  }
  for index = 1; index < records.length(); index = index + 1 {
    if records[index - 1].id == records[index].id {
      return Err(DuplicateLinkageRecordId(side, records[index].id))
    }
  }
  Ok(())
}

///|
fn validate_left_linkage_names(
  records : Array[LinkRecord],
  config : LinkageConfig,
) -> Result[Unit, LinkageError] {
  for record in records {
    match
      prepare_index_name(
        record.name,
        config.match_config,
        config.blocking_algorithms,
      ) {
      Err(error) =>
        return Err(LinkageIndexFailed(LinkageLeft, record.id, error))
      Ok(_) => ()
    }
  }
  Ok(())
}

///|
fn build_right_linkage_index(
  records : Array[LinkRecord],
  config : LinkageConfig,
) -> Result[NameIndex, LinkageError] {
  let index = match
    NameIndex::new(config.match_config, config.blocking_algorithms) {
    Err(error) => return Err(LinkageIndexFailed(LinkageRight, "", error))
    Ok(value) => value
  }
  for record in records {
    match index.insert(record.id, record.name) {
      Err(error) =>
        return Err(LinkageIndexFailed(LinkageRight, record.id, error))
      Ok(_) => ()
    }
  }
  Ok(index)
}

///|
fn prepare_linkage_inputs(
  left : Array[LinkRecord],
  right : Array[LinkRecord],
  config : LinkageConfig,
) -> Result[PreparedLinkageInputs, LinkageError] {
  match validate_linkage_config(config) {
    Err(error) => return Err(error)
    Ok(_) => ()
  }
  let left_records = left.copy()
  let right_records = right.copy()
  left_records.sort_by(linkage_record_order)
  right_records.sort_by(linkage_record_order)
  match validate_linkage_record_ids(left_records, LinkageLeft) {
    Err(error) => return Err(error)
    Ok(_) => ()
  }
  match validate_linkage_record_ids(right_records, LinkageRight) {
    Err(error) => return Err(error)
    Ok(_) => ()
  }
  match validate_left_linkage_names(left_records, config) {
    Err(error) => return Err(error)
    Ok(_) => ()
  }
  let right_index = match build_right_linkage_index(right_records, config) {
    Err(error) => return Err(error)
    Ok(value) => value
  }
  Ok({ left: left_records, right: right_records, right_index })
}