Encoding.default_external = 'UTF-8'

require './lib/description_template'
require './lib/gitlab_api'
require './lib/team'

class Retrospective
  LOG_SEPARATOR = '-' * 70

  def initialize(read_client: , write_client:)
    @read_client = read_client
    @write_client = write_client
  end

  def create_issue(team:, release:, dry_run:)
    issue_url = nil
    template = DescriptionTemplate.new(team, release, api_client: read_client)
    result = template.result_with_hash(updating_description: false)

    log_info('Issue', result, dry_run: dry_run)

    unless dry_run
      created_issue = write_client.post(
        "projects/gl-retrospectives%2F#{team.project}/issues",
        body: {
          title: "#{release['title']} #{team.name} retrospective",
          description: result,
          confidential: team.confidential?
        }
      )

      issue_url = created_issue['_links']['self']

      puts "Created with URL #{created_issue['web_url']}"
      puts ''
    end

    mention_team(template.current_api_path, team: team, dry_run: dry_run) if team.mention_team_on_creation

    create_discussions(issue_url, team: team, dry_run: dry_run)
  end

  def update_issue(team:, release:, dry_run:)
    template = DescriptionTemplate.new(team, release, api_client: read_client)
    result = template.result_with_hash(updating_description: true, query_all_groups: team.query_all_groups?)

    log_info("Issue #{template.current_issue_url}", result, verb: 'update', dry_run: dry_run)

    unless dry_run
      write_client.put(template.current_api_path, body: { description: result })

      puts "Updated issue #{template.current_issue_url}"
      puts ''
    end

    mention_team(template.current_api_path, team: team, dry_run: dry_run) if team.mention_team

    if team.create_individual_discussions
      create_individual_discussions(template.current_api_path, team: team,
                                                               dry_run: dry_run)
    end
  end

  private

  attr_reader :read_token, :write_token, :write_client, :read_client

  def create_discussions(issue_url, team:, dry_run:)
    questions = team.discussions.to_a

    if team.create_discussions
      questions.unshift(
        '👍 What went well this release?',
        '👎 What didn\'t go well this release?',
        '📈 What can we improve going forward?',
        '🌟 What praise do you have for the group?'
      )
    end

    return if questions.empty?

    questions.each do |question|
      comment = "## #{question}"

      log_info('Discussion', comment, dry_run: dry_run)

      unless dry_run
        write_client.post("#{issue_url}/discussions", body: { body: comment })
      end
    end

    puts 'Created discussions'
    puts ''
  end

  def mention_team(issue_url, team:, dry_run:)
    comment = Team::TEAM_MEMBER_FIELDS.map do |people|
      next if team[people].nil? || team[people].empty?

      [
        '*',
        *team[people].map { |person| "@#{person}" },
        "(#{people})"
      ].join(' ')
    end.compact.join("\n")

    log_info('Mention comment', comment, dry_run: dry_run)

    unless dry_run
      return if team_mention_comment_created?(issue_url: issue_url, comment_body: comment)

      write_client.post("#{issue_url}/notes", body: { body: comment })

      puts 'Created comment'
      puts ''
    end
  end

  def team_mention_comment_created?(issue_url:, comment_body:)
    comments = read_client.get("#{issue_url}/notes")
    comments.any? { |comment| comment['body'] == comment_body }
  end

  def create_individual_discussions(issue_url, team:, dry_run:)
    questions = Team::TEAM_MEMBER_FIELDS.map do |people|
      next if team[people].nil? || team[people].empty?

      team[people].map do |person|
        "@#{person} what went well this release? What didn't go well? What can we improve?"
      end
    end.flatten.compact

    questions.each do |question|
      log_info('Discussion', question, dry_run: dry_run)

      write_client.post("#{issue_url}/discussions", body: { body: question }) unless dry_run
    end

    puts 'Created individual discussions'
    puts ''
  end

  def log_info(header, message, dry_run:, verb: 'create')
    puts LOG_SEPARATOR
    puts "#{header} to #{verb}#{' (--dry-run enabled)' if dry_run}"
    puts LOG_SEPARATOR
    puts message
    puts LOG_SEPARATOR
    puts ''
  end

  def inspect
    "#<#{self.class.name}:#{object_id}>"
  end
end
