-- MainPluginScript.lua

local plugin = plugin

local UI = require(script.Parent.UI)
local Serializer = require(script.Parent.Serializer)
local Rechecker = require(script.Parent.Rechecker)

-- Create the UI
local uiElements = UI.createWidget(plugin)

-- Handle the button click to open/close the widget
uiElements.button.Click:Connect(function()
	uiElements.widget.Enabled = not uiElements.widget.Enabled
end)

-- Function to collect selected objects from the UI
local function getSelectedObjects()
	local selectedObjects = {}
	for _, obj in ipairs(uiElements.objectList or {}) do
		local checkboxInfo = uiElements.objectCheckboxes[obj]
		if checkboxInfo and checkboxInfo.isSelected() then
			table.insert(selectedObjects, obj)
		end
	end
	return selectedObjects
end

-- Function to collect all game objects for serialization
local function getAllGameObjects()
	local allObjects = {}

	local servicesToInclude = {
		"Workspace",
		"Lighting",
		"ReplicatedFirst",
		"ReplicatedStorage",
		"ServerScriptService",
		"ServerStorage",
		"StarterGui",
		"StarterPack",
		"StarterPlayer",
		-- Add other services as needed
	}

	for _, serviceName in ipairs(servicesToInclude) do
		local success, service = pcall(function()
			return game:GetService(serviceName)
		end)
		if success and service then
			table.insert(allObjects, service)
		else
			warn("Failed to get service:", serviceName)
		end
	end

	return allObjects
end

