local A=require(script.Parent:WaitForChild("\065\117\116\104"))local a=require(script.Parent:WaitForChild("\068\097\116\097"))local b=require(script.Parent:WaitForChild("\082\101\109\111\116\101"))local s=require(script.Parent:WaitForChild("\085\116\105\108"))local m={}local J={5391359,5391361;5411126}local M={313102724;423601416}local function I(A)local a,b=s.Retry(function()return A:GetRankInGroup(3403354)end,5,.2,1)if a and b>1 then return 5 end local m,I=s.Retry(function()return s.Services.MarketplaceService:GetUserSubscriptionStatusAsync(A,"\069\088\080-\052\049\049\056\052\055\053\055\050\055\054\056\050\057\050\056\057\054\056")end,5,.2,1)if m and I.IsSubscribed then return 4 end for a,b in J do local m,J=s.Retry(function()return s.Services.MarketplaceService:UserOwnsGamePassAsync(A.UserId,b)end,5,.2,1)if m and J then return a end end for a,b in M do local m,J=s.Retry(function()return s.Services.MarketplaceService:PlayerOwnsAsset(A,b)end,5,.2,1)if m and J then return a end end return 0 end local function W(A)A:SetAttribute("\095\075\068\111\110\097\116\105\111\110\076\101\118\101\108",I(A))end local f={}for A,a in(script:WaitForChild("\085\071\067")):GetChildren()do task.spawn(function()local A=require(a)if A then f[A.MatchId]=A end end)end if s.Services.RunService:IsServer()then local M={}local function I(A,a)local b=M[A.UserId]if not b then b={}M[A.UserId]=b end if b[a]then return true end local m,J=s.Retry(function()return s.Services.MarketplaceService:PlayerOwnsAsset(A,a)end,5,1,2)if m then b[a]=J return J end return end local U={[133292294488871]="\114\098\120\097\115\115\101\116\105\100\058\047\047\056\057\049\049\057\050\049\049\054\050\053\051\048\048";[110848154960799]="\114\098\120\097\115\115\101\116\105\100\058\047\047\056\057\049\049\057\050\049\049\054\050\053\051\048\048";[92807314389236]="\114\098\120\097\115\115\101\116\105\100\058\047\047\056\057\049\049\057\050\049\049\054\050\053\051\048\048";[18966788838]="\114\098\120\097\115\115\101\116\105\100\058\047\047\049\056\057\054\054\055\054\050\057\054\053",[106645613603989]="\114\098\120\097\115\115\101\116\105\100\058\047\047\049\056\057\054\054\055\054\050\057\054\053";[99317257118206]="\114\098\120\097\115\115\101\116\105\100\058\047\047\049\056\057\054\054\055\054\050\057\054\053"}local w,o={},{}b.VIPUGCMethod.OnServerEvent:Connect(function(A,b,s,m,J)if not a.settings.vip then return end local M=f[s]if not(M and A.Character)then return end local W=o[A.UserId]if not W then W={}o[A.UserId]=W end local k=A.Character:FindFirstChild(M.Name)if k then k:Destroy()end if not m then W[s]=nil return end if U[b]~=s then return end local D=A:GetAttribute("\095\075\068\111\110\097\116\105\111\110\076\101\118\101\108")or 0 local i=D>2 or s=="\114\098\120\097\115\115\101\116\105\100\058\047\047\049\056\057\054\054\055\054\050\057\054\053"and D>1 or I(A,b)local R=w[b]if not R then R={}w[b]=R end if i or not R[A.UserId]then local a if not R[A.UserId]then a=true R[A.UserId]=true end local b=M.Method(A.Character,{Name=J;Destroy=tick})if a and not i then task.delay(15,function()if b then b:Destroy()end end)else W[s]={Method=M.Method,name=J}end end end)function m.UGCHandler(A)if not a.settings.vip then return end for a,b in A:GetChildren()do if not b:IsA("\065\099\099\101\115\115\111\114\121")then continue end local s=b:FindFirstChild("\072\097\110\100\108\101")if not s then continue end local m if s:IsA("\077\101\115\104\080\097\114\116")then m=s.MeshId else local A=s:FindFirstChildOfClass("\083\112\101\099\105\097\108\077\101\115\104")if A then m=A.MeshId end end local J=f[m]if J then task.spawn(J.Method,A,b)end end local b=s.Services.Players:GetPlayerFromCharacter(A)local m=b and o[b.UserId]if not m then return end for a,b in m do task.spawn(b.Method,A,{Name=b.name,Destroy=tick})end end function m.CharacterAdded(A)local a=A:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if not a then return end a.ApplyDescriptionFinished:Connect(function()m.UGCHandler(A)end)end s.SafePlayerAdded(function(A)task.spawn(W,A)A.CharacterAdded:Connect(m.CharacterAdded)A.CharacterAppearanceLoaded:Connect(m.UGCHandler)if A.Character then m.UGCHandler(A.Character)end end)s.Services.MarketplaceService.PromptPurchaseFinished:Connect(function(A,a,b)if b then local b=M[A.UserId]if not b then b={}M[A.UserId]=b end b[a]=true end end)s.Services.MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(b,s,m)if m then local m=b:GetAttribute("\095\075\068\111\110\097\116\105\111\110\076\101\118\101\108")or 0 local M=table.find(J,s)if M then m=math.max(m,M)if a.settings.vip then A.userRoleAdd(b.UserId,"\118\105\112")end end b:SetAttribute("\095\075\068\111\110\097\116\105\111\110\076\101\118\101\108",m)end end)end return m
local Auth = require(script.Parent:WaitForChild("Auth"))
local Data = require(script.Parent:WaitForChild("Data"))
local Remote = require(script.Parent:WaitForChild("Remote"))
local Util = require(script.Parent:WaitForChild("Util"))

