-- Server Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")

-- Configuration
local SPAWN_POSITION = Vector3.new(-15, 19, -63)
local CURRENCY_NAME = "Skira"

-- Remote Events and Functions
local PurchaseItemEvent = ReplicatedStorage:FindFirstChild("PurchaseItem") or Instance.new("RemoteEvent", ReplicatedStorage)
PurchaseItemEvent.Name = "PurchaseItem"

local IsLimitedItemAvailableFunction = ReplicatedStorage:FindFirstChild("IsLimitedItemAvailable") or Instance.new("RemoteFunction", ReplicatedStorage)
IsLimitedItemAvailableFunction.Name = "IsLimitedItemAvailable"

local LimitedItemStatusChangedEvent = ReplicatedStorage:FindFirstChild("LimitedItemStatusChanged") or Instance.new("RemoteEvent", ReplicatedStorage)
LimitedItemStatusChangedEvent.Name = "LimitedItemStatusChanged"

local GetPlayerCurrencyFunction = ReplicatedStorage:FindFirstChild("GetPlayerCurrency") or Instance.new("RemoteFunction", ReplicatedStorage)
GetPlayerCurrencyFunction.Name = "GetPlayerCurrency"

local PurchaseFeedbackEvent = ReplicatedStorage:FindFirstChild("PurchaseFeedback") or Instance.new("RemoteEvent", ReplicatedStorage)
PurchaseFeedbackEvent.Name = "PurchaseFeedback"

local GetShopItemsFunction = ReplicatedStorage:FindFirstChild("GetShopItems") or Instance.new("RemoteFunction", ReplicatedStorage)
GetShopItemsFunction.Name = "GetShopItems"

-- Shop items configuration
local ShopItems = {
	["Blahaj"] = {
		Name = "Blahaj",
		Description = "Best, softest, cutest, squishy toy!",
		Price = 35,
		Limited = false,
		New = false
	},
	["Antler"] = {
		Name = "Antler",
		Description = "Stolen antler that an employee stole after hitting a person",
		Price = 75,
		Limited = false,
		New = false
	},
	["Dynamite"] = {
		Name = "Dynamite",
		Description = "An explosive stick filled with explosive powder.",
		Price = 15,
		Limited = false,
		New = true
	},
	["ECO Bricks Package"] = {
		Name = "ECO Bricks Package",
		Description = "Eco Bricks for your needs!",
		Price = 5,
		Limited = false,
		New = false
	},
	["Glaggle ball"] = {
		Name = "Glaggle ball",
		Description = "If the earth is round, how come the ball ain't even going nowhere?",
		Price = 18,
		Limited = false,
		New = false
	},
	["Mannequin"] = {
		Name = "Mannequin",
		Description = "Has feelings, do not hurt",
		Price = 18,
		Limited = false,
		New = false
	},
	["Maxwell"] = {
		Name = "Maxwell",
		Description = "Found this random cat on the road, decided to name it Maxwell",
		Price = 18,
		Limited = true,
		New = false
	},
}

-- Table to keep track of limited items availability
local LimitedItemsAvailability = {}

-- Initialize limited items availability (1 item per limited item)
for itemName, itemData in pairs(ShopItems) do
	if itemData.Limited then
		LimitedItemsAvailability[itemName] = 1 -- Quantity available
	end
end

-- Function to check if a limited item is available
local function IsLimitedItemAvailable(player, itemName)
	local availability = LimitedItemsAvailability[itemName]
	if availability and availability > 0 then
		return true
	else
		return false
	end
end

-- Bind the RemoteFunction
IsLimitedItemAvailableFunction.OnServerInvoke = IsLimitedItemAvailable

-- Function to get player's currency
local function GetPlayerCurrency(player)
	if player:FindFirstChild("leaderstats") and player.leaderstats:FindFirstChild(CURRENCY_NAME) then
		return player.leaderstats[CURRENCY_NAME].Value
	else
		-- Initialize leaderstats if not present
		local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = player

		local currencyValue = Instance.new("IntValue")
		currencyValue.Name = CURRENCY_NAME
		currencyValue.Value = 250 -- Starting amount
		currencyValue.Parent = leaderstats

		return currencyValue.Value
	end
