# frozen_string_literal: true

PROJECT_NAME = helper.config.project_name

MESSAGE = <<MARKDOWN
## Reviewer roulette

Changes that require review have been detected! A merge request is normally
reviewed by both a reviewer and a maintainer in its primary category and by a
maintainer in all other categories.
MARKDOWN

TABLE_MARKDOWN = <<MARKDOWN

To spread load more evenly across eligible reviewers, Danger has picked a candidate for each
review slot. Feel free to
[override these selections](https://about.gitlab.com/handbook/engineering/projects/##{PROJECT_NAME})
if you think someone else would be better-suited
or use the [GitLab Review Workload Dashboard](https://gitlab-org.gitlab.io/gitlab-roulette/?currentProject=#{PROJECT_NAME})
to find other available reviewers.

To read more on how to use the reviewer roulette, please take a look at the
[Engineering workflow](https://about.gitlab.com/handbook/engineering/workflow/#basics)
and [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html).
Please consider assigning a reviewer or maintainer who is a
[domain expert](https://about.gitlab.com/handbook/engineering/projects/##{PROJECT_NAME})
in the area of the merge request.

Once you've decided who will review this merge request, mention them as you
normally would! Danger does not automatically notify them for you.

MARKDOWN

TABLE_HEADER_WITH_CATEGORIES = <<MARKDOWN
| Category | Reviewer | Maintainer |
| -------- | -------- | ---------- |
MARKDOWN

TABLE_HEADER_WITHOUT_CATEGORIES = <<MARKDOWN
| Reviewer | Maintainer |
| -------- | ---------- |
MARKDOWN

WARNING_MESSAGE = <<MARKDOWN
⚠ Failed to retrieve information ⚠
%{warnings}
MARKDOWN

OPTIONAL_REVIEW_TEMPLATE = '%{role} review is optional'
NOT_AVAILABLE_TEMPLATE = 'No %{role} available'

def note_for_spins_role(spins, role)
  spins.each do |spin|
    note = note_for_spin_role(spin, role)

    return note if note
  end

  NOT_AVAILABLE_TEMPLATE % { role: role }
end

def note_for_spin_role(spin, role)
  if spin.optional_role == role
    return OPTIONAL_REVIEW_TEMPLATE % { role: role.capitalize }
  end

  spin.public_send(role)&.markdown_name(author: roulette.team_mr_author)
end

def markdown_row_for_spins(category, spins_array, show_category_column:)
  reviewer_note = note_for_spins_role(spins_array, :reviewer)
  maintainer_note = note_for_spins_role(spins_array, :maintainer)

  row = +"| #{reviewer_note} | #{maintainer_note} |"
  row.prepend("| #{helper.label_for_category(category)} ") if show_category_column
  row
end

def warning_list(roulette)
  return unless roulette.warnings.any?

  roulette.warnings.map { |warning| "* #{warning}" }.join("\n")
end

changes = helper.changes_by_category
categories = roulette.prepare_categories(changes.keys)

if changes.any?
  show_category_column = categories.size > 1 || categories.first != :none
  random_roulette_spins = roulette.spin(nil, categories)

  rows = random_roulette_spins.map do |spin|
    markdown_row_for_spins(spin.category, [spin], show_category_column: show_category_column)
  end

  table_header = show_category_column ? TABLE_HEADER_WITH_CATEGORIES : TABLE_HEADER_WITHOUT_CATEGORIES

  markdown(MESSAGE)

  warnings = warning_list(roulette)

  markdown(format(WARNING_MESSAGE, warnings: warnings)) if warnings

  markdown(TABLE_MARKDOWN + table_header + rows.join("\n")) unless rows.empty?
end
