# frozen_string_literal: true

require 'spec_helper'

describe ReleaseTools::Promotion::Manager do
  let(:deploy_package) { '13.1.202005220540-7c84ccdc806.59f00bb0515' }
  let(:package_version) { ReleaseTools::Version.new(deploy_package) }
  let(:version) { ReleaseTools::Version.new('13.1.0') }
  let(:status) { instance_double(ReleaseTools::Promotion::ProductionStatus, fine?: true) }

  subject(:manager) do
    described_class.new
  end

  before do
    allow(ReleaseTools::ReleaseManagers::Schedule)
      .to receive(:new)
      .and_return(instance_double(ReleaseTools::ReleaseManagers::Schedule, version_for_date: version))

    allow(manager).to receive(:status).and_return(status)
  end

  describe '#authorize!' do
    let(:fake_client) { spy("ReleaseTools::GitlabClient") }
    let(:issue) { instance_double(ReleaseTools::MonthlyIssue, project: ReleaseTools::Project::Release::Tasks) }

    before do
      stub_const("ReleaseTools::GitlabClient", fake_client)
    end

    it 'updates the issue' do
      expect(ReleaseTools::Promotion::StatusNote).to receive(:new)
        .with(
          {
            status: status,
            package_version: package_version,
            override_reason: 'false'
          }
        ).and_return(double('note', body: 'a comment'))

      without_dry_run do
        manager.authorize!(package_version, issue)
      end

      expect(fake_client)
        .to have_received(:create_issue_note)
        .with(
          ReleaseTools::Project::Release::Tasks,
          {
            issue: issue,
            body: 'a comment'
          }
        )
    end

    it 'raises an exception if the system is not fine' do
      expect(status).to receive(:fine?).and_return(false)
      expect(manager).to receive(:create_issue_comment)

      without_dry_run do
        expect { manager.authorize!(package_version, issue) }.to raise_error(ReleaseTools::Promotion::Manager::UnsafeProductionError)
      end
    end

    context 'when IGNORE_PRODUCTION_CHECKS is set' do
      it 'updates the issue with the reason why it was overridden' do
        ignore_production_checks = 'a reason to ignore checks'

        expect(ReleaseTools::Promotion::StatusNote).to receive(:new)
          .with(
            {
              status: status,
              package_version: package_version,
              override_reason: ignore_production_checks
            }
          ).and_return(double('note', body: 'a comment'))

        ClimateControl.modify(
          IGNORE_PRODUCTION_CHECKS: ignore_production_checks
        ) do
          without_dry_run do
            manager.authorize!(package_version, issue)
          end
        end

        expect(fake_client)
          .to have_received(:create_issue_note)
          .with(
            ReleaseTools::Project::Release::Tasks,
            {
              issue: issue,
              body: 'a comment'
            }
          )
      end

      it 'unescapes the ignore reason' do
        expect(ReleaseTools::Promotion::StatusNote).to receive(:new)
          .with(
            {
              status: status,
              package_version: package_version,
              override_reason: 'foo,bar'
            }
          ).and_return(double('note', body: 'a comment'))

        ClimateControl.modify(
          IGNORE_PRODUCTION_CHECKS: CGI.escape('foo,bar')
        ) do
          without_dry_run do
            manager.authorize!(package_version, issue)
          end
        end

        expect(fake_client)
          .to have_received(:create_issue_note)
          .with(
            ReleaseTools::Project::Release::Tasks,
            {
              issue: issue,
              body: 'a comment'
            }
          )
      end

      it "doesn't raise an exception if the system is not fine" do
        ignore_production_checks = 'a reason to ignore checks'

        expect(manager).to receive(:create_issue_comment)

        ClimateControl.modify(IGNORE_PRODUCTION_CHECKS: ignore_production_checks) do
          without_dry_run do
            expect { manager.authorize!(package_version, issue) }.not_to raise_error
          end
        end
      end
    end
  end
end
