-- /**
--  * Handles more complex objects ( such as objects with circular references.
--  * maps and sets etc )
--  */

local function printComplexValue(
	val: any,
	config: Config,
	indentation: string,
	depth: number,
	refs: Refs,
	hasCalledToJSON: boolean?
): string
	if table.find(refs, val) ~= nil then
		return "[Circular]"
	end
	refs = { unpack(refs) }
	table.insert(refs, val)

	depth = depth + 1
	local hitMaxDepth = depth > config.maxDepth
	local min = config.min

	if
		config.callToJSON
		and not hitMaxDepth
		and val.toJSON
		and typeof(val.toJSON) == "function"
		and not hasCalledToJSON
	then
		return printer(val.toJSON(), config, indentation, depth, refs, true)
	end

	-- ROBLOX deviation start: rewrote this part since lua only has tables
	if hitMaxDepth then
		if getType(val) == "set" then
			return "[Set]"
		else
			return "[Table]"
		end
	end
	local retval = ""
	if not min then
		retval = if config.printBasicPrototype then "Table" .. " " else ""
	end

	if is_array(val) then
		return retval .. "{" .. printListItems(val, config, indentation, depth, refs, printer) .. "}"
	end

	if getType(val) == "set" then
		if hitMaxDepth then
			return "[Set]"
		else
			return "Set {" .. printListItems(val._array, config, indentation, depth, refs, printer) .. "}"
		end
	end

	return retval .. "{" .. printTableEntries(val, config, indentation, depth, refs, printer) .. "}"
	-- ROBLOX deviation end
end

local function isNewPlugin(plugin_: Plugin): boolean
	return (plugin_ :: NewPlugin).serialize ~= nil
end

function printPlugin(plugin_: Plugin, val: any, config: Config, indentation: string, depth: number, refs: Refs): string
	local printed

	local ok, err = pcall(function()
		if isNewPlugin(plugin_) then
			printed = (plugin_ :: NewPlugin).serialize(val, config, indentation, depth, refs, printer)
		else
			printed = (plugin_ :: OldPlugin).print(val, function(valChild)
				return printer(valChild, config, indentation, depth, refs)
			end, function(str)
				local indentationNext = indentation .. config.indent
				return indentationNext .. str:gsub("\n", "\n" .. indentationNext)
			end, {
				edgeSpacing = config.spacingOuter,
				min = config.min,
				spacing = config.spacingInner,
			}, config.colors)
		end
	end)
	if not ok then
		error(PrettyFormatPluginError(err))
	end

	if typeof(printed) ~= "string" then
		error(
			Error(
				string.format(
					'pretty-format: Plugin must return type "string" but instead returned "%s".',
					typeof(printed)
				)
			)
		)
	end
	return printed
end
