local T=game:GetService("\080\104\121\115\105\099\115\083\101\114\118\105\099\101")local O=game:GetService("\084\101\120\116\083\101\114\118\105\099\101")local a=script.Parent.Parent local D=require(a.Constants)local w=require(a.Packages.Roact)local v=require(a.Packages.StudioComponents)local H=v.withTheme local t=v.ScrollFrame local A=v.Label local c=require(script.GridItem)local I=40 local Q=30 local q=5 local C=1 local V=35 local B=D.GridCellSize local function L(T)local a=Vector2.new(100000.0,100000.0)return O:GetTextSize(T,14,Enum.Font.SourceSansBold,a)end local P=w.Component:extend("\071\114\105\100\086\105\101\119")function P.init(T)T.scrollPosition,T.setScrollPosition=w.createBinding(Vector2.new(0,0))T:setState({HoveredGroupName0="",HoveredGroupName1=""})end function P.render(O)local a=O.props.Groups local D=O.state.HoveredGroupName0 local v=O.state.HoveredGroupName1 local P=I for T,O in ipairs(a)do local a=(L(O.name)).x+1 if a>P then P=a end end local Z=Q local N=math.rad(V)for T,O in ipairs(a)do local a=L(O.name)*Vector2.new(1,.5)local D=math.ceil((3+a.x*math.sin(N))+a.y*math.cos(N))if D>Z then Z=D end end local E={}for T,O in a do E[O.name]=T end local M={}for H,t in ipairs(a)do local A={}for H=H,#a,1 do local I=a[H]local Q=T:CollisionGroupsAreCollidable(t.name,I.name)local q=t.name==D and E[I.name]>=E[v]or I.name==v and E[t.name]<=E[D]A[H]=w.createElement(c,{Disabled=O.props.Disabled;LayoutOrder=#a-H;Highlighted=q;Collidable=Q;OnActivated=function()O.props.SetGroupsCollidable(t.name,I.name,not Q)end;OnHoverBegan=function()O:setState({HoveredGroupName0=t.name;HoveredGroupName1=I.name})end;OnHoverEnded=function()if D==t.name and v==I.name then O:setState({HoveredGroupName0="",HoveredGroupName1=""})end end})end M[H]=w.createElement("\070\114\097\109\101",{LayoutOrder=H;Size=UDim2.fromOffset(B.x*#a,B.y),BackgroundTransparency=1},{Layout=w.createElement("\085\073\076\105\115\116\076\097\121\111\117\116",{SortOrder=Enum.SortOrder.LayoutOrder;FillDirection=Enum.FillDirection.Horizontal}),Content=w.createFragment(A)})end local x={}for T,D in ipairs(a)do local H=D.name==v x[T]=w.createElement("\070\114\097\109\101",{LayoutOrder=#a-T,Size=UDim2.new(0,B.x,1,0);BackgroundTransparency=1},{Label=w.createElement(A,{AnchorPoint=Vector2.new(.5,1);BackgroundTransparency=1,Position=UDim2.new(.5,3,1,0);Rotation=V,Size=UDim2.fromOffset(0,14),Text=D.name;Font=H and Enum.Font.SourceSansBold or Enum.Font.SourceSans,TextColorStyle=H and Enum.StudioStyleGuideColor.BrightText or Enum.StudioStyleGuideColor.MainText;TextXAlignment=Enum.TextXAlignment.Right;TextYAlignment=Enum.TextYAlignment.Bottom;Disabled=O.props.Disabled})})end local e={}for T,a in ipairs(a)do local v=a.name==D e[T]=w.createElement(A,{LayoutOrder=T,BackgroundTransparency=1,Size=UDim2.new(1,0,0,B.y);Text=a.name,Font=v and Enum.Font.SourceSansBold or Enum.Font.SourceSans,TextColorStyle=v and Enum.StudioStyleGuideColor.BrightText or Enum.StudioStyleGuideColor.MainText,TextXAlignment=Enum.TextXAlignment.Right;Disabled=O.props.Disabled})end return w.createFragment({Main=w.createElement(t,{AnchorPoint=Vector2.new(1,1);Size=UDim2.new(1,-P-q,1,-Z-C),Position=UDim2.fromScale(1,1),ScrollingDirection=Enum.ScrollingDirection.XY,OnScrolled=O.setScrollPosition,Disabled=O.props.Disabled},M);Header0=w.createElement("\070\114\097\109\101",{AnchorPoint=Vector2.new(1,0),BackgroundTransparency=1,Position=UDim2.fromScale(1,0),Size=UDim2.new(1,-P-q,0,Z);ClipsDescendants=true},{Holder=w.createElement("\070\114\097\109\101",{BackgroundTransparency=1;Size=UDim2.new(0,#a*B.x,1,0),Position=O.scrollPosition:map(function(T)return UDim2.fromOffset(-T.x,0)end)},{Layout=w.createElement("\085\073\076\105\115\116\076\097\121\111\117\116",{SortOrder=Enum.SortOrder.LayoutOrder;FillDirection=Enum.FillDirection.Horizontal}),Content=w.createFragment(x)})}),Header0Triangle=H(function(T)return w.createElement("\073\109\097\103\101\076\097\098\101\108",{ZIndex=2,BackgroundTransparency=1;AnchorPoint=Vector2.new(1,1);Position=UDim2.fromOffset(P,Z);Size=UDim2.fromOffset(P,Z),Image="\114\098\120\097\115\115\101\116\105\100\058\047\047\054\056\053\049\056\057\052\049\052\051";ImageColor3=T:GetColor(Enum.StudioStyleGuideColor.MainBackground)})end);Header1=w.createElement("\070\114\097\109\101",{BackgroundTransparency=1;Size=UDim2.new(0,P,1,-Z-C);Position=UDim2.fromScale(0,1);AnchorPoint=Vector2.new(0,1),ClipsDescendants=true},{Holder=w.createElement("\070\114\097\109\101",{BackgroundTransparency=1,Size=UDim2.new(1,0,0,#a*B.y);Position=O.scrollPosition:map(function(T)return UDim2.fromOffset(0,-T.y)end)},{Layout=w.createElement("\085\073\076\105\115\116\076\097\121\111\117\116",{SortOrder=Enum.SortOrder.LayoutOrder}),Content=w.createFragment(e)})})})end return P
local PhysicsService = game:GetService("PhysicsService")
local TextService = game:GetService("TextService")

