# frozen_string_literal: true

require 'spec_helper'
require 'email_spec'

describe Emails::ServiceDesk do
  include EmailSpec::Helpers
  include EmailSpec::Matchers
  include EmailHelpers

  include_context 'gitlab email notification'

  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project) }
  let_it_be(:issue) { create(:issue, project: project) }
  let(:template) { double(content: template_content) }

  class ServiceEmailClass < ApplicationMailer
    include GitlabRoutingHelper
    include EmailsHelper
    include Emails::ServiceDesk

    helper GitlabRoutingHelper
    helper EmailsHelper

    append_view_path Rails.root.join('ee', 'app', 'views', 'notify')

    # this method is implemented in Notify class, we don't need to test it
    def reply_key
      'test-key'
    end

    # this method is implemented in Notify class, we don't need to test it
    def sender(author_id, params = {})
      author_id
    end

    # this method is implemented in Notify class
    #
    # We do not need to test the Notify method, it is already tested in notify_spec
    def mail_new_thread(issue, options)
      # we need to rewrite this in order to look up templates in the correct directory
      self.class.mailer_name = 'notify'

      # this is needed for default layout
      @unsubscribe_url = 'http://unsubscribe.example.com'

      mail(options)
    end
    alias_method :mail_answer_thread, :mail_new_thread
  end

  shared_examples 'handle template content' do |template_key|
    before do
      expect(Gitlab::Template::ServiceDeskTemplate).to receive(:find)
        .with(template_key, issue.project)
        .and_return(template)
    end

    it 'builds the email correctly' do
      aggregate_failures do
        is_expected.to have_referable_subject(issue, include_project: false, reply: reply_in_subject)
        is_expected.to have_body_text(expected_body)
        expect(subject.content_type).to include('text/html')
      end
    end
  end

  shared_examples 'read template from repository' do |template_key|
    let(:template_content) { 'custom text' }
    let(:issue) { create(:issue, project: project)}

    context 'when a template is in the repository' do
      let(:project) { create(:project, :custom_repo, files: { ".gitlab/service_desk_templates/#{template_key}.md" => template_content }) }

      it 'uses the text template from the template' do
        is_expected.to have_body_text(template_content)
      end
    end

    context 'when the service_desk_templates directory does not contain correct template' do
      let(:project) { create(:project, :custom_repo, files: { ".gitlab/service_desk_templates/another_file.md" => template_content }) }

      it 'uses the default template' do
        is_expected.to have_body_text(default_text)
      end
    end

    context 'when the service_desk_templates directory does not exist' do
      let(:project) { create(:project, :custom_repo, files: { "other_directory/another_file.md" => template_content }) }

      it 'uses the default template' do
        is_expected.to have_body_text(default_text)
      end
    end

    context 'when the project does not have a repo' do
      let(:project) { create(:project) }

      it 'uses the default template' do
        is_expected.to have_body_text(default_text)
      end
    end
  end

  describe '.service_desk_thank_you_email' do
    let_it_be(:reply_in_subject) { true }
    let_it_be(:default_text) do
      "Thank you for your support request! We are tracking your request as ticket #{issue.to_reference}, and will respond as soon as we can."
    end

    subject { ServiceEmailClass.service_desk_thank_you_email(issue.id) }

    it_behaves_like 'read template from repository', 'thank_you'

    context 'handling template markdown' do
      context 'with a simple text' do
        let(:template_content) { 'thank you, **your new issue** has been created.' }
        let(:expected_body) { 'thank you, <strong>your new issue</strong> has been created.' }

        it_behaves_like 'handle template content', 'thank_you'
      end

      context 'with an issue id and issue path placeholders' do
        let(:template_content) { 'thank you, **your new issue:** %{ISSUE_ID}, path: %{ISSUE_PATH}' }
        let(:expected_body) { "thank you, <strong>your new issue:</strong> ##{issue.iid}, path: #{project.full_path}##{issue.iid}" }

        it_behaves_like 'handle template content', 'thank_you'
      end

      context 'with an issue id placeholder with whitespace' do
        let(:template_content) { 'thank you, **your new issue:** %{  ISSUE_ID}' }
        let(:expected_body) { "thank you, <strong>your new issue:</strong> ##{issue.iid}" }

        it_behaves_like 'handle template content', 'thank_you'
      end

      context 'with unexpected placeholder' do
        let(:template_content) { 'thank you, **your new issue:** %{this is issue}' }
        let(:expected_body) { "thank you, <strong>your new issue:</strong> %{this is issue}" }

        it_behaves_like 'handle template content', 'thank_you'
      end
    end
  end

  describe '.service_desk_new_note_email' do
    let_it_be(:reply_in_subject) { false }
    let_it_be(:note) { create(:note_on_issue, noteable: issue, project: project) }
    let_it_be(:default_text) { note.note }

    subject { ServiceEmailClass.service_desk_new_note_email(issue.id, note.id) }

    it_behaves_like 'read template from repository', 'new_note'

    context 'handling template markdown' do
      context 'with a simple text' do
        let(:template_content) { 'thank you, **new note on issue** has been created.' }
        let(:expected_body) { 'thank you, <strong>new note on issue</strong> has been created.' }

        it_behaves_like 'handle template content', 'new_note'
      end

      context 'with an issue id, issue path and note placeholders' do
        let(:template_content) { 'thank you, **new note on issue:** %{ISSUE_ID}, path: %{ISSUE_PATH}: %{NOTE_TEXT}' }
        let(:expected_body) { "thank you, <strong>new note on issue:</strong> ##{issue.iid}, path: #{project.full_path}##{issue.iid}: #{note.note}" }

        it_behaves_like 'handle template content', 'new_note'
      end

      context 'with an issue id placeholder with whitespace' do
        let(:template_content) { 'thank you, **new note on issue:** %{  ISSUE_ID}: %{ NOTE_TEXT  }' }
        let(:expected_body) { "thank you, <strong>new note on issue:</strong> ##{issue.iid}: #{note.note}" }

        it_behaves_like 'handle template content', 'new_note'
      end

      context 'with unexpected placeholder' do
        let(:template_content) { 'thank you, **new note on issue:** %{this is issue}' }
        let(:expected_body) { "thank you, <strong>new note on issue:</strong> %{this is issue}" }

        it_behaves_like 'handle template content', 'new_note'
      end
    end
  end
end
