require(game.ReplicatedFirst.ReadyModule)
local shopGui = script.Parent
_G.ShopGui = shopGui
local shopFrame = shopGui.Items
local shopMaterial = shopGui.CashLabel
local shopBackButton = shopGui.BackButton
local shopSearch = shopGui.Search

-- Parts
local partsStore = _G.Storage:WaitForChild("Parts")
local namedFrames = {}
local directNamedFrames = {}
local folders = {}
local currentFolder = partsStore
local currentTerm = ""

local function createItemFrame(item)
	local defaultFrame = shopFrame.Grid.ItemFrame
	defaultFrame.Visible = false
	
	-- Create ViewportFrame and put a camera in
	local itemFrame = defaultFrame:Clone()
	itemFrame.Parent = shopFrame
	itemFrame.ItemLabel.Text = item:GetAttribute("Name") or item.Name
	itemFrame.Visible = true
	if not item:HasTag("ConnectorObject") then itemFrame.PolyLabel:Destroy() end
	itemFrame.NewLabel:Destroy()
	itemFrame.Name = item:GetAttribute("Name") or item.Name

	local viewportFrame = itemFrame.ViewportFrame

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

	viewportFrame.CurrentCamera = camera

	item = item:Clone()
	item.Parent = viewportFrame
	item:PivotTo(item:GetAttribute("Rotation") or CFrame.identity)
	local distance
	local cameraRotation = 45
	if item:IsA("BasePart") then
		distance = item.Size.Magnitude
	elseif item:IsA("Model") then
		if not item.PrimaryPart then 
			warn(item:GetFullName().." has no PrimaryPart, please set one!")
			item.PrimaryPart = item:FindFirstChildWhichIsA("BasePart")
		end
		distance = item:GetExtentsSize().Magnitude
	end

	local function rotateCamera()
		camera.CFrame = CFrame.fromEulerAnglesYXZ(-0.8,math.rad(cameraRotation),0)
		camera.CFrame = camera.CFrame + camera.CFrame.LookVector * -(distance/1.2)
	end
	rotateCamera()

	local mouseInside = false
	viewportFrame.MouseEnter:Connect(function()
		mouseInside = true
		viewportFrame.BackgroundColor3 = Color3.new(0.75,0.75,0.75)
		while wait() and mouseInside do
			cameraRotation = cameraRotation + 0.33
			rotateCamera()
		end
	end)
	viewportFrame.MouseLeave:Connect(function() mouseInside = false viewportFrame.BackgroundColor3 = Color3.new(1,1,1) end)
	
	return itemFrame
end

local function clearItems()
	for _,item in pairs(shopFrame:GetChildren()) do
		if item:IsA("Frame") then
			item.Parent = nil -- Now is this a good idea or not...
		end
	end
end

local f = string.find
local l = string.lower
local function loadSearch(term)
	clearItems()
	wait()
	term = l(term)
	for _,info in pairs(namedFrames) do
		if f(l(info[1]),term,1,true) then -- A crude search if anything
			info[2].Parent = shopFrame
		end
	end
	for _,info in pairs(directNamedFrames) do
		if f(l(info[1]),term,1,true) then -- A crude search if anything
			info[2].Parent = shopFrame
		end
	end
end

shopSearch.FocusLost:Connect(function(enter, inputObject)
	if enter then
		-- add a quick enter
	end
end)

local function loadFolder(folder)
	currentFolder = folder
	clearItems()
	wait()
	for _,frame in pairs(folders[folder]) do
		frame.Parent = shopFrame
	end
end

shopSearch.Changed:Connect(function()
	if currentTerm == shopSearch.Text then return end
	currentTerm = shopSearch.Text
	if #shopSearch.Text > 0 then
		loadSearch(shopSearch.Text)
	else
		loadFolder(currentFolder)
	end
end)

local existing = {}
local t = 200
local function registerItem(item)
	if existing[item] then return end
	existing[item] = true
	if item:HasTag("DoNotPlace") then return end
	local isFolder = item:IsA("Folder")
	local isPart = item.Parent:IsA("Folder") and (item:IsA("Model") or item:IsA("BasePart"))
	if isFolder or isPart then
		local model = item
		if isFolder then
			local smallestOrder = t+1
			local smallestItem
			for _,child in pairs(item:GetDescendants()) do
				if not (child.Parent:IsA("Folder") and (child:IsA("BasePart") or child:IsA("Model"))) then continue end
				local order = child:GetAttribute("Order") or t
				if order < smallestOrder then smallestOrder = order smallestItem = child end
			end
			model = smallestItem
		end
		if not model then warn(item:GetFullName().." has no children.") return end
		local frame = createItemFrame(model)
		frame.LayoutOrder = item:GetAttribute("Order") or t 
		folders[item.Parent] = folders[item.Parent] or {} -- Make sure the folder exists
		table.insert(folders[item.Parent],frame)
		if isPart then
			if item:GetAttribute("Name") then table.insert(namedFrames,{item:GetAttribute("Name"),frame}) end
			table.insert(directNamedFrames,{item.Name,frame})
			frame.InputEnded:Connect(function(inputObject)
				if inputObject.UserInputType == Enum.UserInputType.MouseButton1 or inputObject.UserInputType == Enum.UserInputType.Touch then
					_G.Events.Pick:Fire(item)
					if item.Parent:IsA("Folder") and item.Parent:HasTag("AutoBack") then
						loadFolder(item.Parent.Parent)
					end
				end
			end)
		else
			frame.ItemLabel.Text = item.Name 
			frame.InputEnded:Connect(function(inputObject)
				if inputObject.UserInputType == Enum.UserInputType.MouseButton1 or inputObject.UserInputType == Enum.UserInputType.Touch then
					loadFolder(item)
				end
			end)
		end
	end
end

local function loadStore()
	for _,item in pairs(partsStore:GetDescendants()) do
		registerItem(item)
	end
	loadFolder(currentFolder)
end

shopBackButton.MouseButton1Click:Connect(function()
	local parent = currentFolder.Parent
	if currentFolder == partsStore then parent = partsStore end
	loadFolder(parent)
end)

loadStore()