# frozen_string_literal: true

require 'spec_helper'

describe ReleaseTools::MonthlyIssue do
  let(:version) { ReleaseTools::Version.new('8.3.0') }
  let(:helm_version_finder) { instance_double(ReleaseTools::Helm::HelmVersionFinder, execute: '1.2.3') }

  before do
    allow(ReleaseTools::Helm::HelmVersionFinder)
     .to receive(:new)
     .and_return(helm_version_finder)
  end

  it_behaves_like 'issuable #initialize'

  subject(:issue) { described_class.new(version: version) }

  describe '#title' do
    let(:version) { ReleaseTools::Version.new('8.3.5-rc1') }

    it "returns the issue title" do
      expect(issue.title).to eq 'Release 8.3'
    end
  end

  describe '#description' do
    before do
      allow(ReleaseTools::Versions)
        .to receive(:current_stable_branch)
        .and_return('15-11-stable-ee')

      upcoming_releases = {
        '8.2' => '2023-04-22',
        '8.3' => '2023-05-24'
      }

      allow(ReleaseTools::GitlabReleasesGemClient)
       .to receive(:upcoming_releases)
       .and_return(upcoming_releases)
    end

    it "includes a section to tag the monthly release" do
      expect(issue.description).to include('Tag day')
    end

    it "includes the correct version" do
      content = issue.description

      expect(content).to include('8.3.0 is published and publicly available')
    end

    it 'returns Helm versions' do
      content = issue.description

      expect(content).to include 'https://dev.gitlab.org/gitlab/charts/gitlab/-/pipelines/?ref=v1.2.3'
    end
  end

  describe '#labels' do
    it 'returns a list of labels' do
      expect(issue.labels).to eq 'Monthly Release,team::Delivery'
    end
  end

  describe '#assignees' do
    let(:version) { ReleaseTools::Version.new('11.8') }

    it 'returns the assignee IDs' do
      schedule = instance_spy(ReleaseTools::ReleaseManagers::Schedule)

      allow(ReleaseTools::ReleaseManagers::Schedule)
        .to receive(:new)
        .and_return(schedule)

      expect(schedule)
        .to receive(:active_release_managers)
        .and_return([double('user1', id: 1), double('user2', id: 2)])

      expect(issue.assignees).to eq([1, 2])
    end
  end

  describe '#current_stable_branch' do
    let(:version) { ReleaseTools::Version.new('16.0') }

    it 'returns the current stable branch' do
      versions = [
        ReleaseTools::Version.new('15.11.1'),
        ReleaseTools::Version.new('15.10.9'),
        ReleaseTools::Version.new('15.9.8')
      ]

      allow(ReleaseTools::Versions)
        .to receive(:next_versions)
        .and_return(versions)

      expect(issue.current_stable_branch).to eq('15-11-stable-ee')
    end
  end

  describe "#create" do
    it 'creates a monthly release pipeline' do
      expect(issue).to receive(:release_pipeline).and_return(true)

      expect(ReleaseTools::GitlabClient).to receive(:create_issue)
        .with(issue, issue.project).and_return(true)

      issue.create
    end
  end

  describe '#release_pipeline' do
    let(:web_url) { "https://gitlab.example.com/pipelines/123" }
    let(:dry_run_url) { "https://example.com/foo/bar/-/pipelines/1" }

    it "creates a monthly release pipeline on the ops instance" do
      expect(ReleaseTools::GitlabOpsClient).to receive(:create_pipeline).with(
        ReleaseTools::Project::ReleaseTools,
        {
          MONTHLY_RELEASE_PIPELINE: 'true'
        }
      ).and_call_original

      expect(ReleaseTools::GitlabOpsClient.client).to receive(:create_pipeline).and_return(double(web_url: web_url))

      without_dry_run do
        expect(issue.release_pipeline.web_url).to eq(web_url)
      end
    end

    context 'in dry run mode' do
      it 'imitates the create_pipeline API response' do
        expect(ReleaseTools::GitlabOpsClient).not_to receive(:create_pipeline)

        expect(issue.release_pipeline.web_url).to eq(dry_run_url)
      end
    end
  end

  describe '#release_date' do
    it 'fetches the release date and returns a Date' do
      release_date = '2023-05-24'

      upcoming_releases = {
        '8.2' => '2023-04-22',
        '8.3' => release_date,
        '8.4' => '2023-06-18',
        '8.5' => '2023-07-21'
      }

      allow(ReleaseTools::GitlabReleasesGemClient)
       .to receive(:upcoming_releases)
       .and_return(upcoming_releases)

      expect(issue.release_date).to eq(Date.parse(release_date))
    end
  end

  describe '#formated_date' do
    it 'formats the date' do
      expect(issue.formated_date(Date.parse('2023-08-03'))).to eq('Thursday, 2023-08-03')
    end
  end

  context 'release day helpers' do
    before do
      allow(issue).to receive(:release_date).and_return(Date.parse('2023-08-17'))
    end

    describe '#ordinalized_release_date' do
      it 'returns the dynamic ordinalized day' do
        expect(issue.ordinalized_release_date).to eq('17th')
      end
    end

    describe '#release_day' do
      it 'returns the release day' do
        expect(issue.release_day).to eq('Thursday, 2023-08-17')
      end
    end

    describe '#tag_day' do
      it 'returns one day before the release day' do
        expect(issue.tag_day).to eq('Wednesday, 2023-08-16')
      end
    end

    describe '#rc_tag_day' do
      it 'returns two days before the release day' do
        expect(issue.rc_tag_day).to eq('Tuesday, 2023-08-15')
      end
    end

    describe '#candidate_selection_day' do
      it 'returns three days before the release day' do
        expect(issue.candidate_selection_day).to eq('Monday, 2023-08-14')
      end
    end

    describe '#preparation_start_day' do
      it 'returns the Friday before the release day' do
        expect(issue.preparation_start_day).to eq('Friday, 2023-08-11')
      end
    end
  end
end
