class Eth2PeerSelectionStrategy implements PeerSelectionStrategy {

  @Override
  public List<PeerAddress> selectPeersToConnect(
      final P2PNetwork<?> network,
      final PeerPools peerPools,
      final Supplier<List<DiscoveryPeer>> candidates) {
    final PeerSubnetSubscriptions peerSubnetSubscriptions =
        peerSubnetSubscriptionsFactory.create(network);
    final int peersRequiredForPeerCount =
        targetPeerCountRange.getPeersToAdd(network.getPeerCount());
    final int randomlySelectedPeerCount = getCurrentRandomlySelectedPeerCount(network, peerPools);
    final int randomlySelectedPeersToAdd =
        targetPeerCountRange.getRandomlySelectedPeersToAdd(randomlySelectedPeerCount);

    final int peersRequiredForSubnets = peerSubnetSubscriptions.getSubscribersRequired();
    final int scoreBasedPeersToAdd =
        Math.max(peersRequiredForPeerCount - randomlySelectedPeerCount, peersRequiredForSubnets);
    final int maxPeersToAdd = scoreBasedPeersToAdd + randomlySelectedPeersToAdd;
    LOG.trace("Connecting to up to {} known peers", maxPeersToAdd);
    if (maxPeersToAdd == 0) {
      return emptyList();
    }

    final List<DiscoveryPeer> allCandidatePeers = new ArrayList<>(candidates.get());
    final List<PeerAddress> selectedPeers = new ArrayList<>();

    if (randomlySelectedPeersToAdd > 0) {
      selectedPeers.addAll(
          selectAndRemoveRandomPeers(
              network, peerPools, randomlySelectedPeersToAdd, allCandidatePeers));
    }

    if (scoreBasedPeersToAdd > 0) {
      selectedPeers.addAll(
          selectPeersByScore(
              network, peerSubnetSubscriptions, scoreBasedPeersToAdd, allCandidatePeers));
    }
    return unmodifiableList(selectedPeers); // Unmodifiable to make errorprone happy
  }

  public  Eth2PeerSelectionStrategy(
      final TargetPeerRange targetPeerCountRange,
      final PeerSubnetSubscriptions.Factory peerSubnetSubscriptionsFactory,
      final ReputationManager reputationManager,
      final Shuffler shuffler);

}