# frozen_string_literal: true

require 'spec_helper'

RSpec.describe SlackIntegration, feature_category: :integrations do
  let_it_be(:integration) { create(:slack_integration) }

  describe "Associations" do
    it { is_expected.to belong_to(:integration) }
  end

  describe 'constant' do
    it 'is expected that DEFAULT_ALIAS is defined with the correct value' do
      expect(SlackIntegration::INSTANCE_ALIAS).to eq('_gitlab-instance')
    end
  end

  describe 'authorized_scope_names' do
    subject(:slack_integration) { integration }

    it 'accepts assignment to nil' do
      slack_integration.update!(authorized_scope_names: nil)

      expect(slack_integration.authorized_scope_names).to be_empty
    end

    it 'accepts assignment to a string' do
      slack_integration.update!(authorized_scope_names: 'foo')

      expect(slack_integration.authorized_scope_names).to contain_exactly('foo')
    end

    it 'accepts assignment to an array of strings' do
      slack_integration.update!(authorized_scope_names: %w[foo bar])

      expect(slack_integration.authorized_scope_names).to contain_exactly('foo', 'bar')
    end

    it 'accepts assignment to a comma-separated string' do
      slack_integration.update!(authorized_scope_names: 'foo,bar')

      expect(slack_integration.authorized_scope_names).to contain_exactly('foo', 'bar')
    end

    it 'strips white-space' do
      slack_integration.update!(authorized_scope_names: 'foo , bar,baz')

      expect(slack_integration.authorized_scope_names).to contain_exactly('foo', 'bar', 'baz')
    end
  end

  describe 'all_features_supported?/upgrade_needed?' do
    subject(:slack_integration) { integration }

    context 'with enough scopes' do
      before do
        slack_integration.update!(authorized_scope_names: %w[chat:write.public chat:write commands])
      end

      it { is_expected.to be_all_features_supported }
      it { is_expected.not_to be_upgrade_needed }
    end

    %w[chat:write.public chat:write].each do |scope_name|
      context "without #{scope_name}" do
        before do
          scopes = %w[chat:write.public chat:write] - [scope_name]
          slack_integration.update!(authorized_scope_names: scopes)
        end

        it { is_expected.not_to be_all_features_supported }
        it { is_expected.to be_upgrade_needed }
      end
    end
  end

  describe 'feature_available?' do
    subject(:slack_integration) { integration }

    context 'without any scopes' do
      it 'is always true for :commands' do
        expect(slack_integration).to be_feature_available(:commands)
      end

      it 'is always false for others' do
        expect(slack_integration).not_to be_feature_available(:notifications)
        expect(slack_integration).not_to be_feature_available(:foo)
      end
    end

    context 'with enough scopes for notifications' do
      before do
        slack_integration.update!(authorized_scope_names: %w[chat:write.public chat:write foo])
      end

      it 'only has the correct features' do
        expect(slack_integration).to be_feature_available(:commands)
        expect(slack_integration).to be_feature_available(:notifications)
        expect(slack_integration).not_to be_feature_available(:foo)
      end
    end

    context 'with enough scopes for commands' do
      before do
        slack_integration.update!(authorized_scope_names: %w[commands foo])
      end

      it 'only has the correct features' do
        expect(slack_integration).to be_feature_available(:commands)
        expect(slack_integration).not_to be_feature_available(:notifications)
        expect(slack_integration).not_to be_feature_available(:foo)
      end
    end

    context 'with all scopes' do
      before do
        slack_integration.update!(authorized_scope_names: %w[commands chat:write chat:write.public])
      end

      it 'only has the correct features' do
        expect(slack_integration).to be_feature_available(:commands)
        expect(slack_integration).to be_feature_available(:notifications)
        expect(slack_integration).not_to be_feature_available(:foo)
      end
    end
  end

  describe '#to_database_hash' do
    subject(:slack_integration) { integration }

    it 'includes the correct attributes' do
      expect(slack_integration.to_database_hash.keys).to contain_exactly(*described_class::DATABASE_ATTRIBUTES)
    end
  end

  it 'toggles the integration to active when created' do
    integration = create(:gitlab_slack_application_integration, active: false, slack_integration: nil)

    expect { create(:slack_integration, integration: integration) }.to change { integration.reload.active }.to(true)
  end

  it 'toggles the integration to inactive when destroyed' do
    integration = create(:gitlab_slack_application_integration)

    expect { integration.slack_integration.destroy! }.to change { integration.reload.active }.to(false)
  end

  describe 'Scopes' do
    let_it_be(:slack_integration) { integration }
    let_it_be(:legacy_slack_integration) { create(:slack_integration, :legacy) }

    describe '#with_bot' do
      it 'returns records with bot data' do
        expect(described_class.with_bot).to contain_exactly(slack_integration)
      end
    end

    describe '#by_team' do
      it 'returns records with shared team_id' do
        team_id = slack_integration.team_id
        team_slack_integration = create(:slack_integration, team_id: team_id)

        expect(described_class.by_team(team_id)).to contain_exactly(slack_integration, team_slack_integration)
      end
    end

    describe '#by_integration' do
      it 'returns records by the integration' do
        integration = legacy_slack_integration.integration

        expect(described_class.by_integration(integration)).to contain_exactly(legacy_slack_integration)
      end
    end
  end

  describe 'Validations' do
    it { is_expected.to validate_presence_of(:team_id) }
    it { is_expected.to validate_presence_of(:team_name) }
    it { is_expected.to validate_presence_of(:alias) }
    it { is_expected.to validate_presence_of(:user_id) }
    it { is_expected.to validate_presence_of(:integration) }
  end
end
