// The rest of this function mostly treats orchestrator chain as another container chain, so move it into
// The rest of this function mostly treats orchestrator chain as another container chain, remove it from
/// Select which container chains will be assigned collators and how many collators, but do not specify which
/// Each chain has a min and max number of collators. If the number of collators is not enough to reach the min,
/// * lower than the min of the first chain: we assign all the collators to the first chain. This is the
/// * lower than the sum of all the min: we cannot assign collators to all the chains. So remove chains until
/// we can. The order is important, the first chains will be assigned collators and the last ones will not.
/// * lower than the sum of all the max: we can assign the min value to all the chains, and have some leftover.
/// We use the same order to decide where this extra collators will go, by filling the max of the first chain,
/// * greater than the sum of all the max: all the chains will be assigned their max number of collators.
/// The first item of `chains` should be the orchestrator chain, because it will be the first one to be assigned
// Let's count how many container chains we can support with the current number of collators
// Handle orchestrator chain in a special way, we always want to assign collators to it, even if we don't
// Do not break if there are still some available collators. Even if they were not enough to reach the
// `min` of this chain, it is possible that one of the chains with less priority has a lower `min`, so
// After assigning the min to all the chains we have this remainder. The remainder will be assigned until
// Each chain will have `min + extra` collators, where extra is capped so `min + extra <= max`.
/// Same as `prioritize_invulnerables` but return the invulnerables instead of inserting them into `old_assigned`.
/// Mutates `old_assigned` by removing invulnerables from their old chain, even if they will later be assigned to
// TODO: clean this up, maybe change remove_invulnerables trait into something more ergonomic
// We already had invulnerables, we will just move them to the front of the list if they weren't already
// Still not enough invulnerables, try to get an invulnerable that is currently assigned somewhere else
/// Ensure orchestrator chain has `min_orchestrator` invulnerables. If that's not possible, it tries to add as
/// Mutates `old_assigned` because invulnerables will be inserted there, and if invulnerables were already
/// Assign collators assuming that the number of collators is greater than or equal to the required.
/// The order of both container chains and collators is important to ensure randomness when `old_assigned` is
/// * `old_assigned` does not need to be a subset of `collators`: collators are checked and removed.
/// * `old_assigned` does not need to be a subset of `chains`, unused para ids are removed. Collators
/// * `chains` `num_collators` can be 0. In that case an empty vec is returned for that para id.
/// the number of required collators, to ensure that shuffling doesn't cause a collator with low
/// Or an error if the number of collators is not enough to fill all the chains, or if the required number
// This check is necessary to ensure priority: if the number of collators is less than required, it is
// possible that the chain with the least priority could be assigned collators (since they are in
// We checked that the sum of all `num_collators` fits in `usize`, so we can safely use `as usize`.
// This has the effect of keeping collator priority (the first collator of that list is more
/// `assigned` may already contain the invulnerables, in that case they are only moved to the front.
/// Invulnerables need to be the first of the list because we may truncate the list of collators if the number of
pub fn insert_invulnerables(assigned: &mut Vec<T::AccountId>, invulnerables: &[T::AccountId]) {
/// The required number of collators for `assign_full` is greater than the provided number of collators.