///|
fn best_candidate(
  instance : @core.VrpInstance,
  solution : @core.Solution,
  customer : Int,
  config : @core.SolveConfig,
) -> @core.CandidateInsertion? {
  let candidates = @core.best_insertions_for_customer(
    instance, solution, customer, config,
  )
  candidates.get(0)
}

///|
pub fn greedy_repair(
  instance : @core.VrpInstance,
  partial : @core.Solution,
  config : @core.SolveConfig,
) -> @core.Solution {
  let mut current = partial
  for customer in partial.unassigned.copy() {
    match best_candidate(instance, current, customer, config) {
      None => ()
      Some(candidate) => current = candidate.solution
    }
  }
  current
}

///|
fn regret_score(candidates : Array[@core.CandidateInsertion]) -> Double {
  if candidates.length() == 0 {
    -1.0
  } else if candidates.length() == 1 {
    -candidates[0].objective
  } else {
    candidates[1].objective - candidates[0].objective
  }
}

///|
pub fn regret2_repair(
  instance : @core.VrpInstance,
  partial : @core.Solution,
  config : @core.SolveConfig,
) -> @core.Solution {
  let mut current = partial
  for _ in 0.. chosen_score {
        chosen_score = score
        chosen_customer = customer
        chosen_solution = candidates[0].solution
      }
    }
    if chosen_customer < 0 {
      break
    }
    current = chosen_solution
  }
  current
}

///|
pub fn repair_solution(
  instance : @core.VrpInstance,
  solution : @core.Solution,
  operator : @core.RepairOperator,
  config : @core.SolveConfig,
) -> @core.Solution {
  match operator {
    @core.RepairOperator::Greedy => greedy_repair(instance, solution, config)
    @core.RepairOperator::Regret2 => regret2_repair(instance, solution, config)
    @core.RepairOperator::DemandFirst =>
      demand_first_repair(instance, solution, config)
    @core.RepairOperator::TimeWindow =>
      time_window_repair(instance, solution, config)
  }
}