# frozen_string_literal: true

require 'spec_helper'

describe ReleaseTools::Metrics::PatchReleaseStatus do
  let(:delivery_metrics) { instance_double(ReleaseTools::Metrics::Client) }
  let(:gitlab_client) { stub_const('ReleaseTools::GitlabClient', spy) }

  describe '#execute' do
    before do
      allow(ReleaseTools::Metrics::Client)
        .to receive(:new)
        .and_return(delivery_metrics)
    end

    context 'when the feature flag is disabled' do
      subject(:release_status) { described_class.new(status: :open) }

      it 'does nothing' do
        expect(delivery_metrics).not_to receive(:set)

        release_status.execute
      end
    end

    context 'when creating a new metric for the patch release' do
      let(:next_patch_release_date) { "2024-02-15" }
      let(:current_minor_for_date) { "16.3" }
      let(:previous_minors) { ["16.2", "16.1", "16.0"] }

      before do
        allow(ReleaseTools::GitlabReleasesGemClient)
          .to receive_messages(
            current_minor_for_date: current_minor_for_date,
            next_patch_release_date: next_patch_release_date,
            previous_minors: previous_minors
          )

        allow(gitlab_client)
          .to receive(:present?)
          .and_return(false)

        enable_feature(:release_status_metric)
      end

      context 'when it is a dry run' do
        subject(:release_status) { described_class.new(status: :open) }

        it 'does nothing' do
          expect(delivery_metrics).not_to receive(:set)

          release_status.execute
        end
      end

      context 'when given an invalid status' do
        subject(:release_status) { described_class.new(status: :invalid) }

        it 'does nothing' do
          expect(delivery_metrics).not_to receive(:set)

          without_dry_run { release_status.execute }
        end
      end

      context 'when the status is open' do
        subject(:release_status) { described_class.new(status: :open) }

        it 'creates a status metric for the active version' do
          expect(delivery_metrics).to receive(:reset).with(described_class::METRIC)

          expect(delivery_metrics).to receive(:set)
            .with(described_class::METRIC, 1, { labels: "2024-02-15,16.2 16.1 16.0" })

          without_dry_run { release_status.execute }
        end
      end

      context 'when the status is warning' do
        subject(:release_status) { described_class.new(status: :warning) }

        let(:now) { Time.utc(2024, 4, 9, 0, 45) }
        let(:next_wednesday) { now.next_week(:wednesday).to_date }
        let(:wednesday_two_weeks_from_now) { next_wednesday.next_week(:wednesday).to_date }

        before do
          allow(ReleaseTools::GitlabReleasesGemClient)
           .to receive(:next_patch_release_date)
           .and_return(patch_release_date.to_s)
        end

        context 'when the next patch release date is not next week' do
          let(:patch_release_date) { wednesday_two_weeks_from_now }

          it 'does not set the value of the status metric' do
            expect(delivery_metrics).not_to receive(:set)

            Timecop.travel(now) do
              without_dry_run { release_status.execute }
            end
          end
        end

        context 'when the next patch release date is next week' do
          let(:patch_release_date) { next_wednesday }

          it 'sets the value of the status metric for the next patch release version to 2 (warning)' do
            expect(delivery_metrics).to receive(:reset).with(described_class::METRIC)

            expect(delivery_metrics).to receive(:set)
            .with(described_class::METRIC, 2, { labels: "#{next_wednesday},16.2 16.1 16.0" })

            Timecop.travel(now) do
              without_dry_run { release_status.execute }
            end
          end
        end
      end

      context 'when the status is closed' do
        subject(:release_status) { described_class.new(status: :closed) }

        it 'sets the value of the status metric for the next patch release version to 3 (closed)' do
          expect(delivery_metrics).to receive(:reset).with(described_class::METRIC)

          expect(delivery_metrics).to receive(:set)
           .with(described_class::METRIC, 3, { labels: "2024-02-15,16.2 16.1 16.0" })

          without_dry_run { release_status.execute }
        end
      end

      context 'when the security tracking issue is present' do
        subject(:release_status) { described_class.new(status: :closed) }

        let(:tracking_issue) { build(:issue, due_date: '2024-02-16') }

        before do
          allow(gitlab_client)
            .to receive(:next_security_tracking_issue)
            .and_return(tracking_issue)
        end

        it 'sets the release date label of the metric to the security tracking issue due date' do
          expect(delivery_metrics).to receive(:reset).with(described_class::METRIC)

          expect(delivery_metrics).to receive(:set)
            .with(described_class::METRIC, 3, { labels: "2024-02-16,16.2 16.1 16.0" })

          without_dry_run { release_status.execute }
        end
      end
    end
  end
end
