--!strict

local PhysicsService = game:GetService("PhysicsService")

local OPT_CREATE_GROUPS = true
local OPT_GROUP_ATTRIBUTE = "CollisionGroup"
local ERR_NO_GROUP = "No %q attribute has been set on %s"

local fmt = string.format

local Util = {}

Util.__index = Util

function Util.new(instance: Instance)
	local self = setmetatable({}, Util)
	
	self._events = {}
	self._target = instance
	self._group = instance:GetAttribute(OPT_GROUP_ATTRIBUTE)
	
	if type(self._group) ~= "string" then
		error(fmt(ERR_NO_GROUP, OPT_GROUP_ATTRIBUTE, instance:GetFullName()), 2)
	end
	
	self:ApplyCollisionGroup()
	
	table.insert(self._events, self._target.DescendantAdded:Connect(function(child)
		if child:IsA("BasePart") then
			self:ApplyCollisionGroupToPart(child::BasePart)
		end
	end))
	
	return self
end

function Util:CreateCollisionGroupIfNotExists()
	if OPT_CREATE_GROUPS == false then
		return
	end
	
	if not PhysicsService:GetCollisionGroupId(self._group) then
		PhysicsService:CreateCollisionGroup(self._group)
	end
end

function Util:ApplyCollisionGroupToPart(part: BasePart)
	PhysicsService:SetPartCollisionGroup(part, self._group)
end

function Util:ApplyCollisionGroup()
	self:CreateCollisionGroupIfNotExists()
	
	if self._target:IsA("BasePart") then
		self:ApplyCollisionGroupToPart(self._target::BasePart)
	else
		for _, child: BasePart in ipairs(self._target:GetDescendants()) do
			if not child:IsA("BasePart") then
				continue
			end
			
			self:ApplyCollisionGroupToPart(child)
		end
	end
end

function Util:Destroy()
	for _, event: RBXScriptConnection in ipairs(self._events) do
		event:Disconnect()
	end
end

return Util