end

-- Bind the RemoteFunction
GetPlayerCurrencyFunction.OnServerInvoke = GetPlayerCurrency

-- Function to handle item purchases
local function HandlePurchase(player, itemName)
	if not player or not itemName then
		warn("[Shop System] Invalid purchase request")
		return
	end

	-- Validate the item
	local itemData = ShopItems[itemName]
	if not itemData then
		warn(string.format("[Shop System] Item '%s' not found in shop data", itemName))
		PurchaseFeedbackEvent:FireClient(player, "Item not found.")
		return
	end

	-- Check if the player can afford the item
	local playerCurrency = GetPlayerCurrency(player)
	if playerCurrency < itemData.Price then
		PurchaseFeedbackEvent:FireClient(player, "You don't have enough " .. CURRENCY_NAME .. " to purchase " .. itemData.Name .. ".")
		return
	end

	-- Handle limited items
	if itemData.Limited then
		local available = IsLimitedItemAvailable(player, itemName)
		if not available then
			PurchaseFeedbackEvent:FireClient(player, "Sorry, " .. itemData.Name .. " is sold out.")
			return
		else
			-- Reduce the availability count
			LimitedItemsAvailability[itemName] = LimitedItemsAvailability[itemName] - 1

			-- Notify all clients about the change in availability
			LimitedItemStatusChangedEvent:FireAllClients(itemName)
		end
	end

	-- Deduct the cost from the player's currency
	if player:FindFirstChild("leaderstats") and player.leaderstats:FindFirstChild(CURRENCY_NAME) then
		player.leaderstats[CURRENCY_NAME].Value = player.leaderstats[CURRENCY_NAME].Value - itemData.Price
	else
		warn("[Shop System] Player does not have the currency value")
		PurchaseFeedbackEvent:FireClient(player, "An error occurred while processing your purchase.")
		return
	end

	-- Spawn the item
	local spawnableItems = ReplicatedStorage:FindFirstChild("Spawnable items")
	if not spawnableItems then
		warn("[Shop System] Spawnable items folder not found")
		PurchaseFeedbackEvent:FireClient(player, "An error occurred while processing your purchase.")
		return
	end

	local spawnableItem = spawnableItems:FindFirstChild(itemData.Name)
	if not spawnableItem then
		warn(string.format("[Shop System] Failed to find item '%s' for purchase!", itemData.Name))
		PurchaseFeedbackEvent:FireClient(player, "An error occurred while processing your purchase.")
		return
	end

	-- Ensure SpawnedItems folder exists
	local spawnedItemsFolder = workspace:FindFirstChild("SpawnedItems")
	if not spawnedItemsFolder then
		spawnedItemsFolder = Instance.new("Folder")
		spawnedItemsFolder.Name = "SpawnedItems"
		spawnedItemsFolder.Parent = workspace
	end

	-- Spawn the item
	local success, newItem = pcall(function()
		local newItem = spawnableItem:Clone()
		newItem.Parent = spawnedItemsFolder

		-- Set the position of the item
		if newItem:IsA("Model") then
			if newItem.PrimaryPart then
				newItem:SetPrimaryPartCFrame(CFrame.new(SPAWN_POSITION))
			else
				-- If no PrimaryPart, move all BaseParts
				local center = newItem:GetBoundingBox().Position
				for _, part in ipairs(newItem:GetDescendants()) do
					if part:IsA("BasePart") then
						part.Position = part.Position - center + SPAWN_POSITION
					end
				end
			end
		elseif newItem:IsA("BasePart") then
			newItem.Position = SPAWN_POSITION
		else
			warn(string.format("[Shop System] Unsupported item type for '%s'", itemData.Name))
			PurchaseFeedbackEvent:FireClient(player, "An error occurred while processing your purchase.")
			return nil
		end

		return newItem
	end)

	if not success or not newItem then
		warn(string.format("[Shop System] Failed to spawn item '%s': %s", itemData.Name, tostring(newItem)))
		PurchaseFeedbackEvent:FireClient(player, "An error occurred while processing your purchase.")
	else
		print(string.format("[Shop System] Successfully spawned item '%s' for player '%s'", itemData.Name, player.Name))
		PurchaseFeedbackEvent:FireClient(player, "You have successfully purchased " .. itemData.Name .. "!")
	end
