require "minitest/assertions"

module DataModel
	# Provides assertions for minitest
	module Testing::Minitest
		include Minitest::Assertions

		# Assert that a child model error was found.
		# @param err [Error] the error to check
		# @param type [Symbol] the type of error to check for
		# @param key [Array(Symbol)] limit checking to a specific child key
		# @return [void]
		def assert_child_model_error(err, type, key = nil)
			refute_nil(err)

			assert(err.children.any?, "validate was successful, but should not have been")

			for k in key ? [key] : err.children.keys
				found = err.children[k]&.any? { |(t, _ctx)| t == type }
				assert(found, "validation was not successful, but #{type} error was not found #{err.inspect}")
			end
		end

		# Assert that a model error was found.
		# @param err [Error] the error to check
		# @param type [Symbol] the type of error to check for
		# @return [void]
		def assert_model_error(err, type)
			refute_nil err

			assert(err.base.any?, "validate was successful, but should not have been")

			found = err.base.any? { |(t, _ctx)| t == type }

			assert(found, "validation was not successful, but #{type} error was not found #{err.inspect}")
		end

		# Assert that no child error is found
		# @param err [Error] the error to check
		# @param type [Symbol] the type of error to check for
		# @param key [Symbol, Array<Symbol>] limit checking to a specific child key
		# @return [void]
		def refute_child_model_error(err, type = nil, key = nil)
			refute_nil(err)

			if !err.any?
				return
			end

			if type.nil?
				refute(err.base.any?, "validation was not successful #{err.inspect}")
				return
			end

			for k in key ? [key] : err.children.keys
				found = err.children[k]&.any? { |(t, _ctx)| t == type }
				refute(found, "validation was not successful, but #{type} error was not found #{err.inspect}")
			end
		end

		# Assert that no base error is present
		# @param err [Error] the error to check
		# @param type [Symbol] the type of error to check for
		# @return [void]
		def refute_model_error(err, type = nil)
			refute_nil(err)

			if !err.any?
				return
			end

			if type.nil?
				refute(err.base.any?, "validation was not successful #{err.inspect}")
				return
			end

			found = err.base.any? { |(t, _ctx)| t == type }

			refute(found, "#{type} error was found #{err.inspect}")
		end

		# Assert that no errors are present
		# @param err [Error] the error to check
		# @param type [Symbol] the type of error to check for
		# @return [void]
		def refute_all_errors(err, type = nil)
			refute_nil(err)

			if !err.any?
				return
			end

			if type.nil?
				refute(err.all.any?, "validation was not successful #{err.inspect}")
				return
			end

			found = err.all.any? { |(t, _ctx)| t == type }

			refute(found, "#{type} error was found #{err.inspect}")
		end
	end
end