require 'thor'
require 'open-uri'

module Dashenee
  class CLI < Thor
    include Thor::Actions

    attr_reader :name

    class << self
      attr_accessor :auth_token

      def hyphenate(str)
        return str.downcase if str =~ /^[A-Z-]+$/
        str.gsub('_', '-').gsub(/\B[A-Z]/, '-\&').squeeze('-').downcase
      end
    end

    no_tasks do
      %w(widget dashboard job).each do |type|
        define_method "generate_#{type}" do |name|
          @name = Thor::Util.snake_case(name)
          directory(type.to_sym, "#{type}s")
        end
      end
    end

    desc "new PROJECT_NAME", "Sets up ALL THE THINGS needed for your dashboard project."
    def new(name)
      @name = Thor::Util.snake_case(name)
      directory(:project, @name)
    end

    desc "generate (widget/dashboard/job) NAME", "Creates a new widget, dashboard, or job."
    def generate(type, name)
      public_send("generate_#{type}".to_sym, name)
    rescue NoMethodError => e
      puts "Invalid generator. Either use widget, dashboard, or job"
    end

    desc "install GIST_ID", "Installs a new widget from a gist."
    def install(gist_id)
      gist = Downloader.get_gist(gist_id)
      public_url = "https://gist.github.com/#{gist_id}"

      install_widget_from_gist(gist)

      print set_color("Don't forget to edit the ", :yellow)
      print set_color("Gemfile ", :yellow, :bold)
      print set_color("and run ", :yellow)
      print set_color("bundle install ", :yellow, :bold)
      say set_color("if needed. More information for this widget can be found at #{public_url}", :yellow)
    rescue OpenURI::HTTPError => http_error
      say set_color("Could not find gist at #{public_url}"), :red
    end

    desc "start", "Starts the server in style!"
    method_option :job_path, :desc => "Specify the directory where jobs are stored"
    def start(*args)
      port_option = args.include?('-p') ? '' : ' -p 3030'
      args = args.join(' ')
      command = "bundle exec thin -R config.ru start#{port_option} #{args}"
      command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path]
      run_command(command)
    end

    desc "stop", "Stops the thin server"
    def stop
      command = "bundle exec thin stop"
      run_command(command)
    end

    desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job. Make sure to supply your auth token if you have one set."
    def job(name, auth_token = "")
      Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require_file(file) }
      self.class.auth_token = auth_token
      f = File.join(Dir.pwd, "jobs", "#{name}.rb")
      require_file(f)
    end

    # map some commands
    map 'g' => :generate
    map 'i' => :install
    map 's' => :start

    private

    def run_command(command)
      system(command)
    end

    def install_widget_from_gist(gist)
      gist['files'].each do |file, details|
        if file =~ /\.(html|coffee|scss)\z/
          widget_name = File.basename(file, '.*')
          new_path = File.join(Dir.pwd, 'widgets', widget_name, file)
          create_file(new_path, details['content'])
        elsif file.end_with?('.rb')
          new_path = File.join(Dir.pwd, 'jobs', file)
          create_file(new_path, details['content'])
        end
      end
    end

    def require_file(file)
      require file
    end
  end
end
