require_relative 'servers_bootstrapper'

# Bootstrap groups of servers based on priorities: higher first.
# Doesn't start bootstrap of next group if bootstrap of previous group failed.
class Devops::Executor::StackExecutor
  class PrioritizedGroupsBootstrapper
    include PutsAndFlush
    attr_reader :out

    def initialize(out, jid, servers_with_priorities)
      @out, @jid, @servers_with_priorities = out, jid, servers_with_priorities
    end

    # @param servers_with_priorities [Hash] is a Hash like
    #   {1 => [server1, server2]}
    # Starts bootstrapping another group only after successful bootstrapping of previous.
    def bootstrap_servers_by_priority
      sorted_priorities.each do |priority|
        puts_and_flush "Bootstrap servers with priority '#{priority}':"
        bootstrapper = ServersBootstrapper.new(@out, @jid, @servers_with_priorities[priority])
        bootstrap_results = bootstrapper.bootstrap_group
        error = most_critical_error(bootstrap_results)
        return error if error
      end
      ServersBootstrapper::Result.from_reason(:ok)
    end

    private

    def sorted_priorities
      @servers_with_priorities.keys.sort.reverse
    end

    def most_critical_error(results)
      results.detect(&:bootstrap_error?) || results.detect(&:failed?)
    end
  end
end