end

-- Connect the purchase event
PurchaseItemEvent.OnServerEvent:Connect(HandlePurchase)

-- Player added event to initialize currency
Players.PlayerAdded:Connect(function(player)
	-- Initialize leaderstats if not present
	if not player:FindFirstChild("leaderstats") then
		local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = player

		local currencyValue = Instance.new("IntValue")
		currencyValue.Name = CURRENCY_NAME
		currencyValue.Value = 250 -- Starting amount
		currencyValue.Parent = leaderstats
	end
end)

-- Function to provide shop items to the client
local function GetShopItems(player)
	-- Create a copy of ShopItems to send to the client
	local itemsToSend = {}
	for itemName, itemData in pairs(ShopItems) do
		-- Copy item data
		local itemCopy = {
			Name = itemData.Name,
			Description = itemData.Description,
			Price = itemData.Price,
			Limited = itemData.Limited,
			New = itemData.New
		}
		table.insert(itemsToSend, itemCopy)
	end
	return itemsToSend
end

GetShopItemsFunction.OnServerInvoke = GetShopItems

-- Client Script

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

-- Configuration
local CURRENCY_NAME = "Skira"
local CAMERA_ROTATION_SPEED = 0.1 -- Rotations per second

-- Remote Functions and Events
local PurchaseItemEvent = ReplicatedStorage:WaitForChild("PurchaseItem")
local IsLimitedItemAvailableFunction = ReplicatedStorage:WaitForChild("IsLimitedItemAvailable")
local LimitedItemStatusChangedEvent = ReplicatedStorage:WaitForChild("LimitedItemStatusChanged")
local GetPlayerCurrencyFunction = ReplicatedStorage:WaitForChild("GetPlayerCurrency")
local PurchaseFeedbackEvent = ReplicatedStorage:WaitForChild("PurchaseFeedback")
local GetShopItemsFunction = ReplicatedStorage:WaitForChild("GetShopItems")
local SkiraUpdateEvent = ReplicatedStorage:WaitForChild("SkiraUpdateEvent")

-- Variables
local ITEMS_FOLDER = ReplicatedStorage:WaitForChild("Spawnable items")
local TEMPLATE_ELEMENT = Players.LocalPlayer.PlayerGui:WaitForChild("Display").Frame.SDS.Frame.List.ItemUI
local ELEMENTS_CONTAINER = Players.LocalPlayer.PlayerGui:WaitForChild("Display").Frame.SDS.Frame.List

-- Required UI elements
local REQUIRED_UI_ELEMENTS = {
	"Name",
	"Description",
	"Optional",
	"Buy",
	"ItemDisplay"
}

-- Shop items table (will be populated from the server)
local ShopItems = {}

-- Current player currency
local playerCurrency = 0

-- Function to display warnings
local function WarnMessage(message)
	warn("[Shop System] " .. message)
end

-- Function to display messages to the player
local function DisplayMessage(message)
	-- Implement your own UI message system here
	-- For example, using a TextLabel or a notification GUI
	print("[Shop Message] " .. message)
end

-- Function to validate UI elements in the template
local function ValidateUIElement(template)
	local missingElements = {}
	for _, element in ipairs(REQUIRED_UI_ELEMENTS) do
		if not template:FindFirstChild(element) then
			table.insert(missingElements, element)
		end
	end
	if #missingElements > 0 then
		WarnMessage(string.format("Missing required UI elements: %s", table.concat(missingElements, ", ")))
		return false
	end
	return true
