require 'lib/puts_and_flush'
class Devops::Executor::StackExecutor
  class StackServersFetcher
    include PutsAndFlush
    attr_reader :out

    NEW = :new
    PERSISTED = :persisted
    STALE = :stale

    def initialize(stack, out)
      @stack, @out = stack, out
      @by_state = {NEW => [], PERSISTED => [], STALE => []}
      fetch
    end


    def new_servers_by_priorities
      servers_with_priority = {}
      @by_state[NEW].each do |provider_info|
        priority = priority_from_info(provider_info)
        servers_with_priority[priority] ||= []
        servers_with_priority[priority] << provider_info
      end
      servers_with_priority
    end

    def servers_to_persist
      @by_state[NEW]
    end

    def already_persisted_servers
      @by_state[PERSISTED]
    end

    def stale_servers
      @by_state[STALE]
    end

    private

    def fetch
      @servers_info = @stack.provider_instance.stack_servers(@stack)
      divide_into_states
      output_fetched_servers
    end

    def priority_from_info(provider_info)
      if provider_info['tags']
        priority = provider_info['tags']['cid:priority'].to_i
      else
        0
      end
    end

    def divide_into_states
      persisted = Devops::Model::Server.stack_servers(@stack.id)
      persisted_ids = persisted.map(&:id)
      in_cloud_ids = @servers_info.map {|info| info['id']}
      new_ids = in_cloud_ids - persisted_ids
      deleted_ids = persisted_ids - in_cloud_ids

      @servers_info.each do |info|
        if new_ids.include?(info['id'])
          @by_state[NEW] << info
        else
          @by_state[PERSISTED] << info
        end
      end

      @by_state[STALE] = persisted.select { |server| deleted_ids.include?(server.id) }
    end

    # Do not move it to stack executor till set events handling properly.
    # For now there may be already persisted servers on creation because of too early events from aws.
    def output_fetched_servers
      if servers_to_persist.any?
        out.puts 'Servers to persist:'
        servers_to_persist.each { |info| out.puts JSON.pretty_generate(info) }
      else
        out.puts 'There are no servers to persist.'
      end

      if already_persisted_servers.any?
        out.puts "\nAlready persisted servers:"
        already_persisted_servers.each { |info| out.puts JSON.pretty_generate(info) }
      end

      if stale_servers.any?
        out.puts "\nStale servers:"
        stale_servers.each { |server| out.puts JSON.pretty_generate(server.to_hash) }
      else
        out.puts "\nThere are no stale servers."
      end
      out.flush
    end
  end
end
