--	["1527622"] = true,
--	["4640898"] = true,
--	["1055299"] = true,
}

local allowedAssets = {
	["8"] = true, -- Hat
	["11"] = true, -- Shirt
	["12"] = true, -- Pants
	["17"] = true, -- Head
	["18"] = true, -- Face
	["27"] = true, -- Torso
	["28"] = true, -- RightArm
	["29"] = true, -- LeftArm
	["30"] = true, -- LeftLeg
	["31"] = true, -- RightLeg
	["41"] = true, -- HairAccessory
	["42"] = true, -- FaceAccessory
	["43"] = true, -- NeckAccessory
	["44"] = true, -- ShoulderAccessory
	["45"] = true, -- FrontAccessory
	["46"] = true, -- BackAccessory
	["47"] = true, -- WaistAccessory
	["48"] = true, -- ClimbAnimation
	["50"] = true, -- FallAnimation
	["51"] = true, -- IdleAnimation
	["52"] = true, -- JumpAnimation
	["53"] = true, -- RunAnimation
	["54"] = true, -- SwimAnimation
	["55"] = true, -- WalkAnimation
}

local playerWearingAssets = {}
local AssetTypeEnumLookup = {}

local function insertToTable(assets, productInfo)
	table.insert(assets, {
		id = productInfo.AssetId,
		assetType = {
			name = AssetTypeEnumLookup[productInfo.AssetTypeId].Name,
			id = productInfo.AssetTypeId,
		},
		name = productInfo.Name
	})
end

local function getOriginalHeadMesh()
	local mesh = Instance.new("SpecialMesh")
	mesh.MeshType = Enum.MeshType.Head
	mesh.Scale = Vector3.new(1.25, 1.25, 1.25)
	local originalSize = Instance.new("Vector3Value")
	originalSize.Name = "OriginalSize"
	originalSize.Value = Vector3.new(1.25, 1.25, 1.25)
	originalSize.Parent = mesh
	return mesh
end

local function getOriginalFace()
	local decal = Instance.new("Decal")
	decal.Texture = DEFAULT_FACE
	return decal
end

local function getOriginalClothing(clothe)
	if clothe == "Shirt" then
		local shirt = Instance.new("Shirt")
		shirt.ShirtTemplate = DEFAULT_SHIRT
		return shirt
	elseif clothe == "Pants" then
		local pants = Instance.new("Pants")
		pants.PantsTemplate = DEFAULT_PANTS
		return pants
	end
end