end

-- Function to validate shop item data
local function ValidateShopItem(itemData)
	if type(itemData) ~= "table" then
		WarnMessage("Invalid item data format")
		return false
	end
	local requiredFields = {"Name", "Description", "Price"}
	for _, field in ipairs(requiredFields) do
		if itemData[field] == nil then
			WarnMessage(string.format("Missing required field '%s' in item data", field))
			return false
		end
	end
	return true
end

-- Function to clean the item model for the viewport
local function CleanModel(model)
	local function recursiveClean(instance)
		if instance.Name == "Package" then
			instance:Destroy()
			return
		end

		if instance:IsA("Script") or 
			instance:IsA("LocalScript") or 
			instance:IsA("Sound") or 
			instance:IsA("StringValue") or 
			instance:IsA("ModuleScript") or 
			instance:IsA("RemoteEvent") or 
			instance:IsA("RemoteFunction") or 
			instance:IsA("BindableEvent") or 
			instance:IsA("BindableFunction") then
			instance:Destroy()
			return
		end

		if not (instance:IsA("Part") or 
			instance:IsA("MeshPart") or 
			instance:IsA("SpecialMesh") or 
			instance:IsA("Model") or 
			instance:IsA("Folder")) then
			instance:Destroy()
			return
		end

		for _, child in ipairs(instance:GetChildren()) do
			recursiveClean(child)
		end
	end

	recursiveClean(model)
end

-- Function to set up the item in the viewport
local function SetupItemInViewport(itemDisplay, itemModel)
	local existingViewport = itemDisplay:FindFirstChild("ViewportFrame")
	if existingViewport then
		existingViewport:Destroy()
	end

	local viewportFrame = Instance.new("ViewportFrame")
	viewportFrame.Name = "ViewportFrame"
	viewportFrame.Size = UDim2.new(1, 0, 1, 0)
	viewportFrame.BackgroundTransparency = 1
	viewportFrame.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
	viewportFrame.Parent = itemDisplay

	local camera = Instance.new("Camera")
	camera.Parent = viewportFrame
	viewportFrame.CurrentCamera = camera

	local modelClone = itemModel:Clone()
	CleanModel(modelClone)
	modelClone.Parent = viewportFrame

	local center = Vector3.new(0, 0, 0)
	local size = Vector3.new(0, 0, 0)
	if modelClone:IsA("Model") then
		local boundingCFrame, boundingSize = modelClone:GetBoundingBox()
		center = boundingCFrame.Position
		size = boundingSize
	elseif modelClone:IsA("BasePart") then
		center = modelClone.Position
		size = modelClone.Size
	end

	local maxSize = math.max(size.X, size.Y, size.Z)
	local distance = maxSize * 2
	local cameraPosition = center + Vector3.new(0, 0, distance)
	camera.CFrame = CFrame.new(cameraPosition, center)

	local startTime = tick()
	local rotationConnection
	rotationConnection = RunService.RenderStepped:Connect(function()
		if not viewportFrame.Parent or not camera.Parent then
			rotationConnection:Disconnect()
			return
		end

		local elapsed = tick() - startTime
		local angle = elapsed * (2 * math.pi * CAMERA_ROTATION_SPEED)
		local newPosition = center + Vector3.new(
			math.cos(angle) * distance,
			0,
			math.sin(angle) * distance
		)
		camera.CFrame = CFrame.new(newPosition, center)
	end)
end

