# frozen_string_literal: true

require 'spec_helper'
require 'email_spec'

RSpec.describe Emails::MergeRequests do
  include EmailSpec::Matchers

  include_context 'gitlab email notification'

  let_it_be(:current_user, reload: true) { create(:user, email: "current@email.com", name: 'www.example.com') }
  let_it_be(:assignee, reload: true) { create(:user, email: 'assignee@example.com', name: 'John Doe') }
  let_it_be(:reviewer, reload: true) { create(:user, email: 'reviewer@example.com', name: 'Jane Doe') }
  let_it_be(:project) { create(:project, :repository) }
  let_it_be(:merge_request) do
    create(
      :merge_request,
      source_project: project,
      target_project: project,
      author: current_user,
      assignees: [assignee],
      reviewers: [reviewer],
      description: 'Awesome description'
    )
  end

  let(:recipient) { assignee }
  let(:current_user_sanitized) { 'www_example_com' }

  describe '#new_mention_in_merge_request_email' do
    subject { Notify.new_mention_in_merge_request_email(recipient.id, merge_request.id, current_user.id) }

    it 'has the correct subject and body' do
      aggregate_failures do
        is_expected.to have_referable_subject(merge_request, reply: true)
        is_expected.to have_body_text(project_merge_request_path(project, merge_request))
        is_expected.to have_body_text('You have been mentioned in merge request')
        is_expected.to have_link(merge_request.to_reference, href: project_merge_request_url(merge_request.target_project, merge_request))
        is_expected.to have_text_part_content(assignee.name)
        is_expected.to have_text_part_content(reviewer.name)
        is_expected.to have_html_part_content(assignee.name)
        is_expected.to have_html_part_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template notify')
    end
  end

  describe '#merge_request_unmergeable_email' do
    subject { Notify.merge_request_unmergeable_email(recipient.id, merge_request.id) }

    it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
      let(:model) { merge_request }
    end

    it_behaves_like 'a multiple recipients email'
    it_behaves_like 'it should show Gmail Actions View Merge request link'
    it_behaves_like 'an unsubscribeable thread'
    it_behaves_like 'appearance header and footer enabled'
    it_behaves_like 'appearance header and footer not enabled'

    it 'is sent as the merge request author' do
      expect_sender(merge_request.author)
    end

    it 'has the correct subject and body' do
      aggregate_failures do
        is_expected.to have_referable_subject(merge_request, reply: true)
        is_expected.to have_body_text(project_merge_request_path(project, merge_request))
        is_expected.to have_body_text('due to conflict.')
        is_expected.to have_link(merge_request.to_reference, href: project_merge_request_url(merge_request.target_project, merge_request))
        is_expected.to have_text_part_content(assignee.name)
        is_expected.to have_html_part_content(assignee.name)
        is_expected.to have_text_part_content(reviewer.name)
        is_expected.to have_html_part_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template notify')
    end
  end

  describe '#closed_merge_request_email' do
    subject { Notify.closed_merge_request_email(recipient.id, merge_request.id, current_user.id) }

    it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
      let(:model) { merge_request }
    end

    it_behaves_like 'it should show Gmail Actions View Merge request link'
    it_behaves_like 'an unsubscribeable thread'
    it_behaves_like 'appearance header and footer enabled'
    it_behaves_like 'appearance header and footer not enabled'

    it 'is sent as the author' do
      expect_sender(current_user)
    end

    it 'has the correct subject and body' do
      aggregate_failures do
        is_expected.to have_referable_subject(merge_request, reply: true)
        is_expected.to have_body_text('closed')
        is_expected.to have_body_text(current_user_sanitized)
        is_expected.to have_body_text(project_merge_request_path(project, merge_request))
        is_expected.to have_link(merge_request.to_reference, href: project_merge_request_url(merge_request.target_project, merge_request))

        expect(subject.text_part).to have_content(assignee.name)
        expect(subject.text_part).to have_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template notify')
    end
  end

  describe '#merged_merge_request_email' do
    let(:merge_author) { assignee }

    subject { Notify.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) }

    it_behaves_like 'a multiple recipients email'
    it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
      let(:model) { merge_request }
    end

    it_behaves_like 'it should show Gmail Actions View Merge request link'
    it_behaves_like 'an unsubscribeable thread'
    it_behaves_like 'appearance header and footer enabled'
    it_behaves_like 'appearance header and footer not enabled'

    it 'is sent as the merge author' do
      expect_sender(merge_author)
    end

    it 'has the correct subject and body' do
      aggregate_failures do
        is_expected.to have_referable_subject(merge_request, reply: true)
        is_expected.to have_body_text('merged')
        is_expected.to have_body_text(project_merge_request_path(project, merge_request))
        is_expected.to have_link(merge_request.to_reference, href: project_merge_request_url(merge_request.target_project, merge_request))

        expect(subject.text_part).to have_content(assignee.name)
        expect(subject.text_part).to have_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template notify')
    end
  end

  describe '#merge_request_status_email' do
    let(:status) { 'reopened' }

    subject { Notify.merge_request_status_email(recipient.id, merge_request.id, status, current_user.id) }

    it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
      let(:model) { merge_request }
    end

    it_behaves_like 'it should show Gmail Actions View Merge request link'
    it_behaves_like 'an unsubscribeable thread'
    it_behaves_like 'appearance header and footer enabled'
    it_behaves_like 'appearance header and footer not enabled'

    it 'is sent as the author' do
      expect_sender(current_user)
    end

    it 'has the correct subject and body' do
      aggregate_failures do
        is_expected.to have_referable_subject(merge_request, reply: true)
        is_expected.to have_body_text(status)
        is_expected.to have_body_text(current_user_sanitized)
        is_expected.to have_body_text(project_merge_request_path(project, merge_request))
        is_expected.to have_link(merge_request.to_reference, href: project_merge_request_url(merge_request.target_project, merge_request))

        expect(subject.text_part).to have_content(assignee.name)
        expect(subject.text_part).to have_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template notify')
    end
  end

  describe "#merge_when_pipeline_succeeds_email" do
    let(:title) { "Merge request #{merge_request.to_reference} was set to auto-merge by #{current_user.name}" }

    subject { Notify.merge_when_pipeline_succeeds_email(recipient.id, merge_request.id, current_user.id) }

    it "has required details" do
      aggregate_failures do
        is_expected.to have_content(title)
        is_expected.to have_content(merge_request.to_reference)
        is_expected.to have_content(current_user.name)
        is_expected.to have_text_part_content(assignee.name)
        is_expected.to have_html_part_content(assignee.name)
        is_expected.to have_text_part_content(reviewer.name)
        is_expected.to have_html_part_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template mailer')
    end
  end

  describe '#approved_merge_request_email' do
    subject { Notify.approved_merge_request_email(recipient.id, merge_request.id, current_user.id) }

    it 'has the correct body' do
      aggregate_failures do
        is_expected.to have_body_text('was approved by')
        is_expected.to have_body_text(current_user.name)
        is_expected.to have_text_part_content(assignee.name)
        is_expected.to have_html_part_content(assignee.name)
        is_expected.to have_text_part_content(reviewer.name)
        is_expected.to have_html_part_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template mailer')
    end
  end

  describe '#unapproved_merge_request_email' do
    subject { Notify.unapproved_merge_request_email(recipient.id, merge_request.id, current_user.id) }

    it 'has the correct body' do
      aggregate_failures do
        is_expected.to have_body_text('was unapproved by')
        is_expected.to have_body_text(current_user.name)
        is_expected.to have_text_part_content(assignee.name)
        is_expected.to have_html_part_content(assignee.name)
        is_expected.to have_text_part_content(reviewer.name)
        is_expected.to have_html_part_content(reviewer.name)
      end
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template mailer')
    end
  end

  describe "#resolved_all_discussions_email" do
    subject { Notify.resolved_all_discussions_email(recipient.id, merge_request.id, current_user.id) }

    it "includes the name of the resolver" do
      expect(subject).to have_body_text current_user_sanitized
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template notify')
    end
  end

  describe '#merge_requests_csv_email' do
    let(:merge_requests) { create_list(:merge_request, 10) }
    let(:export_status) do
      {
        rows_expected: 10,
        rows_written: 10,
        truncated: false
      }
    end

    let(:csv_data) { MergeRequests::ExportCsvService.new(MergeRequest.all, project).csv_data }

    subject { Notify.merge_requests_csv_email(recipient, project, csv_data, export_status) }

    it { expect(subject.subject).to eq("#{project.name} | Exported merge requests") }
    it { expect(subject.to).to contain_exactly(recipient.notification_email_for(project.group)) }
    it { expect(subject.html_part).to have_content("Your CSV export of 10 merge requests from project") }
    it { expect(subject.text_part).to have_content("Your CSV export of 10 merge requests from project") }

    context 'when truncated' do
      let(:export_status) do
        {
          rows_expected: 10,
          rows_written: 10,
          truncated: true
        }
      end

      it { expect(subject).to have_content('attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15 MiB.') }
    end

    it "uses the correct layout template" do
      is_expected.to have_html_part_content('determine_layout returned template mailer')
    end
  end

  def expect_sender(user)
    sender = subject.header[:from].addrs[0]
    expect(sender.display_name).to eq("#{user.name} (@#{user.username})")
    expect(sender.address).to eq(gitlab_sender)
  end
end
