# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ReleaseTools::InternalRelease::Issue do
  subject(:issue) { described_class.new(iteration: iteration) }

  let(:iteration) { 0 }

  let(:versions) do
    [
      ReleaseTools::Version.new('15.2.1-internal0'),
      ReleaseTools::Version.new('15.1.2-internal0')
    ]
  end

  let(:internal_release_coordinator) do
    instance_double(ReleaseTools::InternalRelease::Coordinator, versions: versions)
  end

  before do
    allow(ReleaseTools::InternalRelease::Coordinator)
      .to receive(:new)
      .with(iteration)
      .and_return(internal_release_coordinator)
  end

  it_behaves_like 'issuable #initialize'

  describe '#initialize' do
    let(:iteration) { nil }

    it 'sets internal_number to 0 when input is nil' do
      expect(issue.send(:internal_number)).to eq(0)
    end
  end

  describe '#create' do
    it 'creates an internal release pipeline and issue' do
      expect(issue).to receive(:release_pipeline)
      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" }
    let(:pipeline) { build(:pipeline, web_url: web_url) }

    it "with no version specified it includes INTERNAL_VERSIONS variable with all the Coordinator versions" do
      expect(ReleaseTools::GitlabOpsClient).to receive(:create_pipeline).with(
        ReleaseTools::Project::ReleaseTools,
        {
          INTERNAL_RELEASE_PIPELINE: 'true',
          INTERNAL_VERSIONS: '15.2.1-internal0 15.1.2-internal0'
        }
      ).and_return(pipeline)

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

    context 'with version specified' do
      subject(:issue) do
        described_class.new(
          iteration: iteration,
          version: ReleaseTools::Version.new('15.2.6')
        )
      end

      it "includes INTERNAL_VERSIONS variable with the internal version" do
        expect(ReleaseTools::GitlabOpsClient).to receive(:create_pipeline).with(
          ReleaseTools::Project::ReleaseTools,
          {
            INTERNAL_RELEASE_PIPELINE: 'true',
            INTERNAL_VERSIONS: '15.2.6-internal0'
          }
        ).and_return(pipeline)

        without_dry_run do
          expect(issue.release_pipeline.web_url).to eq(web_url)
        end
      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 '#title' do
    it 'returns the issue title' do
      expect(issue.title).to eq('Internal Release: 15.2.1-internal0, 15.1.2-internal0')
    end

    context 'with version specified' do
      subject(:issue) { described_class.new(iteration: iteration, version: ReleaseTools::Version.new('15.2.6')) }

      it 'returns a title with the internal version' do
        expect(issue.title).to eq('Internal Release: 15.2.6-internal0')
      end
    end
  end

  describe '#confidential?' do
    it 'is always confidential' do
      expect(issue).to be_confidential
    end
  end

  describe '#labels' do
    it 'returns internal releases label' do
      expect(issue.labels).to eq('internal releases')
    end
  end

  describe '#project' do
    it 'returns Release::Tasks project' do
      expect(issue.project).to eq(ReleaseTools::Project::Release::Tasks)
    end
  end

  describe '#versions' do
    context 'with default 0 iteration' do
      it 'returns versions with internal0 suffix' do
        expect(issue.versions).to eq(versions)
      end
    end

    context 'when iteration is a positive integer' do
      let(:iteration) { 1 }

      it 'returns versions with correct internal suffix' do
        expect(issue.versions).to eq(versions)
      end
    end

    context 'with version specified' do
      subject(:issue) { described_class.new(iteration: iteration, version: ReleaseTools::Version.new('15.2.6')) }

      it 'returns only the specified version with internal suffix' do
        expect(issue.versions).to eq([ReleaseTools::Version.new('15.2.6-internal0')])
      end
    end
  end

  describe '#regular_versions' do
    context 'with default 0 iteration' do
      it 'returns comma-separated regular versions' do
        expect(issue.regular_versions).to eq('15.2, 15.1')
      end
    end

    context 'with version specified' do
      subject(:issue) { described_class.new(iteration: iteration, version: ReleaseTools::Version.new('15.2.6')) }

      it 'returns the specified version' do
        expect(issue.regular_versions).to eq('15.2')
      end
    end
  end

  describe '#assignees' do
    let(:schedule) do
      instance_double(
        ReleaseTools::ReleaseManagers::Schedule,
        active_release_managers: [build(:user, id: 1), build(:user, id: 2)]
      )
    end

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

    it 'returns the current RM user IDs' do
      expect(issue.assignees).to eq([1, 2])
    end

    context 'when VersionNotFoundError is raised' do
      before do
        allow(schedule)
          .to receive(:active_release_managers)
          .and_raise(ReleaseTools::ReleaseManagers::Schedule::VersionNotFoundError)
      end

      it 'returns nil' do
        expect(issue.assignees).to be_nil
      end
    end
  end

  describe '#description' do
    let(:tracking_issue) { build(:issue, web_url: 'http://example.com') }

    before do
      allow(issue)
        .to receive(:security_tracking_issue)
        .and_return(build(:issue))
    end

    it 'includes renders the internal template' do
      content = issue.description

      expect(content).to include 'Internal package preparation'
    end
  end
end