local function wear(player, id)
	if id == nil or not (typeof(id) == "number") then
		return
	end
	if not playerWearingAssets[player] then
		return
	end
	if bannedAssets[tostring(id)] then
		return
	end
	
	local productInfo, items
	local success, err = pcall(function()
		productInfo = Marketplace:GetProductInfo(id)
	end)
	if not success then
		return warn(err)
	end
	local assetTypeId = tostring(productInfo.AssetTypeId)
	if not allowedAssets[assetTypeId] then
		return
	end
	
	local character = player.Character
	local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
	if humanoid == nil or humanoid.Health <= 0 then
		return
	end
	
	local success, err = pcall(function()
		items = Insert:LoadAsset(productInfo.AssetId)
	end)
	if not success then
		return warn(err)
	end
	for i, descendant in ipairs(items:GetDescendants()) do
		if descendant:IsA("LuaSourceContainer") or descendant:IsA("BackpackItem") then
			Debris:AddItem(descendant, 0)
		end
	end
	
	local characterAppearanceInfo = playerWearingAssets[player]
	local index = nil
	for i, asset in ipairs(characterAppearanceInfo.assets) do
		if asset.id == id then
			index = i
			break
		end
	end
	
	-- is there a better way to do this?
	if assetTypeId == "8" or assetTypeId == "41" or assetTypeId == "42" or assetTypeId == "43" or assetTypeId == "44" or assetTypeId == "45" or assetTypeId == "46" or assetTypeId == "47" then
		-- accessory
		local accessory = items:GetChildren()[1]
		if not accessory:IsA("Accoutrement") then
			return
		end
		if index then
			local wearing = character:FindFirstChild(accessory.Name)
			if wearing then
				Debris:AddItem(wearing, 0)
				table.remove(characterAppearanceInfo.assets, index)
			end
		elseif #humanoid:GetAccessories() < ACCESSORY_CAP then
			humanoid:AddAccessory(accessory)
			insertToTable(characterAppearanceInfo.assets, productInfo)
		end
	elseif assetTypeId == "11" or assetTypeId == "12" then
		-- clothing
		local clothing = items:GetChildren()[1]
		if not clothing:IsA("Clothing") then
			return
		end
		local wearing = character:FindFirstChildWhichIsA(clothing.ClassName)
		if wearing then
			Debris:AddItem(wearing, 0)
		end
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			getOriginalClothing(clothing.ClassName).Parent = character
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			clothing.Parent = character
		end
	elseif assetTypeId == "48" or assetTypeId == "50" or assetTypeId == "51" or assetTypeId == "52" or assetTypeId == "53" or assetTypeId == "54" or assetTypeId == "55" then
		-- animation
		local animationFolder = items:GetChildren()[1]
		local animateScript = character:FindFirstChild("Animate")
		
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			for i, value in ipairs(animationFolder:GetChildren()) do
				if animateScript:FindFirstChild(value.Name) then
					Debris:AddItem(animateScript[value.Name], 0)
				end
			end
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			if animateScript then
				for i, value in ipairs(animationFolder:GetChildren()) do
					if animateScript:FindFirstChild(value.Name) then
						Debris:AddItem(animateScript[value.Name], 0)
					end
					value.Parent = animateScript
				end
			end
		end
	elseif assetTypeId == "18" then
		-- face
		local decal = items:GetChildren()[1]
		if not decal:IsA("Decal") then
			return
		end
		local head = character:FindFirstChild("Head")
		local wearing = head and head:FindFirstChildWhichIsA("Decal")
		if wearing then
			Debris:AddItem(wearing, 0)
		end
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			player:LoadCharacterAppearance(getOriginalFace())
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			decal.Parent = head
		end
	elseif assetTypeId == "17" then
		-- head
		local mesh = items:GetChildren()[1]
		if not (mesh:IsA("SpecialMesh") or mesh:IsA("CylinderMesh")) then
			return
		end
		local head = character:FindFirstChild("Head")
		local wearing = head and head:FindFirstChildWhichIsA("SpecialMesh")
		if wearing then
			Debris:AddItem(wearing, 0)
		end
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			player:LoadCharacterAppearance(getOriginalHeadMesh())
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			player:LoadCharacterAppearance(mesh)
		end
	elseif assetTypeId == "27" or assetTypeId == "28" or assetTypeId == "29" or assetTypeId == "30" or assetTypeId == "31" then
		-- body parts
		local bodyPartFolder = items:FindFirstChild("R15ArtistIntent")
		if index then
			table.remove(characterAppearanceInfo.assets, index)
			for i, part in ipairs(bodyPartFolder:GetChildren()) do
				local partInCharacter = character:FindFirstChild(part.Name)
				local bodyPartR15 = partInCharacter and humanoid:GetBodyPartR15(partInCharacter)
				local defaultBodyPart = bodyPartR15 and defaultBodyPartsR15:FindFirstChild(part.Name)
				if defaultBodyPart then
					defaultBodyPart = defaultBodyPart:Clone()
					humanoid:ReplaceBodyPartR15(bodyPartR15, defaultBodyPart)
				end
			end
		else
			for i, asset in ipairs(characterAppearanceInfo.assets) do
				if productInfo.AssetTypeId == asset.assetType.id then
					table.remove(characterAppearanceInfo.assets, i)
				end
			end
			insertToTable(characterAppearanceInfo.assets, productInfo)
			for i, part in ipairs(bodyPartFolder:GetChildren()) do
				local partInCharacter = character:FindFirstChild(part.Name)
				local bodyPartR15 = partInCharacter and humanoid:GetBodyPartR15(partInCharacter)
				if bodyPartR15 then
					humanoid:ReplaceBodyPartR15(bodyPartR15, part)
				end
			end
		end
	end
	
	humanoid:BuildRigFromAttachments()
	Debris:AddItem(items, 0)
	remoteEvent:FireClient(player, characterAppearanceInfo)
end

local function skinTone(player, color)
	if color == nil or not (typeof(color) == "string") then
		return
	end
	if not playerWearingAssets[player] then
		return
	end
	
	local character = player.Character
	local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
	if humanoid == nil or humanoid.Health <= 0 then
		return
	end
	
	local characterAppearanceInfo = playerWearingAssets[player]
	local brickColor = BrickColor.new(color)
	characterAppearanceInfo.bodyColors.headColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.leftArmColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.leftLegColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.rightArmColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.rightLegColorId = brickColor.Number
	characterAppearanceInfo.bodyColors.torsoColorId = brickColor.Number
	
	local bodyColors = character:FindFirstChildWhichIsA("BodyColors")
	bodyColors.HeadColor3 = brickColor.Color
	bodyColors.LeftArmColor3 = brickColor.Color
	bodyColors.LeftLegColor3 = brickColor.Color
	bodyColors.RightArmColor3 = brickColor.Color
	bodyColors.RightLegColor3 = brickColor.Color
	bodyColors.TorsoColor3 = brickColor.Color
end

local function scale(player, name, value)
	if name == nil or not (typeof(name) == "string") then
		return
	end
	if value == nil or not (typeof(value) == "number") then
		return
	end
	if not playerWearingAssets[player] then
		return
	end
	
	local character = player.Character
	local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
	if humanoid == nil or humanoid.Health <= 0 then
		return
	end
	
	if name == "BodyHeightScale" then
		math.clamp(value, 95, 105)
	elseif name == "BodyWidthScale" then
		math.clamp(value, 70, 100)
	elseif name == "HeadScale" then
		math.clamp(value, 95, 100)
	elseif name == "BodyProportionScale" then
		math.clamp(value, 0, 100)
	elseif name == "BodyTypeScale" then
		math.clamp(value, 0, 100)
	else
		return
	end
	
	local scaleValue = humanoid and humanoid:FindFirstChild(name)
	if not scaleValue then
		return
	end
	
	scaleValue.Value = value/100
end