local I=script.Parent.Parent local p=I.Parent local l=I.components local t=I.hooks local o=require(p.LuauPolyfill)local b=o.Object local q=o.setTimeout local Y=require(script.Parent.Parent.luaUtils)local S,X,W=Y.Array,Y.setInterval,Y.clearInterval return function(I,p)local o=I.useState local Y=I.useEffect local v=I.useRef local w,P=p.unstable_LowPriority,p.unstable_runWithPriority local A=(require(t.useFrame))(I)local N=(require(l.DivLike))(I)local r=(require(l.Canvas))(I)local x=.001 local c=20 local u=600 local D=1000 local k={}local e={}local E=_G.cachegrind=="\116\114\117\101"local a=function()return math.random()*math.pi end local function d(p)local l,t=p.change or false,b.assign({},p,{change=b.None})local S,X=o(Color3.new(0,0,0))if(S.R+S.G)+S.B>0 then local I=os.clock()+x repeat until not(os.clock()<I)end local W=v(false)Y(function()W.current=true return function()W.current=false end end)Y(function()if l then local I if E then I=100 else I=math.random()*1000 end q(function()P(w,function()return W.current and X(Color3.new(math.random(),math.random(),math.random()))end)end,I)end end,{l})return I.createElement("\080\097\114\116",{Name="\066\108\111\099\107";Material=Enum.Material.Plastic;Color=S;Position=Vector3.new(table.unpack(p.position));Size=Vector3.new(table.unpack(p.scale))})end local function G()local p,l=o(false)Y(function()local I=X(function()l(function(I)return not I end)end,2000)return function()W(I)end end)local t,b=800,600 local q=(t/100)/c return S.map(S.create(u,0),function(l,o)local Y=o-1 local S=(-t/100)/2+q/2 local X=(b/100)/2-q/2 local W=(Y%c)*q local v=math.floor(Y/c)*-q return I.createElement(d,{key=Y,change=p,scale={q;q,q},position={S+W,X+v,0}})end)end local function J()local p=v()local l=os.clock()local t=0 local o=0 A(function()local I=os.clock()local b=1/(I-l)t+=1 local q=(b-o)/t local Y=o o+=q if math.round(o)~=math.round(Y)and p.current~=nil then p.current.Text=D..(" \115\112\105\107\101\115\n"..(u..(" \098\108\111\099\107\115\n"..(u*x..("\109\115 \112\111\116\101\110\116\105\097\108 \108\111\097\100\n\102\112\115 \097\118\103 "..math.round(o))))))end l=I end)return I.createElement("\084\101\120\116\076\097\098\101\108",{Size=UDim2.new(0,150,0,100),Position=UDim2.new(1,-10,1,-10);AnchorPoint=Vector2.new(1,1),Text="\046\046\046";ref=p})end local function m()local p=0 local l=v()local t=o(function()return{a();a(),a()}end)A(function()p+=.01 local I=CFrame.Angles(t[1]+p,t[2]+p,t[3]+p)if l.current then l.current.CFrame=I end end)return I.createElement("\080\097\114\116",{Name="\066\111\120",ref=l;Material=Enum.Material.Rock,Size=Vector3.new(2,2,2);Color=Color3.new(math.random(),math.random(),math.random()),Reflectance=.3})end local function h()return S.map(S.create(D,0),function(p,l)return I.createElement(m,{key=l})end)end local function V(p)local l=os.clock()local function t()return os.clock()-l end A(function()if p.canvasRef.current then p.canvasRef.current.CFrame=CFrame.new(Vector3.new(0,0,6+math.sin(t()*3)*2),Vector3.new(0,0,0))end end)return I.createElement(N)end local T=function()local p=v()return I.createElement("\083\099\114\101\101\110\071\117\105",nil,I.createElement(N,nil,{I.createElement(r,{ref=p},{I.createElement(G);I.createElement(h);I.createElement(V,{canvasRef=p})});I.createElement(J)}))end return{Concurrent=T;Block=d;Blocks=G;FPS=J,Box=m,AnimatedSpikes=h;Dolly=V}end
-- upstream: https://github.com/pmndrs/react-three-fiber/blob/v5.3.19/examples/src/demos/dev/Concurrent.js

local srcWorkspace = script.Parent.Parent
local rootWorkspace = srcWorkspace.Parent
local componentsWorkspace = srcWorkspace.components
local hooksWorkspace = srcWorkspace.hooks

local LuauPolyfill = require(rootWorkspace.LuauPolyfill)
local Object = LuauPolyfill.Object
local setTimeout = LuauPolyfill.setTimeout
local luaUtils = require(script.Parent.Parent.luaUtils)
local Array, setInterval, clearInterval = luaUtils.Array, luaUtils.setInterval, luaUtils.clearInterval

