require 'cl'

module Dpl
  class Cli < Cl
    def self.new(ctx = nil, name = 'dpl')
      ctx ||= Dpl::Ctx::Bash.new
      super
    end

    def run(args)
      args = untaint(args)
      args = with_provider_opt(args)
      super
    rescue UnknownCmd
      unknown_provider(args.first)
    rescue Error => e
      error(e)
    end

    # Tainting is being used for automatically obfuscating values for secure
    # options, so we want to untaint all incoming args here.
    def untaint(args)
      args.map(&:dup).each(&:untaint)
    end

    # backwards compatibility for travis-build dpl v1 integration
    def with_provider_opt(args)
      return args unless arg = args.detect { |arg| arg.include?('--provider') }
      args.delete(arg)
      [arg.split('=').last, *args]
    end

    def error(e)
      msg = "\e[31m#{e.message}\e[0m"
      msg = [msg, *e.backtrace].join("\n") if e.backtrace?
      abort msg
    end

    def unknown_provider(name)
      msg = "\e[31mUnknown provider: #{name}\e[0m"
      msg << "\nDid you mean: #{suggestions(name).join(', ')}?" if suggestions(name).any?
      abort msg
    end

    def suggestions(name)
      return [] unless defined?(DidYouMean)
      DidYouMean::SpellChecker.new(dictionary: providers).correct(name)
    end

    def providers
      Cl::Cmd.registry.keys.map(&:to_s)
    end
  end
end
