-- ROBLOX deviation: Lua's patterns work slightly differently than regexes

local BEFORE_SLASH_PATTERN = "^(.*)[\\/]"

function describeComponentFrame(
	name: string | nil,
	source: Source | nil,
	ownerName: string | nil
): string
	local sourceInfo = ""

	if _G.__DEV__ and source then
		local path = source.fileName
		local fileName = string.gsub(path, BEFORE_SLASH_PATTERN, "")

		-- // In DEV, include code for a common special case:
		-- // prefer "folder/index.js" instead of just "index.js".
		-- ROBLOX deviation: instead of having a special case for 'index.',
		-- we use 'init.'
		if string.match(fileName, "^init%.") then
			-- deviation: finding matching strings works differently in Lua
			local pathBeforeSlash = string.match(path, BEFORE_SLASH_PATTERN)

			if pathBeforeSlash and #pathBeforeSlash ~= 0 then
				local folderName = string.gsub(pathBeforeSlash, BEFORE_SLASH_PATTERN, "")
				fileName = folderName .. "/" .. fileName
			end
		end

		sourceInfo = " (at " .. fileName .. ":" .. source.lineNumber .. ")"
	elseif ownerName then
		sourceInfo = " (created by " .. ownerName .. ")"
	end

	return "\n    in " .. (name or "Unknown") .. sourceInfo
end

local function describeClassComponentFrame(
	-- ROBLOX deviation: React.Component<any>
	ctor: any,
	source: nil | Source,
	-- ROBLOX deviation: this could be a class component OR a function component
	owner: nil | ReactComponent<any>
): string
	-- ROBLOX deviation START: In Roact, class components are tables, so we
	-- jump directly to using the basic component description.

	-- if enableComponentStackLocations then
	-- 	return describeNativeComponentFrame(componentClass, true)
	-- else
	-- 	return describeFunctionComponentFrame(ctor, source, ownerFn);
	-- end
	local name = tostring(ctor)
	local ownerName = nil
	if _G.__DEV__ and owner then
		ownerName = describeOwner(owner)
	end
	return describeComponentFrame(name, source, ownerName)
	-- ROBLOX deviation END
end

function describeFunctionComponentFrame(
	-- ROBLOX TODO: this annotation is incorrect upstream, we fix it here
	fn: nil | Function,
	source: nil | Source,
	-- ROBLOX deviation: this could be a class component OR a function component
	ownerFn: nil | ReactComponent<any>
): string
	-- ROBLOX DEVIATION Jump directly to using basic component description:
	-- if enableComponentStackLocations then
	-- 	return describeNativeComponentFrame(fn, false)
	-- else
	-- 	if not fn then
	-- 		return ""
	-- 	end
	-- 	-- ROBLOX deviation: use debug.info to discover function names
	-- 	local name = debug.info(fn :: Function, "n")
	-- 	local ownerName = nil
	-- 	if _G.__DEV__ and ownerFn then
	-- 		-- ROBLOX deviation: owner may be a function or a table
	-- 		ownerName = describeOwner(ownerFn)
	-- 	end
	-- 	return describeComponentFrame(name, source, ownerName)
	-- end
	if not fn then
		return ""
	end
	-- ROBLOX deviation: use debug.info to discover function names
	local name = debug.info(fn :: Function, "n")
	local ownerName = nil
	if _G.__DEV__ and ownerFn then
		-- ROBLOX deviation: owner may be a function or a table
		ownerName = describeOwner(ownerFn)
	end
	return describeComponentFrame(name, source, ownerName)
end
