# 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.

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.

MARKDOWN

NO_AUTO_ASSIGN = <<MARKDOWN
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_header + rows.join("\n")) unless rows.empty?

  if roulette.auto_assign_reviewers?
    roulette.assign_reviewers_from_roulette(random_roulette_spins)
  else
    markdown(NO_AUTO_ASSIGN)
  end
end
