require 'terminal-table'
require 'colorize'
require 'thor'
require 'launchy'

module Gush
  class CLI < Thor
    class_option :gushfile, desc: "configuration file to use", aliases: "-f"
    class_option :redis, desc: "Redis URL to use", aliases: "-r"
    class_option :namespace, desc: "namespace to run jobs in", aliases: "-n"

    def initialize(*)
      super
      Gush.configure do |config|
        config.gushfile    = options.fetch("gushfile",    config.gushfile)
        config.concurrency = options.fetch("concurrency", config.concurrency)
        config.redis_url   = options.fetch("redis",       config.redis_url)
        config.namespace   = options.fetch("namespace",   config.namespace)
        config.ttl         = options.fetch("ttl",         config.ttl)
      end
      load_gushfile
    end

    desc "create [WorkflowClass]", "Registers new workflow"
    def create(name)
      workflow = client.create_workflow(name)
      puts "Workflow created with id: #{workflow.id}"
      puts "Start it with command: gush start #{workflow.id}"
    end

    desc "start [workflow_id]", "Starts Workflow with given ID"
    def start(*args)
      id = args.shift
      workflow = client.find_workflow(id)
      client.start_workflow(workflow, args)
    end

    desc "create_and_start [WorkflowClass]", "Create and instantly start the new workflow"
    def create_and_start(name, *args)
      workflow = client.create_workflow(name)
      client.start_workflow(workflow.id, args)
      puts "Created and started workflow with id: #{workflow.id}"
    end

    desc "stop [workflow_id]", "Stops Workflow with given ID"
    def stop(*args)
      id = args.shift
      client.stop_workflow(id)
    end

    desc "show [workflow_id]", "Shows details about workflow with given ID"
    option :skip_overview, type: :boolean
    option :skip_jobs, type: :boolean
    option :jobs, default: :all
    def show(workflow_id)
      workflow = client.find_workflow(workflow_id)

      display_overview_for(workflow) unless options[:skip_overview]

      display_jobs_list_for(workflow, options[:jobs]) unless options[:skip_jobs]
    end

    desc "rm [workflow_id]", "Delete workflow with given ID"
    def rm(workflow_id)
      workflow = client.find_workflow(workflow_id)
      client.destroy_workflow(workflow)
    end

    desc "list", "Lists all workflows with their statuses"
    def list
      workflows = client.all_workflows
      rows = workflows.map do |workflow|
        [workflow.id, (Time.at(workflow.started_at) if workflow.started_at), workflow.class, {alignment: :center, value: status_for(workflow)}]
      end
      headers = [
        {alignment: :center, value: 'id'},
        {alignment: :center, value: 'started at'},
        {alignment: :center, value: 'name'},
        {alignment: :center, value: 'status'}
      ]
      puts Terminal::Table.new(headings: headers, rows: rows)
    end

    desc "viz [WorkflowClass]", "Displays graph, visualising job dependencies"
    def viz(name)
      client
      workflow = name.constantize.new
      graph = Graph.new(workflow)
      graph.viz
      Launchy.open graph.path
    end

    private

    def client
      @client ||= Client.new
    end

    def overview(workflow)
      CLI::Overview.new(workflow)
    end

    def display_overview_for(workflow)
      puts overview(workflow).table
    end

    def status_for(workflow)
      overview(workflow).status
    end

    def display_jobs_list_for(workflow, jobs)
      puts overview(workflow).jobs_list(jobs)
    end

    def gushfile
      Gush.configuration.gushfile
    end

    def load_gushfile
      file = client.configuration.gushfile
      if !gushfile.exist?
        raise Thor::Error, "#{file} not found, please add it to your project".colorize(:red)
      end

      load file.to_s
    rescue LoadError
      raise Thor::Error, "failed to require #{file}".colorize(:red)
    end
  end
end
