require “thor” require “active_support” # for autoload require “active_support/core_ext”

# Override thor's long_desc identation behavior # github.com/erikhuda/thor/issues/398 class Thor

module Shell
  class Basic
    def print_wrapped(message, options = {})
      message = "\n#{message}" unless message[0] == "\n"
      stdout.puts message
    end
  end
end

end

module <%= project_class_name %>

class Command < Thor
  class << self
    # thor_args is an array of commands. Examples:
    #   ["help"]
    #   ["dynamodb:migrate"]
    #
    # Same signature as RakeCommand.perform.  Signature is a little weird
    # with some repetition.  Examples:
    #
    #   <%= project_class_name %>::Main.perform("hello", ["hello"])
    #   <%= project_class_name %>::Main.perform("dynamodb:migrate", ["migrate"])
    #
    def perform(full_command, thor_args)
      config = {} # doesnt seem like config is used
      dispatch(nil, thor_args, nil, config)
    rescue Thor::InvocationError => e
      puts e.message
      puts "  ufo #{full_command} -h # for more help"
      exit 1
    end

    # Track all command subclasses.
    def subclasses
      @subclasses ||= []
    end

    def inherited(base)
      super

      if base.name
        self.subclasses << base
      end
    end

    # Useful for help menu when we need to have all the definitions loaded.
    # Using constantize instead of require so we dont care about
    # order. The eager load actually uses autoloading.
    @@eager_loaded = false
    def eager_load!
      return if @@eager_loaded

      path = File.expand_path("../../", __FILE__)
      Dir.glob("#{path}/<%= underscored_name %>/**/*.rb").select do |path|
        next if !File.file?(path)

        class_name = path
                      .sub(/\.rb$/,'')
                      .sub(%r{.*/lib/},'')
                      .classify

        if class_name.include?('-')
          puts "WARN: Unable to autoload a class with a dash in the name" if debug?
          next
        end

        class_name = class_map[class_name] || class_name

        puts "eager_load! loading path: #{path} class_name: #{class_name}" if debug?
        class_name.constantize # dont have to worry about order.
      end

      @@eager_loaded = true
    end

    # Special class mapping cases. This is because ActiveSupport's autoloading
    # forces a specific naming convention.
    def class_map
      map = {
        "<%= project_class_name %>::Cli" => "<%= project_class_name %>::CLI",
        "<%= project_class_name %>::Version" => "<%= project_class_name %>::VERSION",
        "<%= project_class_name %>::Completion" => "<%= project_class_name %>::Completions",
      }
      map.merge(additional_class_map)
      map
    end

    # Override this if you need add addtional class mappings.
    def additional_class_map
      {}
    end

    # Fully qualifed task names. Examples:
    #   hello
    #   sub:goodbye
    def namespaced_commands
      eager_load!
      subclasses.map do |klass|
        klass.all_tasks.keys.map do |task_name|
          klass = klass.to_s.sub('<%= project_class_name %>::','')
          namespace = klass =~ /^Main/ ? nil : klass.underscore.gsub('/',':')
          [namespace, task_name].compact.join(':')
        end
      end.flatten.sort
    end

    # Use <%= project_class_name %> banner instead of Thor to account for namespaces in commands.
    def banner(command, namespace = nil, subcommand = false)
      namespace = namespace_from_class(self)
      command_name = command.usage # set with desc when defining tht Thor class
      namespaced_command = [namespace, command_name].compact.join(':')

      "<%= project_name %> #{namespaced_command}"
    end

    def namespace_from_class(klass)
      namespace = klass.to_s.sub('<%= project_class_name %>::', '').underscore.gsub('/',':')
      namespace unless namespace == "main"
    end

    def help_list(all=false)
      # hack to show hidden comands when requested
      Thor::HiddenCommand.class_eval do
        def hidden?; false; end
      end if all

      list = []
      eager_load!
      subclasses.each do |klass|
        commands = klass.printable_commands(true, false)
        commands.reject! { |array| array[0].include?(':help') }
        list += commands
      end

      list.sort_by! { |array| array[0] }
    end

    # Example:
    #    klass_from_namespace(nil) => Main
    #    klass_from_namespace("sub") => Sub
    def klass_from_namespace(namespace)
      if namespace.nil?
        <%= project_class_name %>::Main
      else
        class_name = namespace.gsub(':','/')
        class_name = "<%= project_class_name %>::#{class_name.classify}"
        class_name = class_map[class_name] || class_name
        class_name.constantize
      end
    end

    # If this fails to match then it'l just return the original full command
    def autocomplete(full_command)
      return nil if full_command.nil? # <%= project_name %> help

      eager_load!

      words = full_command.split(':')
      namespace = words[0..-2].join(':') if words.size > 1
      command = words.last

      # Thor's normalize_command_name autocompletes the command but then we need to add the namespace back
      begin
        thor_subclass = klass_from_namespace(namespace) # could NameError
        command = thor_subclass.normalize_command_name(command) # could Thor::AmbiguousCommandError
        [namespace, command].compact.join(':')
      rescue NameError
        full_command # return original full_command
      rescue Thor::AmbiguousCommandError => e
        full_command # return original full_command
      end
    end

    def debug?
      ENV['DEBUG'] && !ENV['TEST']
    end
  end
end

end