# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ReleaseTools::ReleaseEnvironment::Environment do
  subject(:environment) { described_class.new(version, suffix) }

  let(:version) { '16.11.0' }
  let(:suffix) { nil }
  let(:client) { stub_const('ReleaseTools::GitlabClient', spy) }
  let(:commit) { create(:commit, short_id: 'fddfe1c1') }

  let(:branch) do
    instance_double(
      ReleaseTools::Branch,
      last_commit: commit,
      version: ReleaseTools::Version.new('16.11')
    )
  end

  let(:project) do
    ReleaseTools::Project::Infrastructure::ReleaseEnvironment
  end

  let(:tree_entries) do
    Gitlab::PaginatedResponse.new(
      [
        create(:gitlab_response, name: '16-9-stable'),
        create(:gitlab_response, name: '16-10-stable')
      ]
    )
  end

  # Simplified environment model for testing
  let(:latest_environment_config) do
    <<~EOF
      ---
      install_type: helm
      cluster: release-gitlab-gke
      versions:
        chart: ~7.6.0-0
        registry: registry.gitlab.com/gitlab-org/build/cng-mirror
        components:
          gitaly: 16-10-stable-c23c8625
          registry: 16-10-stable-c23c8625
    EOF
  end

  let(:new_environment_config) do
    <<~EOF
      ---
      install_type: helm
      cluster: release-gitlab-gke
      versions:
        chart: "~7.6.0-0"
        registry: registry.gitlab.com/gitlab-org/build/cng-mirror
        components:
          gitaly: 16-11-stable-fddfe1c1
          registry: 16-11-stable-fddfe1c1
    EOF
  end

  before do
    allow(client)
      .to receive_messages(
        tree: tree_entries,
        file_contents: latest_environment_config
      )
  end

  describe '#create' do
    it 'creates a new release environment file' do
      allow(ReleaseTools::Branch).to receive(:new).and_return(branch)

      expect(client)
        .to receive(:create_file)
        .with(
          project,
          'environments/16-11-stable/environment.yaml',
          project.default_branch,
          new_environment_config,
          a_string_matching('Add new environment 16-11-stable')
        )

      without_dry_run do
        environment.create
      end
    end

    context 'when the environment already exists' do
      it 'does not create the new release environment file' do
        allow(ReleaseTools::Branch).to receive(:new).and_return(branch)

        tree_entries = Gitlab::PaginatedResponse.new(
          [create(:gitlab_response, name: '16-11-stable')]
        )

        allow(client)
          .to receive(:tree)
          .and_return(tree_entries)

        expect(client).not_to receive(:create_file)

        without_dry_run do
          environment.create
        end
      end
    end

    context 'when the environment belongs to an old version' do
      let(:version) { '15.10.0' }

      it 'uses the correct stable branch' do
        allow(ReleaseTools::Branch).to receive(:new).and_return(branch)

        expect(ReleaseTools::Branch)
          .to receive(:new)
          .with(name: '15-10-stable-ee', project: ReleaseTools::Project::GitlabEe)

        without_dry_run do
          environment.create
        end
      end
    end

    context 'when a patch version is used' do
      let(:version) { '16.8.1' }

      let(:new_environment_config) do
        <<~EOF
          ---
          install_type: helm
          cluster: release-gitlab-gke
          versions:
            chart: "~7.6.0-0"
            registry: registry.gitlab.com/gitlab-org/build/cng-mirror
            components:
              gitaly: 16-8-stable-fddfe1c1
              registry: 16-8-stable-fddfe1c1
        EOF
      end

      it 'creates the release environment' do
        allow(ReleaseTools::Branch).to receive(:new).and_return(branch)

        expect(client)
          .to receive(:create_file)
          .with(
            project,
            'environments/16-8-stable/environment.yaml',
            project.default_branch,
            new_environment_config,
            a_string_matching('Add new environment 16-8-stable')
          )

        without_dry_run do
          environment.create
        end
      end
    end

    context 'when multiple environments exist' do
      let(:version) { '17.0.0' }

      let(:tree_entries) do
        Gitlab::PaginatedResponse.new(
          [
            create(:gitlab_response, name: '16-1-stable'),
            create(:gitlab_response, name: '16-2-stable'),
            create(:gitlab_response, name: '16-9-stable'),
            create(:gitlab_response, name: '16-10-stable'),
            create(:gitlab_response, name: '16-11-stable')
          ]
        )
      end

      it 'uses the latest environment per version' do
        expect(client)
          .to receive(:file_contents)
          .with(
            project,
            'environments/16-11-stable/environment.yaml',
            project.default_branch
          )

        without_dry_run do
          environment.create
        end
      end
    end

    context 'without dry run do' do
      it 'does not create a new release environment file' do
        expect(client).not_to receive(:create_file)

        environment.create
      end
    end

    context 'when the suffix is security' do
      let(:suffix) { 'security' }
      let(:new_environment_config) do
        <<~EOF
          ---
          install_type: helm
          cluster: release-gitlab-gke
          versions:
            chart: "~7.6.0-0"
            registry: registry.gitlab.com/gitlab-org/security/charts/components/images
            components:
              gitaly: 16-11-stable-fddfe1c1
              registry: 16-11-stable-fddfe1c1
        EOF
      end

      it 'creates a security release environment' do
        allow(ReleaseTools::Branch).to receive(:new).and_return(branch)

        expect(client)
          .to receive(:create_file)
          .with(
            project,
            'environments/16-11-stable-security/environment.yaml',
            project.default_branch,
            new_environment_config,
            a_string_matching('Add new environment 16-11-stable')
          )

        without_dry_run do
          environment.create
        end
      end
    end
  end
end
