-- ROBLOX deviation: because of deviations in other functions, this function is
-- not needed. If we need to bring it, it should return true if Component is a
-- class component, and false if a function component
-- local function shouldConstruct(Component)
-- 	local prototype = Component.prototype
-- 	return not not (prototype and prototype.isReactComponent)
-- end

local function describeUnknownElementTypeFrameInDEV(
	type: any,
	source: nil | Source,
	-- ROBLOX deviation: owner could be a class component
	ownerFn: nil | ReactComponent<any>
): string
	if not _G.__DEV__ then
		return ""
	end
	if type == nil then
		return ""
	end

	-- ROBLOX deviation: in JavaScript, if `type` contains a class, typeof will
	-- return "function". We need to specifically check for the class.
	if typeof(type) == "table" and typeof(type.__ctor) == "function" then
		-- ROBLOX deviation: since Roact class components are tables, we can't
		-- count on describeClassComponent being a thin wrapper for
		-- describeFunctionComponent like upstream does implicitly
		return describeClassComponentFrame(type, source, ownerFn)
	end

	if typeof(type) == "function" then
		-- ROBLOX DEVIATION: ignore enableComponentStackLocations
		-- if enableComponentStackLocations then
		-- 	-- ROBLOX deviation: since functions and classes have different
		-- 	-- types in Lua, we already know that shouldConstruct would return
		-- 	-- false
		-- 	return describeNativeComponentFrame(type, false)
		-- else
		-- 	return describeFunctionComponentFrame(type, source, ownerFn)
		-- end
		return describeFunctionComponentFrame(type, source, ownerFn)
	end

	if typeof(type) == "string" then
		return describeBuiltInComponentFrame(type, source, ownerFn)
	end

	if type == REACT_SUSPENSE_TYPE then
		return describeBuiltInComponentFrame("Suspense", source, ownerFn)
	elseif type == REACT_SUSPENSE_LIST_TYPE then
		return describeBuiltInComponentFrame("SuspenseList", source, ownerFn)
	end

	if typeof(type) == "table" then
		local typeProp = type["$$typeof"]
		if typeProp == REACT_FORWARD_REF_TYPE then
			return describeFunctionComponentFrame(type.render, source, ownerFn)
		elseif typeProp == REACT_MEMO_TYPE then
			-- // Memo may contain any component type so we recursively resolve it.
			return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn)
		elseif typeProp == REACT_BLOCK_TYPE then
			return describeFunctionComponentFrame(type._render, source, ownerFn)
		elseif typeProp == REACT_LAZY_TYPE then
			local lazyComponent = type
			local payload = lazyComponent._payload
			local init = lazyComponent._init

			local ok, result = pcall(function()
				describeUnknownElementTypeFrameInDEV(
					-- // Lazy may contain any component type so we recursively resolve it.
					init(payload),
					source,
					ownerFn
				)
			end)

			if ok then
				return result
			end
		end
	end

	return ""
end

return {
	-- deviation: ReactShallowRenderer depends on this, but the upstream `react`
	-- repo doesn't expose it; instead, the shallow-renderer's copies of shared
	-- modules do so. Since we opted to reuse the shared modules in this repo
	-- instead of duplicating, we need to have them include this field
	describeComponentFrame = describeComponentFrame,

	describeBuiltInComponentFrame = describeBuiltInComponentFrame,
	describeNativeComponentFrame = describeNativeComponentFrame,
	describeClassComponentFrame = describeClassComponentFrame,
	describeFunctionComponentFrame = describeFunctionComponentFrame,
	describeUnknownElementTypeFrameInDEV = describeUnknownElementTypeFrameInDEV,
}