-- Function to set up the initial ViewportFrame in the template
local function SetupTemplateViewport()
	local template = TEMPLATE_ELEMENT
	if not template then
		warn("Template not found!")
		return
	end

	local itemDisplay = template:FindFirstChild("ItemDisplay")
	if not itemDisplay then
		itemDisplay = Instance.new("Frame")
		itemDisplay.Name = "ItemDisplay"
		itemDisplay.Size = UDim2.new(1, 0, 1, 0)
		itemDisplay.BackgroundTransparency = 1
		itemDisplay.Parent = template
	end

	local viewportFrame = Instance.new("ViewportFrame")
	viewportFrame.Name = "ViewportFrame"
	viewportFrame.Size = UDim2.new(1, 0, 1, 0)
	viewportFrame.BackgroundTransparency = 1
	viewportFrame.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
	viewportFrame.Parent = itemDisplay

	local camera = Instance.new("Camera")
	camera.Parent = viewportFrame
	viewportFrame.CurrentCamera = camera
end

-- Function to get the player's currency
local function GetPlayerCurrency()
	if GetPlayerCurrencyFunction and GetPlayerCurrencyFunction:IsA("RemoteFunction") then
		local success, result = pcall(function()
			return GetPlayerCurrencyFunction:InvokeServer()
		end)
		if success then
			playerCurrency = result -- Update the local variable
			return result
		else
			WarnMessage("Failed to get player currency")
			return 0
		end
	else
		WarnMessage("GetPlayerCurrency RemoteFunction not found")
		return 0
	end
end

-- Function to check limited item availability
local function CheckLimitedItemAvailability(itemName)
	if IsLimitedItemAvailableFunction and IsLimitedItemAvailableFunction:IsA("RemoteFunction") then
		local success, result = pcall(function()
			return IsLimitedItemAvailableFunction:InvokeServer(itemName)
		end)
		if success then
			return result
		else
			WarnMessage("Failed to get availability for item: " .. itemName)
			return false
		end
	else
		WarnMessage("IsLimitedItemAvailable RemoteFunction not found")
		return false
	end
end