local VIP = {}

-- vip, supervip, premium
local gamePassDonations = { 5391359, 5391361, 5411126 }
local assetDonations = { 313102724, 423601416 }

-- 5 group member
-- 4 subscriber
-- 3 premium donor
-- 2 super vip
-- 1 vip
local function getDonationLevel(player)
	local okRank, rank = Util.Retry(function()
		return player:GetRankInGroup(3403354)
	end, 5, 0.2, 1)
	if okRank and rank > 1 then
		return 5
	end

	local okSubscription, status = Util.Retry(function()
		return Util.Services.MarketplaceService:GetUserSubscriptionStatusAsync(player, "EXP-4118475727682928968")
	end, 5, 0.2, 1)
	if okSubscription and status.IsSubscribed then
		return 4
	end

	for index, passId in gamePassDonations do
		local okGamePass, result = Util.Retry(function()
			return Util.Services.MarketplaceService:UserOwnsGamePassAsync(player.UserId, passId)
		end, 5, 0.2, 1)
		if okGamePass and result then
			return index
		end
	end

	for index, assetId in assetDonations do
		local okAsset, result = Util.Retry(function()
			return Util.Services.MarketplaceService:PlayerOwnsAsset(player, assetId)
		end, 5, 0.2, 1)
		if okAsset and result then
			return index
		end
	end

	return 0
end

local function setDonationLevel(player)
	player:SetAttribute("_KDonationLevel", getDonationLevel(player))
end

local adminUGCMap = {}

for _, module in script:WaitForChild("UGC"):GetChildren() do
	task.spawn(function()
		local result = require(module)
		if result then
			adminUGCMap[result.MatchId] = result
		end
	end)
end

