require_relative 'services_helper'

module Kontena::Cli::Services
  class ExecCommand < Kontena::Command
    include Kontena::Cli::Common
    include Kontena::Cli::GridOptions
    include ServicesHelper

    parameter "NAME", "Service name"
    parameter "CMD ...", "Command"

    option ["-i", "--instance"], "INSTANCE", "Exec on given numbered instance, default first running" do |value| Integer(value) end
    option ["-a", "--all"], :flag, "Exec on all running instances"
    option ["--shell"], :flag, "Execute as a shell command"
    option ["--skip"], :flag, "Skip failed instances when executing --all"
    option ["--silent"], :flag, "Do not show exec status"
    option ["--verbose"], :flag, "Show exec status"

    requires_current_master
    requires_current_grid

    # Exits if exec returns with non-zero
    def exec_container(container)
      if shell?
        cmd = ['sh', '-c', cmd_list.join(' ')]
      else
        cmd = cmd_list
      end

      stdout = stderr = exit_status = nil

      if !silent? && (verbose? || all?)
        spinner "Executing command on #{container['name']}" do
          stdout, stderr, exit_status = client.post("containers/#{container['id']}/exec", {cmd: cmd})

          raise Kontena::Cli::SpinAbort if exit_status != 0
        end
      else
        stdout, stderr, exit_status = client.post("containers/#{container['id']}/exec", {cmd: cmd})
      end

      stdout.each do |chunk| $stdout.write chunk end
      stderr.each do |chunk| $stderr.write chunk end

      exit exit_status if exit_status != 0 && !skip?

      return exit_status == 0
    end

    def execute
      service_containers = client.get("services/#{parse_service_id(name)}/containers")['containers']
      service_containers.sort_by! { |container| container['instance_number'] }
      running_containers = service_containers.select{|container| container['status'] == 'running' }

      if running_containers.empty?
        exit_with_error "Service #{name} does not have any running containers"
      end

      if all?
        ret = true
        service_containers.each do |container|
          if container['status'] == 'running'
            if !exec_container(container)
              ret = false
            end
          else
            warning "Service #{name} container #{container['name']} is #{container['status']}, skipping"
          end
        end
        return ret
      elsif instance
        if !(container = service_containers.find{|container| container['instance_number'] == instance})
          exit_with_error "Service #{name} does not have container instance #{instance}"
        elsif container['status'] != 'running'
          exit_with_error "Service #{name} container #{container['name']} is not running, it is #{container['status']}"
        else
          exec_container(container)
        end
      else
        exec_container(running_containers.first)
      end
    end
  end
end
