require "db/mongo/models/stack/stack_factory"
require "lib/puts_and_flush"
module Devops; module Executor; class StackExecutor; end; end; end # predeclare for visibility
require_relative "stack_executor/stack_creation_waiter"
require_relative "stack_executor/stack_servers_persister"
require_relative "stack_executor/prioritized_groups_bootstrapper"
require_relative "stack_executor/stack_servers_fetcher"

module Devops
  module Executor
    class StackExecutor
      include PutsAndFlush
      attr_reader :out, :stack

      def initialize(options)
        @out = options.fetch(:out)
        @stack = options[:stack]
        self.just_persisted_by_priority = {}
        @current_user = options.fetch(:current_user)
      end

      def create_stack(stack_attrs)
        stack_attrs.merge!('persisting_is_locked' => true)
        @stack = Devops::Model::StackFactory.create(stack_attrs["provider"], stack_attrs, out)
        @stack.save
      end

      def wait_till_stack_is_created
        wait_result = waiter.wait
        stack.unlock_persisting!
        wait_result.ok?
      end

      def persist_new_servers
        reload_stack
        raise 'It seems that stack is synchronizing at the moment' if stack.persisting_is_locked
        begin
          stack.lock_persisting!
          fetcher.new_servers_by_priorities.each do |priority, provider_infos|
            servers = provider_infos.map {|info| persister.persist(info) }
            just_persisted_by_priority[priority] = servers
          end

          just_persisted_by_priority.values.flatten.each do |server|
            puts_and_flush "\n\nPersisted server #{server.id}: #{JSON.pretty_generate(server.to_hash)}"
          end
        ensure
          stack.unlock_persisting!
        end
      end

      def bootstrap_just_persisted(jid)
        puts_and_flush "Bootstrapping just persisted servers" if just_persisted_by_priority.values.flatten.any?
        just_persisted_by_priority.each do |priority, servers|
          puts_and_flush "Servers with priority '#{priority}': #{servers.map(&:id).join(", ")}"
        end
        PrioritizedGroupsBootstrapper.new(out, jid, just_persisted_by_priority).bootstrap_servers_by_priority
      end

      def delete_stale_servers
        fetcher.stale_servers.each do |server|
          server_executor = Devops::Executor::ServerExecutor.new(server, out, @current_user)
          server_executor.delete_server
        end
      end

      def delete_stack
        stack.delete_stack_in_cloud!
        # mongo.stack_servers_delete(stack.name)
        # mongo.stack_delete(stack.id)
        Devops::Model::Server.delete_stack_servers(stack.id)
        stack.delete
      end

      private

      attr_accessor :just_persisted_by_priority

      def reload_stack
        @stack = Model::StackAws.find(@stack.id)
      end

      def fetcher
        @fetcher ||= StackServersFetcher.new(stack, out)
      end

      def persister
        @persister ||= StackServersPersister.new(@stack)
      end

      def waiter
        StackCreationWaiter.new(stack, out)
      end

    end
  end
end