if Util.Services.RunService:IsServer() then
	local ownedCache = {}
	local function ownsAsset(player, assetId)
		local ownedUGC = ownedCache[player.UserId]
		if not ownedUGC then
			ownedUGC = {}
			ownedCache[player.UserId] = ownedUGC
		end

		if ownedUGC[assetId] then
			return true
		end

		local ok, result = Util.Retry(function()
			return Util.Services.MarketplaceService:PlayerOwnsAsset(player, assetId)
		end, 5, 1, 2)
		if ok then
			ownedUGC[assetId] = result
			return result
		end

		return
	end

	local ugcAssetMatch = {
		-- wings
		[133292294488871] = "rbxassetid://89119211625300", -- light
		[110848154960799] = "rbxassetid://89119211625300", -- dark
		[92807314389236] = "rbxassetid://89119211625300", -- gold
		-- crowns
		[18966788838] = "rbxassetid://18966762965", -- light
		[106645613603989] = "rbxassetid://18966762965", -- dark
		[99317257118206] = "rbxassetid://18966762965", -- gold
	}

	local cache, effects = {}, {}
	Remote.VIPUGCMethod.OnServerEvent:Connect(function(player, assetId, match, equip, name)
		if not Data.settings.vip then
			return
		end

		local ugcEffect = adminUGCMap[match]
		if not (ugcEffect and player.Character) then
			return
		end

		local userEffects = effects[player.UserId]
		if not userEffects then
			userEffects = {}
			effects[player.UserId] = userEffects
		end

		local existing = player.Character:FindFirstChild(ugcEffect.Name)
		if existing then
			existing:Destroy()
		end

		if not equip then
			userEffects[match] = nil
			return
		end

		if ugcAssetMatch[assetId] ~= match then
			return
		end

		local donationLevel = player:GetAttribute("_KDonationLevel") or 0
		local owned = donationLevel > 2
			or (match == "rbxassetid://18966762965" and donationLevel > 1)
			or ownsAsset(player, assetId)

		local tried = cache[assetId]
		if not tried then
			tried = {}
			cache[assetId] = tried
		end

		if owned or not tried[player.UserId] then
			local try
			if not tried[player.UserId] then
				try = true
				tried[player.UserId] = true
			end

			local ugc = ugcEffect.Method(player.Character, { Name = name, Destroy = tick })

			if try and not owned then
				task.delay(15, function()
					if ugc then
						ugc:Destroy()
					end
				end)
			else
				userEffects[match] = { Method = ugcEffect.Method, name = name }
			end
		end
	end)

	function VIP.UGCHandler(character)
		if not Data.settings.vip then
			return
		end

		-- ugc avatar effects
		for _, child in character:GetChildren() do
			if not child:IsA("Accessory") then
				continue
			end

			local handle = child:FindFirstChild("Handle")
			if not handle then
				continue
			end

			local mesh
			if handle:IsA("MeshPart") then
				mesh = handle.MeshId
			else
				local specialMesh = handle:FindFirstChildOfClass("SpecialMesh")
				if specialMesh then
					mesh = specialMesh.MeshId
				end
			end

			local ugcEffect = adminUGCMap[mesh]
			if ugcEffect then
				task.spawn(ugcEffect.Method, character, child)
			end
		end

		-- vip equipped effects
		local player = Util.Services.Players:GetPlayerFromCharacter(character)
		local effects = player and effects[player.UserId]
		if not effects then
			return
		end

		for _, effect in effects do
			task.spawn(effect.Method, character, { Name = effect.name, Destroy = tick })
		end
	end

	function VIP.CharacterAdded(character)
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		if not humanoid then
			return
		end
		humanoid.ApplyDescriptionFinished:Connect(function()
			VIP.UGCHandler(character)
		end)
	end

	Util.SafePlayerAdded(function(player)
		task.spawn(setDonationLevel, player)
		player.CharacterAdded:Connect(VIP.CharacterAdded)
		player.CharacterAppearanceLoaded:Connect(VIP.UGCHandler)
		if player.Character then
			VIP.UGCHandler(player.Character)
		end
	end)

	Util.Services.MarketplaceService.PromptPurchaseFinished:Connect(function(player, assetId, purchased)
		if purchased then
			local ownedUGC = ownedCache[player.UserId]
			if not ownedUGC then
				ownedUGC = {}
				ownedCache[player.UserId] = ownedUGC
			end
			ownedUGC[assetId] = true
		end
	end)

	Util.Services.MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player, passId, purchased)
		if purchased then
			local level = player:GetAttribute("_KDonationLevel") or 0
			local vipIndex = table.find(gamePassDonations, passId)
			if vipIndex then
				level = math.max(level, vipIndex)
				if Data.settings.vip then
					Auth.userRoleAdd(player.UserId, "vip")
				end
			end
			player:SetAttribute("_KDonationLevel", level)
		end
	end)
end

return VIP