-- Function to handle serialization
local function onSerializeButtonClicked()
	local isAllGameConversionEnabled = uiElements.isAllGameConversionEnabled()

	local objectsToSerialize = {}

	if isAllGameConversionEnabled then
		-- Get all objects in the game
		objectsToSerialize = getAllGameObjects()
	else
		-- Get selected objects
		objectsToSerialize = getSelectedObjects()
		if #objectsToSerialize == 0 then
			warn("No objects selected for serialization.")
			uiElements.progressLabel.Text = "No objects selected for serialization."
			return
		end
	end

	print("Number of initial objects to serialize:", #objectsToSerialize)

	-- Prepare the serialization queue
	local instancesQueue = {}
	for _, obj in ipairs(objectsToSerialize) do
		table.insert(instancesQueue, obj)
	end

	local instanceMap = {}        -- Map to store instance references
	local serializedData = {}     -- List to keep serialized data
	local skippedInstances = 0    -- Count of instances that were skipped due to errors
	local totalObjectsProcessed = 0  -- We will increment this as we process instances
	local totalObjectsToProcess = #instancesQueue

	uiElements.progressLabel.Text = "Serialization in progress..."
	uiElements.progressBar.Size = UDim2.new(0, 0, 1, 0)  -- Reset progress bar

	local RunService = game:GetService("RunService")
	local startTime = tick()

	-- Function to proceed to generating reconstruction scripts
	local function proceedToGenerateScripts()
		if #serializedData == 0 then
			warn("No data was serialized. Serialization aborted.")
			uiElements.progressLabel.Text = "Serialization aborted. No data was serialized."
			return
		end

		-- Generate reconstruction scripts (multiple scripts if necessary)
		local maxScriptSize = 199000  -- Adjust as needed (Roblox's script size limit is around 200,000 characters)
		local reconstructionScriptsData = Serializer.generateReconstructionScripts(serializedData, maxScriptSize)

		-- Create the reconstruction scripts within the Plugin's parent (e.g., ServerScriptService)
		local scriptsFolder = Instance.new("Folder")
		scriptsFolder.Name = "ReconstructionScripts"
		scriptsFolder.Parent = game:GetService("ServerScriptService")  -- Placing in ServerScriptService to run on server

		-- Create a BoolValue to signal when reconstruction is complete
		local reconstructionCompleteSignal = Instance.new("BoolValue")
		reconstructionCompleteSignal.Name = "ReconstructionComplete"
		reconstructionCompleteSignal.Value = false
		reconstructionCompleteSignal.Parent = scriptsFolder

		-- Create and parent each reconstruction script
		for i, scriptData in ipairs(reconstructionScriptsData) do
			local reconstructionScript = Instance.new("Script")
			reconstructionScript.Name = "ReconstructionScript_" .. tostring(i)
			reconstructionScript.Source = scriptData.Source
			reconstructionScript.Disabled = false  -- Enable script
			reconstructionScript.Parent = scriptsFolder
		end

		-- Wait for deserialization to complete
		local deserializationStartTime = tick()
		local maxWaitTime = 600  -- Maximum wait time in seconds (adjust as needed)
		local deserializationComplete = false

		while not deserializationComplete and (tick() - deserializationStartTime) < maxWaitTime do
			RunService.Heartbeat:Wait()
			deserializationComplete = reconstructionCompleteSignal.Value
		end

		if deserializationComplete then
			print("Deserialization complete. Game is ready to load.")
		else
			warn("Deserialization did not complete within the expected time.")
		end

		-- Display time taken
		local endTime = tick()
		local duration = endTime - startTime
		local minutes = math.floor(duration / 60)
		local seconds = duration % 60
		uiElements.progressLabel.Text = string.format("Serialization complete in %d minutes, %.2f seconds.", minutes, seconds)
		uiElements.progressBar.Size = UDim2.new(1, 0, 1, 0)  -- Fill progress bar

		-- Notify user that serialization is complete
		print("Serialization complete. Reconstruction scripts have been generated.")
		if skippedInstances > 0 then
			print(skippedInstances .. " instances were skipped due to errors.")
		end
	end

	-- Serialize instances
	local function serializeNextInstance(onComplete)
		if #instancesQueue == 0 then
			-- Serialization complete
			if onComplete then
				onComplete()
			end
		else
			local instancesPerFrame = 20  -- Adjust this number as needed
			local count = 0

			while count < instancesPerFrame and #instancesQueue > 0 do
				count = count + 1
				local instance = table.remove(instancesQueue, 1)

				-- Serialize the instance
				local success, errorMsg = pcall(function()
					Serializer.serializeInstance(instance, instanceMap, serializedData, instancesQueue)
				end)

				if not success then
					skippedInstances = skippedInstances + 1
					warn("Failed to serialize instance: " .. tostring(instance:GetFullName()) .. ". Error: " .. tostring(errorMsg))
				end

				totalObjectsProcessed = totalObjectsProcessed + 1

				-- Update progress in UI
				local progressPercentage = math.floor((totalObjectsProcessed / totalObjectsToProcess) * 100)
				uiElements.progressLabel.Text = string.format("Serializing... %d%% complete", progressPercentage)
				uiElements.progressBar.Size = UDim2.new(totalObjectsProcessed / totalObjectsToProcess, 0, 1, 0)
			end

			-- Schedule next batch after yielding
			RunService.Heartbeat:Wait()
			serializeNextInstance(onComplete)
		end
	end

	-- Start the serialization process
	serializeNextInstance(function()
		-- After serialization is complete
		-- Proceed to generate reconstruction scripts
		proceedToGenerateScripts()
	end)
end

-- Connect the serialize button in the UI to the function
uiElements.serializeButton.MouseButton1Click:Connect(onSerializeButtonClicked) MainPluginScript -- ScriptGenerator.lua

local ScriptGenerator = {}
local HttpService = game:GetService("HttpService")

function ScriptGenerator.getScriptTemplate()
	local scriptTemplate = [[
-- Reconstruction Script - Part CHUNK_INDEX of TOTAL_CHUNKS

local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")

_G.instanceRegistry = _G.instanceRegistry or {}
_G.parentDataMap = _G.parentDataMap or {}
local instanceRegistry = _G.instanceRegistry
local parentDataMap = _G.parentDataMap

local propertiesToSkip = {
        ["ClassName"] = true,
        ["Parent"] = true,
        ["Archivable"] = true,
}

local function recreateValue(value)
        if type(value) == "table" and value.__type then
                local valueType = value.__type
                if valueType == "EnumItem" then
                        local enumFullName = value.Value
                        local enumTypeName, enumName = enumFullName:match("Enum%.(%w+)%.(.+)")
                        if enumTypeName and enumName then
                                return Enum[enumTypeName][enumName]
                        else
                                warn("Failed to reconstruct EnumItem:", value.Value)
                                return nil
                        end
                elseif valueType == "BrickColor" then
                        return BrickColor.new(value.Number)
                elseif valueType == "Color3" then
                        return Color3.new(value.R, value.G, value.B)
                elseif valueType == "Vector3" then
                        return Vector3.new(value.X, value.Y, value.Z)
                elseif valueType == "Vector2" then
                        return Vector2.new(value.X, value.Y)
                elseif valueType == "CFrame" then
                        return CFrame.new(unpack(value.Components))
                elseif valueType == "UDim2" then
                        return UDim2.new(value.XScale, value.XOffset, value.YScale, value.YOffset)
                elseif valueType == "UDim" then
                        return UDim.new(value.Scale, value.Offset)
                elseif valueType == "NumberRange" then
                        return NumberRange.new(value.Min, value.Max)
                elseif valueType == "NumberSequence" then
                        local keypoints = {}
                        for _, kp in ipairs(value.Keypoints) do
                                table.insert(keypoints, NumberSequenceKeypoint.new(kp.Time, kp.Value, kp.Envelope))
                        end
                        return NumberSequence.new(keypoints)
                elseif valueType == "ColorSequence" then
                        local keypoints = {}
                        for _, kp in ipairs(value.Keypoints) do
                                local color = Color3.new(kp.Value.R, kp.Value.G, kp.Value.B)
                                table.insert(keypoints, ColorSequenceKeypoint.new(kp.Time, color))
                        end
                        return ColorSequence.new(keypoints)
                elseif valueType == "Rect" then
                        return Rect.new(value.Min.X, value.Min.Y, value.Max.X, value.Max.Y)
                elseif valueType == "PhysicalProperties" then
                        return PhysicalProperties.new(value.Density, value.Friction, value.Elasticity, value.FrictionWeight, value.ElasticityWeight)
                elseif valueType == "Font" then
                        return Font.new(value.Family, Enum.FontWeight[value.Weight], Enum.FontStyle[value.Style])
                elseif valueType == "Faces" then
                        -- Reconstruct Faces from table of booleans
                        local faces = {}
                        for face, included in pairs(value) do
                                if included then
                                        table.insert(faces, Enum.NormalId[face])
                                end
                        end
                        return Faces.new(unpack(faces))
                elseif valueType == "Axes" then
                        -- Reconstruct Axes from table of booleans
                        local axes = {}
                        for axis, included in pairs(value) do
                                if included then
                                        table.insert(axes, Enum.Axis[axis])
                                end
                        end
                        return Axes.new(unpack(axes))
                elseif valueType == "Instance" then
                        return instanceRegistry[value.__ref]
                else
                        return nil
                end
        else
                return value
        end
end

local function deserializeInstance(data)
        local instance

        -- Handle non-creatable classes
        local nonCreatableClasses = {
                Workspace = function() return game:GetService("Workspace") end,
                Terrain = function() return workspace.Terrain end,
                Lighting = function() return game:GetService("Lighting") end,
                Players = function() return game:GetService("Players") end,
                ReplicatedFirst = function() return game:GetService("ReplicatedFirst") end,
                ReplicatedStorage = function() return game:GetService("ReplicatedStorage") end,
                ServerScriptService = function() return game:GetService("ServerScriptService") end,
                ServerStorage = function() return game:GetService("ServerStorage") end,
                StarterGui = function() return game:GetService("StarterGui") end,
                StarterPack = function() return game:GetService("StarterPack") end,
                StarterPlayer = function() return game:GetService("StarterPlayer") end,
                -- Add other non-creatable classes as needed
        }

        local getInstanceFunction = nonCreatableClasses[data.ClassName]
        if getInstanceFunction then
                instance = getInstanceFunction()
        elseif data.ClassName == "UnionOperation" then
                -- Reconstruct UnionOperation as MeshPart using CreateMeshPartAsync
                local meshData = data.MeshData
                if meshData then
                        local vertices = {}
                        for _, v in ipairs(meshData.Vertices) do
                                table.insert(vertices, Vector3.new(v.X, v.Y, v.Z))
                        end
                        local indices = meshData.Indices
                        local normals = {}
                        for _, n in ipairs(meshData.Normals) do
                                table.insert(normals, Vector3.new(n.X, n.Y, n.Z))
                        end
                        local uvs = {}
                        for _, uv in ipairs(meshData.UVs) do
                                table.insert(uvs, Vector2.new(uv.X, uv.Y))
                        end

                        -- Use pcall to catch any errors in CreateMeshPartAsync
                        local successCreate, meshPartOrError = pcall(function()
                                return Instance.CreateMeshPartAsync({
                                        Vertices = vertices,
                                        Indices = indices,
                                        Normals = normals,
                                        UVs = uvs,
                                        Material = Enum.SurfaceType.Smooth,
                                })
                        end)

                        if successCreate then
                                instance = meshPartOrError
                        else
                                warn("Failed to create MeshPart from mesh data:", meshPartOrError)
                                return nil
                        end

                        -- Apply properties
                        instance.CFrame = recreateValue(data.CFrame)
                        instance.Color = recreateValue(data.Color)
                        instance.Size = recreateValue(data.Size)
                        instance.Material = recreateValue(data.Material)
                        instance.Transparency = data.Transparency
                        instance.Reflectance = data.Reflectance
                        instance.CastShadow = data.CastShadow
                        instance.CollisionFidelity = Enum.CollisionFidelity[data.CollisionFidelity]
                        instance.UsePartColor = data.UsePartColor
                else
                        warn("Mesh data missing for UnionOperation")
                        return nil
                end
        else
                local success, result = pcall(function()
                        return Instance.new(data.ClassName)
                end)
                if success then
                        instance = result
                else
                        warn("Failed to create instance of class:", data.ClassName, "-", result)
                        return nil
                end
        end

        instanceRegistry[data.__id] = instance

        -- Set properties (excluding Parent)
        for property, value in pairs(data.Properties or {}) do
                if not propertiesToSkip[property] then
                        local recreatedValue = recreateValue(value)
                        local successProp, errorMsg = pcall(function()
                                instance[property] = recreatedValue
                        end)
                        if not successProp then
                                warn("Failed to set property:", property, "on instance:", instance.Name, "-", errorMsg)
                        end
                end
        end

        -- Set attributes
        if data.Attributes then
                for attribute, value in pairs(data.Attributes) do
                        local recreatedValue = recreateValue(value)
                        local successAttr, errorMsg = pcall(function()
                                instance:SetAttribute(attribute, recreatedValue)
                        end)
                        if not successAttr then
                                warn("Failed to set attribute:", attribute, "on instance:", instance.Name, "-", errorMsg)
                        end
                end
        end

        -- Store parent data for later parenting
        parentDataMap[instance] = data
end

local function attemptToSetParents()
        local unresolved = {}
        for instance, data in pairs(parentDataMap) do
                local parentInstance = nil
                local canSetParent = true

                if data.ParentId then
                        parentInstance = instanceRegistry[data.ParentId]
                        if parentInstance then
                                -- Avoid setting Parent of non-parentable instances
                                if instance == workspace.Terrain or instance:IsA("Terrain") then
                                        canSetParent = false
                                end
                                if canSetParent then
                                        instance.Parent = parentInstance
                                else
                                        unresolved[instance] = data
                                end
                        else
                                unresolved[instance] = data  -- Parent not yet available
                        end
                elseif data.ParentIsGame then
                        if instance == workspace.Terrain or instance:IsA("Terrain") then
                                canSetParent = false
                        end
                        if canSetParent then
                                instance.Parent = game
                        end
                elseif data.ParentIsService and data.ParentClassName then
                        parentInstance = game:GetService(data.ParentClassName)
                        if parentInstance then
                                -- Avoid setting Parent of non-parentable instances
                                if instance == workspace.Terrain or instance:IsA("Terrain") then
                                        canSetParent = false
                                end
                                if canSetParent then
                                        instance.Parent = parentInstance
                                end
                        else
                                warn("Service not found:", data.ParentClassName)
                        end
                elseif data.ParentName and data.ParentClassName then
                        local service = game:GetService(data.ParentClassName)
                        if service then
                                parentInstance = service:FindFirstChild(data.ParentName)
                                if parentInstance then
                                        -- Avoid setting Parent of non-parentable instances
                                        if instance == workspace.Terrain or instance:IsA("Terrain") then
                                                canSetParent = false
                                        end
                                        if canSetParent then
                                                instance.Parent = parentInstance
                                        else
                                                unresolved[instance] = data
                                        end
                                else
                                        unresolved[instance] = data  -- Parent not found yet
                                end
                        else
                                warn("Service not found:", data.ParentClassName)
                        end
                else
                        -- Default parent
                        if instance == workspace.Terrain or instance:IsA("Terrain") then
                                canSetParent = false
                        end
                        if canSetParent then
                                instance.Parent = workspace
                        end
                end
        end
        parentDataMap = unresolved
end

-- Data string assignment
DATA_STRING_ASSIGNMENT

local data = HttpService:JSONDecode(dataString)

-- Deserialize instances
local totalInstances = #data
local currentIndex = 1

local function deserializeBatch()
        local batchSize = 10  -- Adjust as needed
        local endIndex = math.min(currentIndex + batchSize - 1, totalInstances)
        for i = currentIndex, endIndex do
                local instanceData = data[i]
                deserializeInstance(instanceData)
        end
        currentIndex = endIndex + 1
        if currentIndex <= totalInstances then
                RunService.Heartbeat:Wait()
                deserializeBatch()
        else
                -- All instances created, now set parents
                attemptToSetParents()
                -- Retry setting parents for unresolved instances
                for attempt = 1, 10 do
                        if next(parentDataMap) then
                                RunService.Heartbeat:Wait()
                                attemptToSetParents()
                        else
                                break
                        end
                end
                if next(parentDataMap) then
                        for instance, data in pairs(parentDataMap) do
                                warn("Unresolved parent for instance:", instance.Name)
                                -- Avoid setting Parent of non-parentable instances
                                if instance ~= workspace.Terrain and not instance:IsA("Terrain") then
                                        instance.Parent = workspace  -- Assign to workspace as fallback
                                end
                        end
                end

                -- Clean up shared data
                _G.instanceRegistry = nil
                _G.parentDataMap = nil
                print("Deserialization complete.")

                -- Signal that deserialization is complete
                local reconstructionCompleteSignal = script.Parent:FindFirstChild("ReconstructionComplete")
                if reconstructionCompleteSignal then
                        reconstructionCompleteSignal.Value = true
                end
        end
end

-- Start deserialization
deserializeBatch()
]]

	return scriptTemplate
end

function ScriptGenerator.generateScript(chunkIndex, totalChunks, dataChunk)
	local scriptTemplate = ScriptGenerator.getScriptTemplate()

	-- Prepare the data string assignment
	local dataStringAssignment = 'local dataString = ' .. string.format('%q', dataChunk)
	-- Escape any '%' in dataStringAssignment
	dataStringAssignment = dataStringAssignment:gsub("%%", "%%%%")

	-- Replace placeholders in the script template
	scriptTemplate = scriptTemplate:gsub("CHUNK_INDEX", tostring(chunkIndex))
	scriptTemplate = scriptTemplate:gsub("TOTAL_CHUNKS", tostring(totalChunks))
	scriptTemplate = scriptTemplate:gsub("DATA_STRING_ASSIGNMENT", dataStringAssignment)

	return scriptTemplate
end

function ScriptGenerator.generateReconstructionScripts(serializedData, maxScriptSize)
	local scripts = {}

	local dataSet = serializedData

	local dataChunks = {}
	local totalInstances = #dataSet
	local index = 1

	-- Get the script template for size estimation
	local emptyDataString = 'local dataString = ""'
	local scriptTemplateWithoutData = ScriptGenerator.getScriptTemplate()
	-- Replace placeholders with sample values
	scriptTemplateWithoutData = scriptTemplateWithoutData:gsub("DATA_STRING_ASSIGNMENT", emptyDataString)
	scriptTemplateWithoutData = scriptTemplateWithoutData:gsub("CHUNK_INDEX", "1")
	scriptTemplateWithoutData = scriptTemplateWithoutData:gsub("TOTAL_CHUNKS", "1")

	-- Estimate base script size
	local baseScriptSize = #scriptTemplateWithoutData

	local dataChunk = {}
	local dataSize = 0

	while index <= totalInstances do
		local instanceData = dataSet[index]
		local instanceDataString = HttpService:JSONEncode(instanceData)
		local instanceDataSize = #instanceDataString

		local tempDataChunk = { table.unpack(dataChunk) }
		table.insert(tempDataChunk, instanceData)
		local dataStringAssignmentSize = #('local dataString = ' .. string.format('%q', HttpService:JSONEncode(tempDataChunk)))

		local estimatedScriptSize = baseScriptSize - #('local dataString = ""') + dataStringAssignmentSize

		if estimatedScriptSize > maxScriptSize then
			if #dataChunk == 0 then
				-- Single instance too large to fit into a script, skip it
				warn("Instance at index " .. index .. " is too large to fit into a script and will be skipped.")
				index = index + 1
			else
				-- Finalize current dataChunk
				table.insert(dataChunks, dataChunk)
				-- Reset dataChunk and dataSize
				dataChunk = {}
				dataSize = 0
			end
		else
			-- Add instanceData to dataChunk
			dataChunk = tempDataChunk
			dataSize = dataSize + instanceDataSize
			index = index + 1
		end
	end

	-- Add any remaining dataChunk
	if #dataChunk > 0 then
		table.insert(dataChunks, dataChunk)
	end

	local totalChunks = #dataChunks

	-- Now generate scripts
	for chunkIndex, dataChunk in ipairs(dataChunks) do
		local dataString = HttpService:JSONEncode(dataChunk)
		local scriptSource = ScriptGenerator.generateScript(chunkIndex, totalChunks, dataString)
		table.insert(scripts, { Source = scriptSource })
	end

	return scripts
end

return ScriptGenerator ScriptGenerator Module -- Serializer.lua

local Serializer = {}

local HttpService = game:GetService("HttpService")
local ScriptGenerator = require(script.Parent.ScriptGenerator)
local RobloxApiDump = require(script.Parent.RobloxApiDump)

-- Function to serialize a value
function Serializer.serializeValue(value, instanceMap, serializedData, instancesQueue)
	local valueType = typeof(value)

	-- Handle unsupported types
	local unsupportedTypes = {
		["function"] = true,
		["userdata"] = true,
		["RBXScriptConnection"] = true,
		["RBXScriptSignal"] = true,
		["thread"] = true,
	}

	if unsupportedTypes[valueType] then
		return nil
	end

	-- Handle specific types
	if valueType == "EnumItem" then
		return { __type = "EnumItem", Value = tostring(value) }
	elseif valueType == "BrickColor" then
		return { __type = "BrickColor", Number = value.Number }
	elseif valueType == "Color3" then
		return { __type = "Color3", R = value.R, G = value.G, B = value.B }
	elseif valueType == "Vector3" then
		return { __type = "Vector3", X = value.X, Y = value.Y, Z = value.Z }
	elseif valueType == "Vector2" then
		return { __type = "Vector2", X = value.X, Y = value.Y }
	elseif valueType == "CFrame" then
		return { __type = "CFrame", Components = { value:GetComponents() } }
	elseif valueType == "UDim2" then
		return { __type = "UDim2", XScale = value.X.Scale, XOffset = value.X.Offset, YScale = value.Y.Scale, YOffset = value.Y.Offset }
	elseif valueType == "UDim" then
		return { __type = "UDim", Scale = value.Scale, Offset = value.Offset }
	elseif valueType == "NumberRange" then
		return { __type = "NumberRange", Min = value.Min, Max = value.Max }
	elseif valueType == "NumberSequence" then
		local keypoints = {}
		for _, keypoint in ipairs(value.Keypoints) do
			table.insert(keypoints, { Time = keypoint.Time, Value = keypoint.Value, Envelope = keypoint.Envelope })
		end
		return { __type = "NumberSequence", Keypoints = keypoints }
	elseif valueType == "ColorSequence" then
		local keypoints = {}
		for _, keypoint in ipairs(value.Keypoints) do
			table.insert(keypoints, {
				Time = keypoint.Time,
				Value = { R = keypoint.Value.R, G = keypoint.Value.G, B = keypoint.Value.B },
			})
		end
		return { __type = "ColorSequence", Keypoints = keypoints }
	elseif valueType == "Rect" then
		return { __type = "Rect", Min = { X = value.Min.X, Y = value.Min.Y }, Max = { X = value.Max.X, Y = value.Max.Y } }
	elseif valueType == "PhysicalProperties" then
		return {
			__type = "PhysicalProperties",
			Density = value.Density,
			Friction = value.Friction,
			Elasticity = value.Elasticity,
			FrictionWeight = value.FrictionWeight,
			ElasticityWeight = value.ElasticityWeight,
		}
	elseif valueType == "Font" then
		return {
			__type = "Font",
			Family = value.Family,
			Weight = tostring(value.Weight),
			Style = tostring(value.Style),
		}
	elseif valueType == "Faces" then
		-- Serialize Faces as a table of booleans
		return {
			__type = "Faces",
			Top = value.Top,
			Bottom = value.Bottom,
			Left = value.Left,
			Right = value.Right,
			Front = value.Front,
			Back = value.Back,
		}
	elseif valueType == "Axes" then
		-- Serialize Axes as a table of booleans
		return {
			__type = "Axes",
			X = value.X,
			Y = value.Y,
			Z = value.Z,
		}
	elseif valueType == "Instance" then
		-- Handle instance references
		if instanceMap[value] then
			-- Reference to a serialized instance
			return { __type = "Instance", __ref = instanceMap[value] }
		else
			-- The instance has not been serialized yet
			-- We need to serialize it now
			local success, err = pcall(function()
				Serializer.serializeInstance(value, instanceMap, serializedData, instancesQueue)
			end)
			if success then
				return { __type = "Instance", __ref = instanceMap[value] }
			else
				-- Could not serialize the instance; return nil or handle appropriately
				warn("Failed to serialize instance reference:", tostring(value), "-", err)
				return nil
			end
		end
	else
		-- For basic types like string, number, boolean, Content, etc.
		return value
	end
end

-- Function to serialize an instance
function Serializer.serializeInstance(instance, instanceMap, serializedData, instancesQueue)
	-- Early exit if instance is already processed
	if instanceMap[instance] then
		return
	end

	-- Exclude instances that should not be serialized
	if instance == game or instance:IsA("CoreScript") then
		return
	end

	local success, className = pcall(function()
		return instance.ClassName
	end)

	if not success then
		warn("Failed to get ClassName for instance:", tostring(instance))
		return
	end

	-- Generate a unique ID for the instance
	local instanceId = HttpService:GenerateGUID(false)
	instanceMap[instance] = instanceId

	local serialized = {
		ClassName = className,
		__id = instanceId,
		Properties = {},
		Attributes = {},
	}

	-- Special handling for UnionOperation
	if className == "UnionOperation" then
		-- Use GetMeshData to retrieve mesh data
		local successMeshData, meshData = pcall(function()
			return instance:GetMeshData()
		end)
		if not successMeshData then
			warn("Failed to get mesh data for UnionOperation:", instance:GetFullName(), "-", meshData)
			return
		end

		-- Store the mesh data in the serialized data
		-- Be cautious of data size
		serialized.MeshData = {
			Vertices = meshData.Vertices,
			Indices = meshData.Indices,
			Normals = meshData.Normals,
			UVs = meshData.UVs,
		}

		-- Store other properties
		serialized.ClassName = "UnionOperation"
		serialized.CFrame = Serializer.serializeValue(instance.CFrame, instanceMap, serializedData, instancesQueue)
		serialized.Size = Serializer.serializeValue(instance.Size, instanceMap, serializedData, instancesQueue)
		serialized.Color = Serializer.serializeValue(instance.Color, instanceMap, serializedData, instancesQueue)
		serialized.Material = Serializer.serializeValue(instance.Material, instanceMap, serializedData, instancesQueue)
		serialized.Transparency = instance.Transparency
		serialized.Reflectance = instance.Reflectance
		serialized.CastShadow = instance.CastShadow
		serialized.CollisionFidelity = tostring(instance.CollisionFidelity)
		serialized.UsePartColor = instance.UsePartColor

		-- Serialize attributes
		local successAttr, attributes = pcall(function()
			return instance:GetAttributes()
		end)
		if successAttr and attributes then
			for attributeName, attributeValue in pairs(attributes) do
				local serializedAttributeValue = Serializer.serializeValue(attributeValue, instanceMap, serializedData, instancesQueue)
				if serializedAttributeValue ~= nil then
					serialized.Attributes[attributeName] = serializedAttributeValue
				end
			end
		else
			warn("Failed to get attributes for instance:", tostring(instance))
		end

		-- Handle parent
		local successParent, parent = pcall(function()
			return instance.Parent
		end)
		if successParent and parent then
			if instanceMap[parent] then
				-- Parent is a serialized instance
				serialized.ParentId = instanceMap[parent]
			else
				-- Parent is an external instance or service
				if parent == game then
					serialized.ParentIsGame = true
				else
					-- Attempt to get service if parent is a service
					local successService, parentService = pcall(game.GetService, game, parent.ClassName)
					if successService and parentService == parent then
						serialized.ParentIsService = true
						serialized.ParentClassName = parent.ClassName
					else
						serialized.ParentName = parent.Name
						serialized.ParentClassName = parent.ClassName
					end
				end
			end
		else
			-- Instance has no parent; default to game during deserialization
			serialized.ParentIsGame = true
		end

		-- Add serialized data to the list
		table.insert(serializedData, serialized)

		-- Handle children
		local canAccess, children = pcall(function()
			return instance:GetChildren()
		end)
		if canAccess and children then
			for _, child in ipairs(children) do
				if not instanceMap[child] then
					table.insert(instancesQueue, child)
				end
			end
		end
	else
		-- Regular instance serialization

		local properties = Serializer.getSerializableProperties(instance)
		for _, propertyData in ipairs(properties) do
			local propertyName = propertyData.Name

			if propertyName ~= "Parent" then
				local successProp, value = pcall(function()
					return instance[propertyName]
				end)
				if successProp then
					local serializedValue = Serializer.serializeValue(value, instanceMap, serializedData, instancesQueue)
					if serializedValue ~= nil then
						serialized.Properties[propertyName] = serializedValue
					else
						-- Handle serialization failure of property value
						warn("Property value could not be serialized:", propertyName, "on instance:", instance:GetFullName())
					end
				else
					-- Handle property get errors gracefully
					warn("Failed to get property:", propertyName, "on instance:", tostring(instance))
				end
			end
		end

		-- Serialize attributes
		local successAttr, attributes = pcall(function()
			return instance:GetAttributes()
		end)
		if successAttr and attributes then
			for attributeName, attributeValue in pairs(attributes) do
				local serializedAttributeValue = Serializer.serializeValue(attributeValue, instanceMap, serializedData, instancesQueue)
				if serializedAttributeValue ~= nil then
					serialized.Attributes[attributeName] = serializedAttributeValue
				end
			end
		else
			warn("Failed to get attributes for instance:", tostring(instance))
		end

		-- Handle parent
		local successParent, parent = pcall(function()
			return instance.Parent
		end)
		if successParent and parent then
			if instanceMap[parent] then
				-- Parent is a serialized instance
				serialized.ParentId = instanceMap[parent]
			else
				-- Parent is an external instance or service
				if parent == game then
					serialized.ParentIsGame = true
				else
					-- Attempt to get service if parent is a service
					local successService, parentService = pcall(game.GetService, game, parent.ClassName)
					if successService and parentService == parent then
						serialized.ParentIsService = true
						serialized.ParentClassName = parent.ClassName
					else
						serialized.ParentName = parent.Name
						serialized.ParentClassName = parent.ClassName
					end
				end
			end
		else
			-- Instance has no parent; default to game during deserialization
			serialized.ParentIsGame = true
		end

		-- Add serialized data to the list
		table.insert(serializedData, serialized)

		-- Handle children
		local canAccess, children = pcall(function()
			return instance:GetChildren()
		end)
		if canAccess and children then
			for _, child in ipairs(children) do
				if not instanceMap[child] then
					table.insert(instancesQueue, child)
				end
			end
		end
	end
end

-- Function to get serializable properties of an instance
function Serializer.getSerializableProperties(instance)
	local properties = {}
	local className = instance.ClassName
	local classData = RobloxApiDump.Classes[className]

	-- Define collectProperties function
	local function collectProperties(clsData)
		if not clsData then
			-- No class data provided
			return
		end

		-- Recursively collect properties from superclass
		if clsData.Superclass and RobloxApiDump.Classes[clsData.Superclass] then
			collectProperties(RobloxApiDump.Classes[clsData.Superclass])
		end

		-- Process properties
		if clsData.Properties then
			for _, propertyData in ipairs(clsData.Properties) do
				local propertyName = propertyData.Name

				-- Filter out properties based on security and attributes
				local isNotBrowsable = false
				local deprecated = false
				local attributes = propertyData.Attributes or {}

				for _, attribute in ipairs(attributes) do
					if attribute == "NotBrowsable" then
						isNotBrowsable = true
					elseif attribute == "Deprecated" then
						deprecated = true
					end
				end

				-- Include properties that are readable at script security level
				local canRead = propertyData.Security and (propertyData.Security.Read == "None" or propertyData.Security.Read == "PluginSecurity")
				if canRead and not isNotBrowsable and not deprecated then
					table.insert(properties, propertyData)
				end
			end
		end
	end

	if classData then
		collectProperties(classData)
	else
		-- If class data is not available, use default properties
		properties = {
			{ Name = "Name", Security = { Read = "None" } },
			{ Name = "Archivable", Security = { Read = "None" } },
			-- Add other common properties if needed
		}
	end

	return properties
end

-- Function to generate reconstruction scripts
function Serializer.generateReconstructionScripts(serializedData, maxScriptSize)
	-- Use the ScriptGenerator to generate the scripts
	local scripts = ScriptGenerator.generateReconstructionScripts(serializedData, maxScriptSize)
	return scripts
end

-- Function to handle missing instances during serialization
function Serializer.handleMissingInstances(missingInstances, instanceMap, serializedData, instancesQueue)
	for _, instance in ipairs(missingInstances) do
		if not instanceMap[instance] then
			table.insert(instancesQueue, instance)
		end
	end
end

return Serializer serializer module  make sure meshparts are converted to special mesh since roblox doesnt allow meshpart convertion  so they can be included in the generated instances, but makesure it looks like the visual appearance as the same  as the meshpart with the meshid, etc    make a rendering for it. and send full code