local Plugin = script.Parent.Parent
local Constants = require(Plugin.Constants)

local Roact = require(Plugin.Packages.Roact)
local StudioComponents = require(Plugin.Packages.StudioComponents)

local withTheme = StudioComponents.withTheme
local ScrollFrame = StudioComponents.ScrollFrame
local Label = StudioComponents.Label
local GridItem = require(script.GridItem)

local MARGIN_MIN_LEFT = 40
local MARGIN_MIN_TOP = 30

local MARGIN_PADDING_LEFT = 5
local MARGIN_PADDING_TOP = 1

local DIAGONAL_ANGLE = 35
local CELL_SIZE = Constants.GridCellSize

local function getTextSize(text)
	local frameSize = Vector2.new(1e5, 1e5)
	return TextService:GetTextSize(text, 14, Enum.Font.SourceSansBold, frameSize)
end

local GridView = Roact.Component:extend("GridView")

function GridView:init()
	self.scrollPosition, self.setScrollPosition = Roact.createBinding(Vector2.new(0, 0))
	self:setState({
		HoveredGroupName0 = "",
		HoveredGroupName1 = "",
	})
end

function GridView:render()
	local groups = self.props.Groups
	local hoveredName0 = self.state.HoveredGroupName0
	local hoveredName1 = self.state.HoveredGroupName1

	local leftMargin = MARGIN_MIN_LEFT
	for _, group in ipairs(groups) do
		local width = getTextSize(group.name).x + 1
		if width > leftMargin then
			leftMargin = width
		end
	end

	local topMargin = MARGIN_MIN_TOP
	local angle = math.rad(DIAGONAL_ANGLE)
	for _, group in ipairs(groups) do
		local aabb = getTextSize(group.name) * Vector2.new(1, 0.5)
		local height = math.ceil(3 + aabb.x * math.sin(angle) + aabb.y * math.cos(angle))
		if height > topMargin then
			topMargin = height
		end
	end

	local nameOrder = {}
	for i, group in groups do
		nameOrder[group.name] = i
	end

	local gridContent = {}
	for i, group0 in ipairs(groups) do
		local items = {}
		for j = i, #groups do
			local group1 = groups[j]
			local collidable = PhysicsService:CollisionGroupsAreCollidable(group0.name, group1.name)
			local highlighted = (group0.name == hoveredName0 and nameOrder[group1.name] >= nameOrder[hoveredName1])
				or (group1.name == hoveredName1 and nameOrder[group0.name] <= nameOrder[hoveredName0])

			items[j] = Roact.createElement(GridItem, {
				Disabled = self.props.Disabled,
				LayoutOrder = #groups - j,
				Highlighted = highlighted,
				Collidable = collidable,
				OnActivated = function()
					self.props.SetGroupsCollidable(group0.name, group1.name, not collidable)
				end,
				OnHoverBegan = function()
					self:setState({
						HoveredGroupName0 = group0.name,
						HoveredGroupName1 = group1.name,
					})
				end,
				OnHoverEnded = function()
					if hoveredName0 == group0.name and hoveredName1 == group1.name then
						self:setState({
							HoveredGroupName0 = "",
							HoveredGroupName1 = "",
						})
					end
				end,
			})
		end
		gridContent[i] = Roact.createElement("Frame", {
			LayoutOrder = i,
			Size = UDim2.fromOffset(CELL_SIZE.x * #groups, CELL_SIZE.y),
			BackgroundTransparency = 1,
		}, {
			Layout = Roact.createElement("UIListLayout", {
				SortOrder = Enum.SortOrder.LayoutOrder,
				FillDirection = Enum.FillDirection.Horizontal,
			}),
			Content = Roact.createFragment(items),
		})
	end

	local headerContent0 = {}
	for i, group in ipairs(groups) do
		local highlighted = group.name == hoveredName1
		headerContent0[i] = Roact.createElement("Frame", {
			LayoutOrder = #groups - i,
			Size = UDim2.new(0, CELL_SIZE.x, 1, 0),
			BackgroundTransparency = 1,
		}, {
			Label = Roact.createElement(Label, {
				AnchorPoint = Vector2.new(0.5, 1),
				BackgroundTransparency = 1,
				Position = UDim2.new(0.5, 3, 1, 0),
				Rotation = DIAGONAL_ANGLE,
				Size = UDim2.fromOffset(0, 14),
				Text = group.name,
				Font = highlighted and Enum.Font.SourceSansBold or Enum.Font.SourceSans,
				TextColorStyle = highlighted and Enum.StudioStyleGuideColor.BrightText
					or Enum.StudioStyleGuideColor.MainText,
				TextXAlignment = Enum.TextXAlignment.Right,
				TextYAlignment = Enum.TextYAlignment.Bottom,
				Disabled = self.props.Disabled,
			}),
		})
	end

	local headerContent1 = {}
	for i, group in ipairs(groups) do
		local highlighted = group.name == hoveredName0
		headerContent1[i] = Roact.createElement(Label, {
			LayoutOrder = i,
			BackgroundTransparency = 1,
			Size = UDim2.new(1, 0, 0, CELL_SIZE.y),
			Text = group.name,
			Font = highlighted and Enum.Font.SourceSansBold or Enum.Font.SourceSans,
			TextColorStyle = highlighted and Enum.StudioStyleGuideColor.BrightText
				or Enum.StudioStyleGuideColor.MainText,
			TextXAlignment = Enum.TextXAlignment.Right,
			Disabled = self.props.Disabled,
		})
	end

	return Roact.createFragment({
		Main = Roact.createElement(ScrollFrame, {
			AnchorPoint = Vector2.new(1, 1),
			Size = UDim2.new(1, -leftMargin - MARGIN_PADDING_LEFT, 1, -topMargin - MARGIN_PADDING_TOP),
			Position = UDim2.fromScale(1, 1),
			ScrollingDirection = Enum.ScrollingDirection.XY,
			OnScrolled = self.setScrollPosition,
			Disabled = self.props.Disabled,
		}, gridContent),
		Header0 = Roact.createElement("Frame", {
			AnchorPoint = Vector2.new(1, 0),
			BackgroundTransparency = 1,
			Position = UDim2.fromScale(1, 0),
			Size = UDim2.new(1, -leftMargin - MARGIN_PADDING_LEFT, 0, topMargin),
			ClipsDescendants = true,
		}, {
			Holder = Roact.createElement("Frame", {
				BackgroundTransparency = 1,
				Size = UDim2.new(0, #groups * CELL_SIZE.x, 1, 0),
				Position = self.scrollPosition:map(function(pos)
					return UDim2.fromOffset(-pos.x, 0)
				end),
			}, {
				Layout = Roact.createElement("UIListLayout", {
					SortOrder = Enum.SortOrder.LayoutOrder,
					FillDirection = Enum.FillDirection.Horizontal,
				}),
				Content = Roact.createFragment(headerContent0),
			}),
		}),
		Header0Triangle = withTheme(function(theme)
			return Roact.createElement("ImageLabel", {
				ZIndex = 2,
				BackgroundTransparency = 1,
				AnchorPoint = Vector2.new(1, 1),
				Position = UDim2.fromOffset(leftMargin, topMargin),
				Size = UDim2.fromOffset(leftMargin, topMargin),
				Image = "rbxassetid://6851894143",
				ImageColor3 = theme:GetColor(Enum.StudioStyleGuideColor.MainBackground),
			})
		end),
		Header1 = Roact.createElement("Frame", {
			BackgroundTransparency = 1,
			Size = UDim2.new(0, leftMargin, 1, -topMargin - MARGIN_PADDING_TOP),
			Position = UDim2.fromScale(0, 1),
			AnchorPoint = Vector2.new(0, 1),
			ClipsDescendants = true,
		}, {
			Holder = Roact.createElement("Frame", {
				BackgroundTransparency = 1,
				Size = UDim2.new(1, 0, 0, #groups * CELL_SIZE.y),
				Position = self.scrollPosition:map(function(pos)
					return UDim2.fromOffset(0, -pos.y)
				end),
			}, {
				Layout = Roact.createElement("UIListLayout", {
					SortOrder = Enum.SortOrder.LayoutOrder,
				}),
				Content = Roact.createFragment(headerContent1),
			}),
		}),
	})
end

return GridView
