# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::BackgroundMigration::RemoveOrphanedVulnerabilityNotesBatchedMigration, feature_category: :vulnerability_management do
  let(:migration) do
    described_class.new(
      batch_table: 'notes',
      batch_column: 'id',
      sub_batch_size: 100,
      pause_ms: 100,
      connection: ActiveRecord::Base.connection
    )
  end

  let(:user_id) do
    table(:users).create!(email: 'author@example.com', notification_email: 'author@example.com', name: 'Author',
      username: 'author', projects_limit: 1000, organization_id: organization_id).id
  end

  let(:organization_id) do
    table(:organizations).create!(
      name: 'Organization',
      path: 'organization').id
  end

  let(:namespace_id) do
    table(:namespaces).create!(
      name: 'Namespace',
      path: 'namespace',
      organization_id: organization_id).id
  end

  let(:project_namespace_id) do
    table(:namespaces).create!(
      name: 'Project Namespace',
      path: 'project-namespace',
      organization_id: organization_id).id
  end

  let(:project_id) do
    table(:projects).create!(
      name: 'Project',
      path: 'project',
      namespace_id: namespace_id,
      organization_id: organization_id,
      project_namespace_id: project_namespace_id
    ).id
  end

  let(:note_attributes) do
    {
      author_id: user_id,
      project_id: project_id,
      namespace_id: namespace_id,
      created_at: Time.current,
      updated_at: Time.current
    }
  end

  before do
    allow(Vulnerability).to receive_message_chain(:where, :pluck).and_return([1, 2, 3])
  end

  def create_note(noteable_id:, noteable_type:)
    table(:notes).create!(
      note: 'Note Content',
      noteable_type: noteable_type,
      noteable_id: noteable_id,
      **note_attributes
    )
  end

  describe 'orphaned notes removal' do
    # These notes are created before the test runs
    let!(:invalid_note_1) { create_note(noteable_id: 4, noteable_type: 'Vulnerability') }

    let!(:invalid_note_2) { create_note(noteable_id: 28, noteable_type: 'Vulnerability') }

    it 'removes orphaned Vulnerability notes' do
      expect { migration.perform }.to change { table(:notes).count }.by(-2)
      expect(table(:notes).find_by(id: invalid_note_1.id)).to be_blank
      expect(table(:notes).find_by(id: invalid_note_2.id)).to be_blank
    end
  end

  describe 'valid notes retention' do
    let!(:valid_note) { create_note(noteable_id: 1, noteable_type: 'Vulnerability') }

    it 'retains valid Vulnerability notes' do
      expect { migration.perform }.not_to change { table(:notes).count }
      expect(table(:notes).find_by(id: valid_note.id)).to be_present
    end
  end

  describe 'non-vulnerability notes' do
    let!(:issue_note_nil_id) { create_note(noteable_id: nil, noteable_type: 'Issue') }

    let!(:issue_note_with_id) { create_note(noteable_id: 2, noteable_type: 'Issue') }

    it 'does not remove non-Vulnerability notes' do
      expect { migration.perform }.not_to change { table(:notes).count }
      expect(table(:notes).find_by(id: issue_note_nil_id.id)).to be_present
      expect(table(:notes).find_by(id: issue_note_with_id.id)).to be_present
    end
  end
end