return function(Roact, Scheduler)
	local useState = Roact.useState
	local useEffect = Roact.useEffect
	local useRef = Roact.useRef

	local low, run = Scheduler.unstable_LowPriority, Scheduler.unstable_runWithPriority

	local useFrame = require(hooksWorkspace.useFrame)(Roact)
	local DivLike = require(componentsWorkspace.DivLike)(Roact)
	local Canvas = require(componentsWorkspace.Canvas)(Roact)

	-- ROBLOX deviation: because os.clock() returns a nr in seconds it's easier to
	-- use slowdown in seconds as well
	local SLOWDOWN = 1 / 1000
	local ROW = 20
	local BLOCK_AMOUNT = 600
	local SPIKE_AMOUNT = 1000

	local _geom = {} -- new BoxBufferGeometry(1, 1, 1)
	local _matr = {} -- new MeshNormalMaterial()
	local isCachegrind = _G.cachegrind == "true"

	local rpi = function()
		return math.random() * math.pi
	end

	local function Block(props)
		local change, _restProps = props.change or false, Object.assign({}, props, { change = Object.None })
		-- ROBLOX deviation: we need to use 3 numbers to represent a color in Roblox
		local color, set = useState(Color3.new(0, 0, 0))

		-- Artificial slowdown ...
		-- ROBLOX deviation: whole color is equal 0 if sum of all color parts is equal to 0
		if color.R + color.G + color.B > 0 then
			local e = os.clock() + SLOWDOWN
			repeat
			until not (os.clock() < e)
		end

		local mounted = useRef(false)

		useEffect(function()
			mounted.current = true
			return function()
				mounted.current = false
			end
		end)

		useEffect(function()
			if change then
				local duration
				if isCachegrind then
					duration = 100
				else
					duration = math.random() * 1000
				end

				setTimeout(function()
					run(low, function()
						return mounted.current and set(Color3.new(math.random(), math.random(), math.random()))
					end)
				end, duration)
			end
		end, {
			change,
		})

		return Roact.createElement("Part", {
			Name = "Block",
			Material = Enum.Material.Plastic,
			Color = color,
			Position = Vector3.new(table.unpack(props.position)),
			Size = Vector3.new(table.unpack(props.scale)),
		})
	end

	local function Blocks()
		local changeBlocks, set = useState(false)
		useEffect(function()
			local handler = setInterval(function()
				set(function(state)
					return not state
				end)
			end, 2000)
			return function()
				clearInterval(handler)
			end
		end)

		-- const { viewport } = useThree()
		-- const { width, height } = viewport().factor
		local width, height = 800, 600 -- TODO implement viewport
		local size = width / 100 / ROW
		return Array.map(Array.create(BLOCK_AMOUNT, 0), function(_, i_)
			local i = i_ - 1
			local left = -width / 100 / 2 + size / 2
			local top = height / 100 / 2 - size / 2
			local x = (i % ROW) * size
			local y = math.floor(i / ROW) * -size

			return Roact.createElement(Block, {
				key = i,
				change = changeBlocks,
				scale = { size, size, size },
				position = { left + x, top + y, 0 },
			})
		end)
	end

	local function FPS()
		local ref = useRef()
		local last = os.clock()
		local qty = 0
		local currentAvg = 0

		useFrame(function()
			local now = os.clock()
			local fps = 1 / (now - last)

			qty += 1
			--[[
				ROBLOX deviation:
				if we round the avg delta in here and don't update currentAvg each time it becomes basically impossible for the fps avg to be updated when qty value becomes larger
			]]
			local avg = (fps - currentAvg) / qty
			local lastAvg = currentAvg
			currentAvg += avg
			-- ROBLOX TODO: remove ref.current ~= nil when ref is guaranteed to be not nil
			if math.round(currentAvg) ~= math.round(lastAvg) and ref.current ~= nil then
				ref.current.Text = SPIKE_AMOUNT
					.. " spikes\n"
					.. BLOCK_AMOUNT
					.. " blocks\n"
					.. (BLOCK_AMOUNT * SLOWDOWN)
					.. "ms potential load\nfps avg "
					.. math.round(currentAvg)
			end
			last = now
		end)

		return Roact.createElement("TextLabel", {
			Size = UDim2.new(0, 150, 0, 100),
			Position = UDim2.new(1, -10, 1, -10),
			AnchorPoint = Vector2.new(1, 1),
			Text = "...",
			-- selene: allow(roblox_incorrect_roact_usage)
			ref = ref,
		})
	end

	local function Box()
		local t = 0
		local mesh = useRef()
		local coords = useState(function()
			return { rpi(), rpi(), rpi() }
		end)
		useFrame(function()
			-- ROBLOX deviation: increase t before calculating rotation matrix
			t += 0.01
			local rotationFrame = CFrame.Angles(coords[1] + t, coords[2] + t, coords[3] + t)
			if mesh.current then
				mesh.current.CFrame = rotationFrame
			end
		end)
		return Roact.createElement("Part", {
			Name = "Box",
			-- selene: allow(roblox_incorrect_roact_usage)
			ref = mesh,
			Material = Enum.Material.Rock,
			Size = Vector3.new(2, 2, 2),
			Color = Color3.new(math.random(), math.random(), math.random()),
			Reflectance = 0.3,
		})
	end

	local function AnimatedSpikes()
		return Array.map(Array.create(SPIKE_AMOUNT, 0), function(_, i)
			return Roact.createElement(Box, { key = i })
		end)
	end

	local function Dolly(props)
		-- const { clock, camera } = useThree()
		local t = os.clock()
		local function getElapsedTime()
			return os.clock() - t
		end
		useFrame(function()
			if props.canvasRef.current then
				props.canvasRef.current.CFrame =
					CFrame.new(Vector3.new(0, 0, 6 + math.sin(getElapsedTime() * 3) * 2), Vector3.new(0, 0, 0))
			end
		end)
		return Roact.createElement(DivLike)
	end

	local App = function()
		local canvasRef = useRef()
		return Roact.createElement(
			"ScreenGui",
			nil,
			Roact.createElement(DivLike, nil, {
				Roact.createElement(Canvas, {
					ref = canvasRef,
				}, {
					Roact.createElement(Blocks),
					Roact.createElement(AnimatedSpikes),
					Roact.createElement(Dolly, { canvasRef = canvasRef }),
				}),
				Roact.createElement(FPS),
			})
		)
	end

	return {
		Concurrent = App,

		Block = Block,
		Blocks = Blocks,
		FPS = FPS,
		Box = Box,
		AnimatedSpikes = AnimatedSpikes,
		Dolly = Dolly,
	}
end