-- Function to create a shop item UI element
local function CreateShopItem(template, itemData)
	if not template then
		WarnMessage("Shop item template is nil")
		return nil
	end

	if not ValidateShopItem(itemData) then
		WarnMessage(string.format("Invalid shop item data for item: %s", itemData.Name or "Unknown"))
		return nil
	end

	if not ValidateUIElement(template) then
		WarnMessage("Template validation failed")
		return nil
	end

	local newItem = template:Clone()
	newItem.Visible = true

	-- Set the size of the newItem to a fixed height
	newItem.Size = UDim2.new(1, 0, 0, 150) -- Adjust the height as needed

	-- Set up item UI elements (Name, Description, Buy button, etc.)
	local itemDisplay = newItem:FindFirstChild("ItemDisplay")
	if itemDisplay then
		local itemModel = ITEMS_FOLDER:FindFirstChild(itemData.Name)
		if itemModel then
			SetupItemInViewport(itemDisplay, itemModel)
		else
			WarnMessage("Item model not found: " .. itemData.Name)
		end
	end

	local nameLabel = newItem:FindFirstChild("Name")
	local descriptionLabel = newItem:FindFirstChild("Description")
	local buyButton = newItem:FindFirstChild("Buy")
	local optionalLabel = newItem:FindFirstChild("Optional")

	if nameLabel then nameLabel.Text = itemData.Name end
	if descriptionLabel then descriptionLabel.Text = itemData.Description end
	if buyButton then buyButton.Text = tostring(itemData.Price) .. " " .. CURRENCY_NAME end

	if optionalLabel then
		if itemData.New then
			optionalLabel.Text = "New!"
			optionalLabel.Visible = true
		elseif itemData.Limited then
			optionalLabel.Text = "Limited"
			optionalLabel.BackgroundColor3 = Color3.new(0.690196, 0.443137, 0.145098)
			optionalLabel.Visible = true
		else
			optionalLabel.Visible = false
		end
	end

	local originalBuyButtonColor
	if buyButton then
		originalBuyButtonColor = buyButton.BackgroundColor3  -- Store the original color

		local function updateBuyButton()
			local itemAvailable = true
			if itemData.Limited then
				itemAvailable = CheckLimitedItemAvailability(itemData.Name)
			end

			if itemAvailable then
				-- Item is available
				buyButton.Text = tostring(itemData.Price) .. " " .. CURRENCY_NAME
				buyButton.Active = true
				buyButton.AutoButtonColor = true
				buyButton.BackgroundColor3 = originalBuyButtonColor
			else
				-- Item is sold out
				buyButton.Text = "Out of Stock"
				buyButton.Active = false
				buyButton.AutoButtonColor = false
				buyButton.BackgroundColor3 = Color3.fromRGB(128, 128, 128)
			end
		end

		updateBuyButton()

		-- Listen for LimitedItemStatusChangedEvent if the item is limited
		if LimitedItemStatusChangedEvent and LimitedItemStatusChangedEvent:IsA("RemoteEvent") then
			LimitedItemStatusChangedEvent.OnClientEvent:Connect(function(changedItemName, availability)
				if changedItemName == itemData.Name then
					updateBuyButton()
				end
			end)
		else
			WarnMessage("LimitedItemStatusChangedEvent not found or not a RemoteEvent")
		end

		-- Set up buy button behavior
		buyButton.MouseButton1Click:Connect(function()
			playerCurrency = GetPlayerCurrency() -- Update the local currency variable

			if playerCurrency < itemData.Price then
				-- Display message to the player that they don't have enough money
				local insufficientFundsMessage = "You don't have enough " .. CURRENCY_NAME .. " to buy " .. itemData.Name .. "."
				DisplayMessage(insufficientFundsMessage)
				return
			end

			-- For limited items, check availability again before buying
			if itemData.Limited then
				local itemAvailable = CheckLimitedItemAvailability(itemData.Name)
				if not itemAvailable then
					-- Item is sold out
					DisplayMessage("This item is sold out.")
					updateBuyButton()
					return
				end
			end

			if PurchaseItemEvent and PurchaseItemEvent:IsA("RemoteEvent") then
				PurchaseItemEvent:FireServer(itemData.Name)
				-- Optionally, disable the buy button to prevent multiple clicks
				-- buyButton.Active = false
			else
				WarnMessage("PurchaseItem RemoteEvent not found or is not a RemoteEvent")
			end
		end)
	end

	newItem.Parent = ELEMENTS_CONTAINER -- Ensure items are parented to the ScrollingFrame

	return newItem
end

-- Function to update the CanvasSize of the ScrollingFrame
local function UpdateCanvasSize()
	local layout = ELEMENTS_CONTAINER:FindFirstChildWhichIsA("UIGridStyleLayout")
	if layout then
		local contentSize = layout.AbsoluteContentSize
		local padding = ELEMENTS_CONTAINER:FindFirstChildOfClass("UIPadding")
		if padding then
			contentSize = Vector2.new(
				contentSize.X + padding.PaddingLeft.Offset + padding.PaddingRight.Offset,
				contentSize.Y + padding.PaddingTop.Offset + padding.PaddingBottom.Offset
			)
		end
		ELEMENTS_CONTAINER.CanvasSize = UDim2.new(0, contentSize.X, 0, contentSize.Y + 400)
		-- print("Updated CanvasSize to:", ELEMENTS_CONTAINER.CanvasSize) -- Debug print
	else
		print("Layout not found in ELEMENTS_CONTAINER")
	end
end

