# frozen_string_literal: true

require 'support/using_hash'
require 'runners/unified/error'
require 'runners/unified/entity_map'
require 'runners/unified/event_subscriber'
require 'runners/unified/test'
require 'runners/unified/test_group'

def define_unified_spec_tests(base_path, paths, expect_failure: false)
  config_override :validate_update_replace, true

  paths.each do |path|
    basename = path[(base_path.length + 1)...path.length]
    context basename do
      group = Unified::TestGroup.new(path)

      group.tests.each do |test|
        context test.description do
          if test.skip?
            before do
              skip test.skip_reason
            end
          end

          before(:all) do
            if SpecConfig.instance.retry_reads == false
              skip 'Tests are not applicable when legacy read retries are used'
            end
            if SpecConfig.instance.retry_writes == false
              skip 'Tests are not applicable when legacy write retries are used'
            end

            if ClusterConfig.instance.topology == :sharded
              if test.require_multiple_mongoses? && SpecConfig.instance.addresses.length == 1
                skip 'Test requires multiple mongoses'
              elsif test.require_single_mongos? && SpecConfig.instance.addresses.length > 1
                # Many transaction spec tests that do not specifically deal with
                # sharded transactions fail when run against a multi-mongos cluster
                skip 'Test requires single mongos'
              end
            end
          end

          retry_test tries: 3 if test.retry?
          if expect_failure
            it 'fails as expected' do
              skip 'Group requirements not satisfied' if test.group_reqs && !test.group_reqs.any? { |r| r.satisfied? }
              skip 'Requirements not satisfied' if test.reqs && !test.reqs.any? { |r| r.satisfied? }
              begin
                test.create_spec_entities
                test.set_initial_data
                begin
                  test.run
                  test.assert_outcome
                  test.assert_events
                # HACK: other errors are possible and likely will need to
                # be added here later as the tests evolve.
                rescue Mongo::Error::OperationFailure::Family, Unified::Error::UnsupportedOperation,
                       UsingHash::UsingHashKeyError, Unified::Error::EntityMissing
                rescue StandardError => e
                  raise "Expected to raise Mongo::Error::OperationFailure or Unified::Error::UnsupportedOperation or UsingHash::UsingHashKeyError or Unified::Error::EntityMissing, got #{e.class}: #{e}"
                else
                  raise 'Expected to raise Mongo::Error::OperationFailure or Unified::Error::UnsupportedOperation or UsingHash::UsingHashKeyError or Unified::Error::EntityMissing, but no error was raised'
                end
              ensure
                test.cleanup
              end
            end
          else
            it 'passes' do
              skip 'Group requirements not satisfied' if test.group_reqs && !test.group_reqs.any? { |r| r.satisfied? }
              skip 'Requirements not satisfied' if test.reqs && !test.reqs.any? { |r| r.satisfied? }
              test.create_spec_entities
              test.set_initial_data
              test.run
              test.assert_outcome
              test.assert_events
              test.assert_tracing_messages
            ensure
              test.cleanup
            end
          end
        end
      end
    end
  end
end
