# frozen_string_literal: true

module Gitlab
  module BackgroundMigration
    # Remove duplicated service records with the same project and type.
    # These were created in the past for unknown reasons, and should be blocked
    # now by the uniqueness validation in the Service model.
    class RemoveDuplicateServices
      # See app/models/service
      class Service < ActiveRecord::Base
        include EachBatch

        self.table_name = 'services'
        self.inheritance_column = :_type_disabled

        scope :project_ids_with_duplicates, -> do
          select(:project_id)
            .distinct
            .where.not(project_id: nil)
            .group(:project_id, :type)
            .having('count(*) > 1')
        end

        scope :types_with_duplicates, -> (project_ids) do
          select(:project_id, :type)
            .where(project_id: project_ids)
            .group(:project_id, :type)
            .having('count(*) > 1')
        end
      end

      def perform(*project_ids)
        types_with_duplicates = Service.types_with_duplicates(project_ids).pluck(:project_id, :type)

        types_with_duplicates.each do |project_id, type|
          remove_duplicates(project_id, type)
        end
      end

      private

      def remove_duplicates(project_id, type)
        scope = Service.where(project_id: project_id, type: type)

        # Build a subquery to determine which service record is actually in use,
        # by querying for it without specifying an order.
        #
        # This should match the record returned by `Project#find_service`,
        # and the `has_one` service associations on `Project`.
        correct_service = scope.select(:id).limit(1)

        # Delete all other services with the same `project_id` and `type`
        duplicate_services = scope.where.not(id: correct_service)
        duplicate_services.delete_all
      end
    end
  end
end