#!/usr/bin/env ruby

require 'docopt'
require 'yaml'
require './lib/gitlab_api'
require './lib/release_collection'
require './lib/retrospective'
require './lib/team'

class RetrospectiveCommand
  def initialize
    @options = Docopt::docopt(docstring)
    @read_client = GitlabApi.new(token: options.fetch('--read-token'))
    @write_client = GitlabApi.new(token: options.fetch('--write-token'))
    @retrospective = Retrospective.new(read_client: read_client, write_client: write_client)
    @dry_run = options.fetch('--dry-run', false)
  end

  def call
    exit_code = if options.fetch('--all-teams', false)
      run_for_all_teams
    else
      run_for_team(Team.find(options.fetch('--team')))
    end
    exit(exit_code)
  rescue Docopt::Exit => e
    puts e.message
    exit 1
  rescue GitlabApi::UpdateFailed
    exit 1
  end

  private

  attr_reader :options, :retrospective, :read_client, :write_client, :dry_run

  def run_for_all_teams
    results = Team.all.map do |team|
      success = begin
        run_for_team(team)
        true
      rescue => e
        puts "#{team.name} failed:"
        puts e
        puts e.backtrace
        false
      end

      [team.name, success]
    end

    exit_code = results.all?(&:last) ? 0 : 1

    puts Retrospective::LOG_SEPARATOR
    puts 'All done!'

    results.each do |(name, success)|
      puts "#{name} #{success ? 'succeeded' : 'failed'}"
    end

    puts "#{Retrospective::LOG_SEPARATOR}\n"

    return exit_code
  end

  def run_for_team(team)
    if options.fetch('create', false)
      retrospective.create_issue(team: team, release: release('create', :current), dry_run: dry_run)
    elsif options.fetch('update', false)
      retrospective.update_issue(team: team, release: release('update', :previous), dry_run: dry_run)
    end

    0 # exit code
  end

  def release(action, release_selector)
    releases = ReleaseCollection.new(api_client: read_client)
    target_release = options.fetch('--release')
    release = target_release ? releases.at(target_release) : releases.send(release_selector)
    exit(0) unless correct_date?(action, release) || options.fetch('--force', false)
    release
  end

  def correct_date?(action, release)
    if action == 'create'
      Date.today - Date.parse(release['start_date']) == 9
    elsif action == 'update'
      Date.today - Date.parse(release['due_date']) == 4
    end
  end

  def docstring
    <<~DOCSTRING
      Create a retrospective issue

      Usage:
        #{__FILE__} (create|update) --read-token=<token> --write-token=<token> (--all-teams|--team=<team>) [--dry-run] [--force] [--release=<release>]
        #{__FILE__} -h | --help

      Options:
        -h --help              Show this screen.
        --dry-run              Print the issue contents to standard output.
        --force                Force the process to run, regardless of date.
        --read-token=<token>   GitLab API token with read permission.
        --write-token=<token>  GitLab API token with write permission to the group intended to manage retrospective issues.
        --all-teams            Run for all teams and print a summary of the results.
        --team=<team>          Team name, including initial caps (team info in teams.yml).
        --release=<release>    Target release (eg 17.5). Defaults to latest
    DOCSTRING
  end
end

# Allow for testing by halting execution when this file is required from another
return unless $0 == __FILE__

RetrospectiveCommand.new.call
