# frozen_string_literal: true

module Gitlab
  module Database
    module AsyncIndexes
      class IndexCreator
        include ExclusiveLeaseGuard

        TIMEOUT_PER_ACTION = 1.day
        STATEMENT_TIMEOUT = 9.hours

        def initialize(async_index)
          @async_index = async_index
        end

        def perform
          try_obtain_lease do
            if index_exists?
              log_index_info('Skipping index creation as the index exists')
            else
              log_index_info('Creating async index')

              set_statement_timeout do
                connection.execute(async_index.definition)
              end

              log_index_info('Finished creating async index')
            end

            async_index.destroy
          end
        end

        private

        attr_reader :async_index

        def index_exists?
          connection.indexes(async_index.table_name).any? { |index| index.name == async_index.name }
        end

        def connection
          @connection ||= async_index.connection
        end

        def lease_timeout
          TIMEOUT_PER_ACTION
        end

        def set_statement_timeout
          connection.execute("SET statement_timeout TO '%ds'" % STATEMENT_TIMEOUT)
          yield
        ensure
          connection.execute('RESET statement_timeout')
        end

        def log_index_info(message)
          Gitlab::AppLogger.info(message: message, table_name: async_index.table_name, index_name: async_index.name)
        end
      end
    end
  end
end