-- Function to initialize the shop
local function InitializeShop()
	local success, err = pcall(function()
		local template = TEMPLATE_ELEMENT
		if not template then
			error("Shop template not found")
		end

		SetupTemplateViewport()
		template.Visible = false

		-- Ensure a layout exists
		local layout = ELEMENTS_CONTAINER:FindFirstChildWhichIsA("UIGridStyleLayout")
		if not layout then
			layout = Instance.new("UIListLayout")
			layout.FillDirection = Enum.FillDirection.Vertical
			layout.SortOrder = Enum.SortOrder.LayoutOrder
			layout.Padding = UDim.new(0, 5)
			layout.Parent = ELEMENTS_CONTAINER
		end

		-- Add UIPadding if not present
		local padding = ELEMENTS_CONTAINER:FindFirstChildOfClass("UIPadding")
		if not padding then
			padding = Instance.new("UIPadding")
			padding.PaddingTop = UDim.new(0, 5)
			padding.PaddingBottom = UDim.new(0, 5)
			padding.PaddingLeft = UDim.new(0, 5)
			padding.PaddingRight = UDim.new(0, 5)
			padding.Parent = ELEMENTS_CONTAINER
		end

		-- Connect to changes in AbsoluteContentSize to update CanvasSize
		layout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(UpdateCanvasSize)

		-- Request shop items from the server
		if GetShopItemsFunction and GetShopItemsFunction:IsA("RemoteFunction") then
			local success, result = pcall(function()
				return GetShopItemsFunction:InvokeServer()
			end)
			if success and type(result) == "table" then
				ShopItems = result
			else
				WarnMessage("Failed to get shop items from server")
				return
			end
		else
			WarnMessage("GetShopItems RemoteFunction not found")
			return
		end

		-- Sort items: New items first, then Limited, then others
		table.sort(ShopItems, function(a, b)
			if a.New ~= b.New then
				return a.New
			elseif a.Limited ~= b.Limited then
				return a.Limited
			else
				return a.Name < b.Name
			end
		end)

		-- Populate the shop items
		for _, itemData in ipairs(ShopItems) do
			local item = CreateShopItem(template, itemData)
			if not item then
				WarnMessage(string.format("Failed to create shop item: %s", itemData.Name or "Unknown"))
			end
		end

		-- Update CanvasSize after adding items
		UpdateCanvasSize()
	end)

	if not success then
		WarnMessage(string.format("Failed to initialize shop: %s", err))
	end
end

-- Handle purchase feedback messages from the server
if PurchaseFeedbackEvent and PurchaseFeedbackEvent:IsA("RemoteEvent") then
	PurchaseFeedbackEvent.OnClientEvent:Connect(function(message)
		DisplayMessage(message)
		-- Update the player's currency display if you have one
		playerCurrency = GetPlayerCurrency()
	end)
else
	WarnMessage("PurchaseFeedbackEvent not found or not a RemoteEvent")
end

-- Handle Skira currency updates from the server
if SkiraUpdateEvent and SkiraUpdateEvent:IsA("RemoteEvent") then
	SkiraUpdateEvent.OnClientEvent:Connect(function(newSkiraAmount)
		playerCurrency = newSkiraAmount
		-- Update any currency display UI here
	end)
else
	WarnMessage("SkiraUpdateEvent not found or not a RemoteEvent")
end

InitializeShop()

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local NotificationModule = {}
local NotifyRemoteEvent = Instance.new("RemoteEvent")
NotifyRemoteEvent.Name = "NotifyRemoteEvent"
NotifyRemoteEvent.Parent = ReplicatedStorage
local iconPresets = {
    Denied = "18622635817",
    Info = "18637909884",
    Question = "18661112871",
    Success = "18637860752",
    Error = "18638286567",
    Wrench = "18653759777"
}
function NotificationModule.Notify(text, target, iconType)
    local iconId = iconPresets[iconType] or iconPresets.Info
    if target == "All" then
        NotifyRemoteEvent:FireAllClients(text, iconId)
    elseif typeof(target) == "Instance" and target:IsA("Player") then
        NotifyRemoteEvent:FireClient(target, text, iconId)
    else
        warn("Invalid target. Use 'All' or provide a specific Player instance.")
    end
end
return NotificationModule

make it so that the client script.. when buying an object.. it will say using the notificationModule inside of ReplicatedStorage "Buying {item} for {price}..." to the user then confirm or not on the server "Bought Successfully!" or "Error, something went wrong, {price} Skira Refunded" then refund the user