# frozen_string_literal: true

RSpec.configure do |config|
  config.around(:each, :disable_foreign_keys => lambda { |v| !!v }) do |example|
    config.rspeckled_logger.debug("Around Each  - Start - #{__FILE__}")

    options = example.metadata[:disable_foreign_keys]
    options = case options
              when ::Array
                { :tables => options.map(&:to_s) }
              when ::String, ::Symbol
                { :tables => [options.to_s] }
              when ::FalseClass
                { :tables => [] }
              when ::TrueClass
                { :tables => :all }
              end

    foreign_key_names_sql = <<~HEREDOC
      SELECT
        "constraint_column_usage"."constraint_name",
        "pg_class"."relname"                          AS "local_table_name",
        "constraint_column_usage"."table_name"        AS "foreign_table_name",
        "constraint_column_usage"."column_name"       AS "foreign_column_name"
      FROM
        "information_schema"."constraint_column_usage"
        INNER JOIN
        "pg_constraint"
          ON
            "constraint_column_usage"."constraint_name" = "pg_constraint"."conname"
        INNER JOIN
        "pg_class"
          ON
            "pg_class"."oid" = "pg_constraint"."conrelid"
      WHERE
        "pg_constraint"."contype" = 'f'
        AND
        "pg_constraint"."condeferrable" = 't'
    HEREDOC

    unless options[:tables] == :all
      foreign_key_names_sql += 'AND ('

      table_constraint_sql = options[:tables].map do |table_name|
        %Q{"pg_class"."relname" = '#{table_name}'}
      end

      foreign_key_names_sql += table_constraint_sql.join(' OR ')

      foreign_key_names_sql += ')'
    end

    foreign_keys_to_disable = ::ActiveRecord::Base.connection.select_values(foreign_key_names_sql).join(',')

    if foreign_keys_to_disable.blank?
      puts 'You asked to disable foreign keys but there were no foreign keys found to disable'
    else
      ::ActiveRecord::Base.connection.execute('SET CONSTRAINTS %<key_pattern>s DEFERRED' % { :key_pattern => foreign_keys_to_disable }) unless foreign_keys_to_disable.empty?
    end

    example.run

    # Remember we don't have to re-enable foreign keys because database cleaner
    # will do that for us when it rolls back the transaction

    config.rspeckled_logger.debug("Around Each  - End   - #{__FILE__}")
  end
end