local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")

local WELD_OFFSET = CFrame.new(0, 1, 0.5)

local function createWeldConstraint(part0, part1)
	assert(part0 and part1, "createWeldConstraint: Invalid parts")
	local weld = Instance.new("WeldConstraint")
	weld.Part0 = part0
	weld.Part1 = part1
	weld.Parent = part0
end

local function createMotor6D(part0, part1, name, parent)
	assert(part0 and part1, "createMotor6D: Invalid parts")
	local motor6D = Instance.new("Motor6D")
	motor6D.Part0 = part0
	motor6D.Part1 = part1
	motor6D.Name = name
	motor6D.C1 = WELD_OFFSET
	motor6D.Parent = parent or part0
end

local function weldAllParts(parentPart, primaryPart)
	assert(parentPart and primaryPart, "weldAllParts: Invalid parts")
	for _, childPart in parentPart:GetChildren() do
		if childPart:IsA("BasePart") then
			createWeldConstraint(childPart, primaryPart)
		elseif childPart:IsA("Model") then
			weldAllParts(childPart, primaryPart)
		end
	end
end

local function calculateOffsets(parts, basePartName)
	local offsets = {}
	local basePart = parts[basePartName]
	if basePart and basePart.PrimaryPart then
		for _, part in parts do
			if part.PrimaryPart then
				offsets[part.Name] = part.PrimaryPart.Position - basePart.PrimaryPart.Position
			end
		end
	end
	return offsets
end

local function setPartsCFrame(parts, torso, offsets)
	for name, part in parts do
		if part.PrimaryPart and offsets[name] then
			part:SetPrimaryPartCFrame(torso.CFrame * CFrame.new(offsets[name]))
		end
	end
end

local function weldPartHierarchy(parts, torso, staticName)
	local offsets = calculateOffsets(parts, staticName)
	local staticPart = parts[staticName]
	if staticPart and staticPart.PrimaryPart then
		staticPart:SetPrimaryPartCFrame(torso.CFrame)
		createWeldConstraint(staticPart.PrimaryPart, torso)
		for name, part in parts do
			if name ~= staticName then
				local middlePart = part:FindFirstChild("Middle")
				local colorPart = part:FindFirstChild("colorPartName")
				if name == "Orbs" or name == "Rod" then
					if middlePart then
						for _, childPart in part:GetChildren() do
							if childPart:IsA("BasePart") and childPart ~= middlePart then
								createWeldConstraint(childPart, middlePart)
							end
						end
					end
				else
					if middlePart and colorPart then
						createWeldConstraint(colorPart, middlePart)
						createWeldConstraint(middlePart, staticPart.PrimaryPart)
						weldAllParts(part, middlePart)
					end
				end
			end
		end
		setPartsCFrame(parts, torso, offsets)
	end
end

local function handleMorph(morphTo, category, torso, Character)
	local function getMorphParts(morph)
		local parts = {}
		for _, partName in {"LowerL", "LowerR", "LowerStatic", "UpperL", "UpperR", "UpperStatic", "LowerStaticB", "LowerStaticA", "Orbs", "Rod"} do
			parts[partName] = morph:FindFirstChild(partName)
		end
		return parts
	end

	morphTo = ServerStorage.Morphs[category][morphTo]
	if morphTo then
		for _, folder in ServerStorage.Morphs[category]:GetChildren() do
			local existingFolder = Character:FindFirstChild(folder.Name)
			if existingFolder then
				existingFolder:Destroy()
			end
		end

		local cloneMorph = morphTo:Clone()
		local parts = getMorphParts(cloneMorph)

		if category == "Ass" then
			for _, partName in {"LowerL", "LowerR"} do
				local colorPart = parts[partName] and parts[partName]:FindFirstChild("color5")
				if colorPart then
					colorPart.Color = torso.Color
				end
			end
			weldPartHierarchy(parts, torso, "LowerStatic")
		elseif category == "Chest" then
			weldPartHierarchy(parts, torso, "UpperStatic")
		elseif category == "Pussy" then
			if parts.LowerStaticB and torso then
				parts.LowerStaticB:SetPrimaryPartCFrame(torso.CFrame)
				createWeldConstraint(parts.LowerStaticB.PrimaryPart, torso)
				weldAllParts(parts.LowerStaticB, parts.LowerStaticB.PrimaryPart)
			else
				warn("LowerStaticB or its PrimaryPart not found or set")
			end
		elseif category == "Penis" then
			if parts.Orbs and parts.Orbs.PrimaryPart then
				createMotor6D(torso, parts.Orbs.PrimaryPart, "Motor6D_Orbs", parts.Orbs)
			end
			if parts.Rod and parts.Rod.PrimaryPart then
				createMotor6D(torso, parts.Rod.PrimaryPart, "Motor6D_Rod", parts.Rod)
			end
			weldPartHierarchy(parts, torso, "LowerStaticA")
		end

		cloneMorph.Parent = Character
	else
		warn("Morph not found for category: " .. category .. ", morph: " .. morphTo)
	end
end

ReplicatedStorage.RemoteEvents.MorphRequest.OnServerEvent:Connect(function(player, morph, category)
	assert(player and morph and category, "Invalid morph request parameters")
	local Character = player.Character
	local torso = Character and (Character:FindFirstChild("Torso") or Character:FindFirstChild("UpperTorso"))

	handleMorph(morph, category, torso, Character)
end)


chest parts fall off. i think they don't get properly weldconstraints.