local y=game:GetService("\067\111\108\108\101\099\116\105\111\110\083\101\114\118\105\099\101")local g=require(script.t)local H={}H.__index=H local k=g.tuple(g.string,g.optional(g.callback))function H.new(g,o)assert(k(g,o))local T={}T.name=g T.instanceCheck=o T._onAddedSignal=y:GetInstanceAddedSignal(g)T._onRemovedSignal=y:GetInstanceRemovedSignal(g)return setmetatable(T,H)end function H.__tostring(y)return y.name end function H._maybeCheck(g,y)if g.instanceCheck then assert(g.instanceCheck(y))end end function H.has(H,g)return y:HasTag(g,H.name)end function H.add(H,g)H:_maybeCheck(g)y:AddTag(g,H.name)end function H.remove(H,g)return y:RemoveTag(g,H.name)end function H.toggle(g,y)if g:has(y)then g:remove(y)else g:add(y)end end function H.getTagged(g)return y:GetTagged(g.name)end function H.onAdded(k,H)assert(g.callback(H))local function o(y)k:_maybeCheck(y)H(y)end local T=k._onAddedSignal:Connect(o)for y,g in ipairs(y:GetTagged(k.name))do k:_maybeCheck(g)o(g)end return T end function H.onRemoved(H,y)assert(g.callback(y))return H._onRemovedSignal:Connect(y)end return H
local CollectionService = game:GetService("CollectionService")

local t = require(script.t)

local Tag = {}
Tag.__index = Tag

local newCheck = t.tuple(
	t.string,
	t.optional(t.callback) -- This can be a t typechecker
)
function Tag.new(name, instanceCheck)
	assert(newCheck(name, instanceCheck))

	local self = {}

	self.name = name
	self.instanceCheck = instanceCheck
    self._onAddedSignal = CollectionService:GetInstanceAddedSignal(name)
    self._onRemovedSignal = CollectionService:GetInstanceRemovedSignal(name)

    return setmetatable(self, Tag)
end

function Tag:__tostring()
	return self.name
end

function Tag:_maybeCheck(instance)
	if self.instanceCheck then
		assert(self.instanceCheck(instance))
	end
end

function Tag:has(instance)
    return CollectionService:HasTag(instance, self.name)
end

function Tag:add(instance)
	self:_maybeCheck(instance)

    CollectionService:AddTag(instance, self.name)
end

function Tag:remove(instance)
	return CollectionService:RemoveTag(instance, self.name)
end

function Tag:toggle(instance)
	if self:has(instance) then
		self:remove(instance)
	else
		self:add(instance)
	end
end

function Tag:getTagged()
	return CollectionService:GetTagged(self.name)
end

function Tag:onAdded(callback)
	assert(t.callback(callback))

	local function onAdded(instance)
		self:_maybeCheck(instance)

		callback(instance)
	end

    local onInstanceAddedConn = self._onAddedSignal:Connect(onAdded)

	for _, instance in ipairs(CollectionService:GetTagged(self.name)) do
		self:_maybeCheck(instance)
        onAdded(instance)
    end

    return onInstanceAddedConn
end

function Tag:onRemoved(callback)
	assert(t.callback(callback))

    return self._onRemovedSignal:Connect(callback)
end

return Tag
