-- BuildGUI Studio Plugin MVP
-- Paste a BUILDGUI/1 transfer code from buildgui.com, then import it into StarterGui.

assert(plugin, "BuildGUI must run as a Roblox Studio plugin")

local ChangeHistoryService = game:GetService("ChangeHistoryService")
local HttpService = game:GetService("HttpService")
local Selection = game:GetService("Selection")
local StarterGui = game:GetService("StarterGui")

local toolbar = plugin:CreateToolbar("BuildGUI")
local toolbarButton = toolbar:CreateButton("BuildGUI", "Import editable BuildGUI interfaces", "")
toolbarButton.ClickableWhenViewportHidden = true

local info = DockWidgetPluginGuiInfo.new(
	Enum.InitialDockState.Right,
	false,
	false,
	360,
	520,
	300,
	400
)
local widget = plugin:CreateDockWidgetPluginGuiAsync("BuildGUIImporterV1", info)
widget.Title = "BuildGUI · Studio Import"

local COLORS = {
	background = Color3.fromRGB(12, 18, 30),
	surface = Color3.fromRGB(19, 29, 46),
	surface2 = Color3.fromRGB(27, 41, 64),
	line = Color3.fromRGB(48, 65, 92),
	text = Color3.fromRGB(240, 247, 255),
	muted = Color3.fromRGB(142, 157, 180),
	accent = Color3.fromRGB(72, 214, 255),
	success = Color3.fromRGB(54, 211, 153),
	danger = Color3.fromRGB(255, 111, 125),
}

local function corner(parent, radius)
	local value = Instance.new("UICorner")
	value.CornerRadius = UDim.new(0, radius or 8)
	value.Parent = parent
	return value
end

local function stroke(parent, color, thickness, transparency)
	local value = Instance.new("UIStroke")
	value.Color = color or COLORS.line
	value.Thickness = thickness or 1
	value.Transparency = transparency or 0
	value.Parent = parent
	return value
end

local function label(parent, text, size, bold)
	local value = Instance.new("TextLabel")
	value.BackgroundTransparency = 1
	value.Text = text or ""
	value.TextColor3 = COLORS.text
	value.Font = bold and Enum.Font.GothamBold or Enum.Font.Gotham
	value.TextSize = size or 13
	value.TextWrapped = true
	value.Parent = parent
	return value
end

local root = Instance.new("Frame")
root.Size = UDim2.fromScale(1, 1)
root.BackgroundColor3 = COLORS.background
root.BorderSizePixel = 0
root.Parent = widget

local padding = Instance.new("UIPadding")
padding.PaddingTop = UDim.new(0, 18)
padding.PaddingBottom = UDim.new(0, 18)
padding.PaddingLeft = UDim.new(0, 18)
padding.PaddingRight = UDim.new(0, 18)
padding.Parent = root

local layout = Instance.new("UIListLayout")
layout.Padding = UDim.new(0, 10)
layout.SortOrder = Enum.SortOrder.LayoutOrder
layout.Parent = root

local brand = label(root, "BUILDGUI", 11, true)
brand.LayoutOrder = 1
brand.Size = UDim2.new(1, 0, 0, 18)
brand.TextColor3 = COLORS.accent
brand.TextXAlignment = Enum.TextXAlignment.Left

local title = label(root, "Ship editable UI to Studio", 20, true)
title.LayoutOrder = 2
title.Size = UDim2.new(1, 0, 0, 50)
title.TextXAlignment = Enum.TextXAlignment.Left

local description = label(root, "On buildgui.com, choose “Copy Studio transfer code.” Paste it below. No HTTP permission or account is required.", 12, false)
description.LayoutOrder = 3
description.Size = UDim2.new(1, 0, 0, 58)
description.TextColor3 = COLORS.muted
description.TextXAlignment = Enum.TextXAlignment.Left
description.TextYAlignment = Enum.TextYAlignment.Top

local input = Instance.new("TextBox")
input.Name = "TransferCode"
input.LayoutOrder = 4
input.Size = UDim2.new(1, 0, 0, 180)
input.BackgroundColor3 = COLORS.surface
input.BorderSizePixel = 0
input.ClearTextOnFocus = false
input.MultiLine = true
input.Text = ""
input.PlaceholderText = "BUILDGUI/1\n{\"type\":\"main_menu\", ...}"
input.PlaceholderColor3 = Color3.fromRGB(93, 109, 134)
input.TextColor3 = COLORS.text
input.Font = Enum.Font.Code
input.TextSize = 12
input.TextWrapped = true
input.TextXAlignment = Enum.TextXAlignment.Left
input.TextYAlignment = Enum.TextYAlignment.Top
corner(input, 9)
stroke(input)
local inputPadding = Instance.new("UIPadding")
inputPadding.PaddingTop = UDim.new(0, 11)
inputPadding.PaddingBottom = UDim.new(0, 11)
inputPadding.PaddingLeft = UDim.new(0, 11)
inputPadding.PaddingRight = UDim.new(0, 11)
inputPadding.Parent = input
input.Parent = root

local importButton = Instance.new("TextButton")
importButton.LayoutOrder = 5
importButton.Size = UDim2.new(1, 0, 0, 44)
importButton.BackgroundColor3 = COLORS.accent
importButton.BorderSizePixel = 0
importButton.Text = "IMPORT INTO STARTERGUI"
importButton.TextColor3 = Color3.fromRGB(5, 14, 24)
importButton.Font = Enum.Font.GothamBold
importButton.TextSize = 13
corner(importButton, 9)
importButton.Parent = root

local status = label(root, "Ready for a BuildGUI transfer code.", 11, false)
status.LayoutOrder = 6
status.Size = UDim2.new(1, 0, 0, 40)
status.TextColor3 = COLORS.muted
status.TextXAlignment = Enum.TextXAlignment.Left
status.TextYAlignment = Enum.TextYAlignment.Top

local undoButton = Instance.new("TextButton")
undoButton.LayoutOrder = 7
undoButton.Size = UDim2.new(1, 0, 0, 36)
undoButton.BackgroundColor3 = COLORS.surface2
undoButton.BorderSizePixel = 0
undoButton.Text = "Undo last Studio change"
undoButton.TextColor3 = COLORS.muted
undoButton.Font = Enum.Font.GothamMedium
undoButton.TextSize = 11
corner(undoButton, 8)
stroke(undoButton)
undoButton.Parent = root

local supported = label(root, "SUPPORTED · Shop · Inventory · HUD · Main Menu · Settings · Codes", 9, true)
supported.LayoutOrder = 8
supported.Size = UDim2.new(1, 0, 0, 30)
supported.TextColor3 = Color3.fromRGB(87, 103, 128)
supported.TextXAlignment = Enum.TextXAlignment.Left

local function fromHex(value, fallback)
	if type(value) ~= "string" or not value:match("^#%x%x%x%x%x%x$") then
		return fallback
	end
	return Color3.fromHex(value)
end

local function sanitizeName(value, fallback)
	value = tostring(value or fallback or "Element")
	value = value:gsub("[^%w_ ]", ""):gsub("%s+", "")
	return value ~= "" and value:sub(1, 40) or (fallback or "Element")
end

local function makeText(parent, className, name, text)
	local value = Instance.new(className)
	value.Name = name
	value.BackgroundTransparency = 1
	value.Text = tostring(text or "")
	value.TextColor3 = Color3.new(1, 1, 1)
	value.Font = Enum.Font.GothamBold
	value.TextSize = 15
	value.TextWrapped = true
	value.Parent = parent
	return value
end

local function makePanel(spec, guiName, width)
	local theme = type(spec.theme) == "table" and spec.theme or {}
	local accent = fromHex(theme.accent, COLORS.accent)
	local background = fromHex(theme.bg, Color3.fromRGB(17, 26, 42))
	local cell = fromHex(theme.cell, Color3.fromRGB(27, 41, 64))
	local radius = math.clamp(tonumber(theme.corner) or 12, 0, 24)
	local panelOpacity = math.clamp(tonumber(theme.panel_opacity) or 1, 0.55, 1)

	local gui = Instance.new("ScreenGui")
	gui.Name = guiName
	gui.ResetOnSpawn = false
	gui.IgnoreGuiInset = true
	gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
	gui:SetAttribute("BuildGUIVersion", 1)
	gui:SetAttribute("BuildGUIType", spec.type)

	local panel = Instance.new("Frame")
	panel.Name = "Panel"
	panel.AnchorPoint = Vector2.new(0.5, 0.5)
	panel.Position = UDim2.fromScale(0.5, 0.5)
	panel.Size = UDim2.new(0, width or 390, 0, 0)
	panel.AutomaticSize = Enum.AutomaticSize.Y
	panel.BackgroundColor3 = background
	panel.BackgroundTransparency = 1 - panelOpacity
	panel.BorderSizePixel = 0
	panel.Parent = gui
	corner(panel, radius)
	stroke(panel, accent, 2)

	local panelPadding = Instance.new("UIPadding")
	panelPadding.PaddingTop = UDim.new(0, 16)
	panelPadding.PaddingBottom = UDim.new(0, 16)
	panelPadding.PaddingLeft = UDim.new(0, 16)
	panelPadding.PaddingRight = UDim.new(0, 16)
	panelPadding.Parent = panel

	local panelLayout = Instance.new("UIListLayout")
	panelLayout.Padding = UDim.new(0, 10)
	panelLayout.SortOrder = Enum.SortOrder.LayoutOrder
	panelLayout.Parent = panel

	return gui, panel, accent, background, cell
end

local function addController(gui, name, source)
	local scriptObject = Instance.new("LocalScript")
	scriptObject.Name = name
	scriptObject.Source = source
	scriptObject.Parent = gui
end

local function buildShop(spec)
	local gui, panel, accent, _, cell = makePanel(spec, "ShopGui", 470)
	local titleLabel = makeText(panel, "TextLabel", "Title", spec.title or "Shop")
	titleLabel.LayoutOrder = 1
	titleLabel.Size = UDim2.new(1, 0, 0, 34)
	titleLabel.TextSize = 24

	local items = Instance.new("Frame")
	items.Name = "Items"
	items.LayoutOrder = 2
	items.Size = UDim2.new(1, 0, 0, 210)
	items.BackgroundTransparency = 1
	items.Parent = panel
	local grid = Instance.new("UIGridLayout")
	grid.CellSize = UDim2.new(0.31, 0, 0, 96)
	grid.CellPadding = UDim2.new(0.03, 0, 0, 8)
	grid.HorizontalAlignment = Enum.HorizontalAlignment.Center
	grid.SortOrder = Enum.SortOrder.LayoutOrder
	grid.Parent = items

	for index, item in ipairs(type(spec.items) == "table" and spec.items or {}) do
		if index > 12 then break end
		local button = Instance.new("TextButton")
		button.Name = sanitizeName(item.label, "Item" .. index)
		button.LayoutOrder = index
		button.BackgroundColor3 = cell
		button.BorderSizePixel = 0
		button.Text = (item.icon and tostring(item.icon) .. "\n" or "") .. tostring(item.label or "Item") .. "\n" .. tostring(item.price or "")
		button.TextColor3 = Color3.new(1, 1, 1)
		button.Font = Enum.Font.GothamBold
		button.TextSize = 14
		button.TextWrapped = true
		button:SetAttribute("Price", tostring(item.price or ""))
		corner(button, 9)
		button.Parent = items
	end

	local close = Instance.new("TextButton")
	close.Name = "CloseButton"
	close.LayoutOrder = 3
	close.Size = UDim2.new(1, 0, 0, 40)
	close.BackgroundColor3 = accent
	close.BorderSizePixel = 0
	close.Text = tostring(spec.close and spec.close.label or "Close")
	close.TextColor3 = Color3.new(1, 1, 1)
	close.Font = Enum.Font.GothamBold
	close.TextSize = 16
	corner(close, 8)
	close.Parent = panel
	addController(gui, "ShopController", [[
local gui=script.Parent
local panel=gui:WaitForChild("Panel")
panel.CloseButton.MouseButton1Click:Connect(function() gui.Enabled=false end)
for _,button in ipairs(panel.Items:GetChildren()) do
	if button:IsA("TextButton") then button.MouseButton1Click:Connect(function()
		print("[BuildGUI Shop]",button.Name,button:GetAttribute("Price"))
	end) end
end]])
	return gui
end

local function buildInventory(spec)
	local gui, panel, _, _, cell = makePanel(spec, "InventoryGui", 420)
	local titleLabel = makeText(panel, "TextLabel", "Title", spec.title or "Inventory")
	titleLabel.LayoutOrder = 1
	titleLabel.Size = UDim2.new(1, 0, 0, 34)
	titleLabel.TextSize = 24
	local slots = Instance.new("Frame")
	slots.Name = "Slots"
	slots.LayoutOrder = 2
	slots.Size = UDim2.new(1, 0, 0, 170)
	slots.BackgroundTransparency = 1
	slots.Parent = panel
	local grid = Instance.new("UIGridLayout")
	grid.CellSize = UDim2.fromOffset(72, 72)
	grid.CellPadding = UDim2.fromOffset(8, 8)
	grid.HorizontalAlignment = Enum.HorizontalAlignment.Center
	grid.Parent = slots
	for index, item in ipairs(type(spec.slots) == "table" and spec.slots or {}) do
		if index > 16 then break end
		local className = item.empty and "Frame" or "TextButton"
		local slot = Instance.new(className)
		slot.Name = item.empty and ("Empty" .. index) or sanitizeName(item.label, "Item" .. index)
		slot.BackgroundColor3 = cell
		slot.BackgroundTransparency = item.empty and 0.45 or 0
		slot.BorderSizePixel = 0
		if slot:IsA("TextButton") then
			slot.Text = tostring(item.icon or "◇") .. ((tonumber(item.qty) or 1) > 1 and ("\n×" .. tostring(item.qty)) or "")
			slot.TextColor3 = Color3.new(1, 1, 1)
			slot.Font = Enum.Font.GothamBold
			slot.TextSize = 22
		end
		corner(slot, 8)
		slot.Parent = slots
	end
	local close = Instance.new("TextButton")
	close.Name = "CloseButton"
	close.LayoutOrder = 3
	close.Size = UDim2.new(1, 0, 0, 38)
	close.BackgroundTransparency = 1
	close.Text = tostring(spec.close and spec.close.label or "Close")
	close.TextColor3 = COLORS.text
	close.Font = Enum.Font.GothamBold
	close.Parent = panel
	addController(gui, "InventoryController", [[
local gui=script.Parent
gui.Panel.CloseButton.MouseButton1Click:Connect(function() gui.Enabled=false end)]])
	return gui
end

local function buildHud(spec)
	local gui, panel, _, _, cell = makePanel(spec, "PlayerHud", 300)
	panel.AnchorPoint = Vector2.new(0, 1)
	panel.Position = UDim2.new(0, 16, 1, -16)
	local titleLabel = makeText(panel, "TextLabel", "PlayerName", spec.title or "Player")
	titleLabel.LayoutOrder = 1
	titleLabel.Size = UDim2.new(1, 0, 0, 30)
	titleLabel.TextXAlignment = Enum.TextXAlignment.Left
	local bars = Instance.new("Frame")
	bars.Name = "Bars"
	bars.LayoutOrder = 2
	bars.Size = UDim2.new(1, 0, 0, 0)
	bars.AutomaticSize = Enum.AutomaticSize.Y
	bars.BackgroundTransparency = 1
	bars.Parent = panel
	local list = Instance.new("UIListLayout")
	list.Padding = UDim.new(0, 8)
	list.Parent = bars
	for index, item in ipairs(type(spec.bars) == "table" and spec.bars or {}) do
		if index > 4 then break end
		local row = Instance.new("Frame")
		row.Name = sanitizeName(item.label, "Bar" .. index)
		row.Size = UDim2.new(1, 0, 0, 34)
		row.BackgroundTransparency = 1
		row.Parent = bars
		local nameLabel = makeText(row, "TextLabel", "BarName", item.label or "Stat")
		nameLabel.Size = UDim2.new(1, 0, 0, 15)
		nameLabel.TextSize = 12
		nameLabel.TextXAlignment = Enum.TextXAlignment.Left
		local track = Instance.new("Frame")
		track.Name = "Track"
		track.Position = UDim2.new(0, 0, 0, 20)
		track.Size = UDim2.new(1, 0, 0, 11)
		track.BackgroundColor3 = cell
		track.BorderSizePixel = 0
		corner(track, 6)
		track.Parent = row
		local fill = Instance.new("Frame")
		fill.Name = "Fill"
		local maximum = math.max(tonumber(item.max) or 100, 1)
		fill.Size = UDim2.new(math.clamp((tonumber(item.value) or 0) / maximum, 0, 1), 0, 1, 0)
		fill.BackgroundColor3 = fromHex(item.color, COLORS.danger)
		fill.BorderSizePixel = 0
		corner(fill, 6)
		fill.Parent = track
	end
	addController(gui, "HudController", "-- Bind these bars to your real player stats.")
	return gui
end

local function buildAction(spec)
	local guiName = spec.type == "main_menu" and "MainMenuGui" or spec.type == "settings_panel" and "SettingsGui" or "CodesGui"
	local gui, panel, accent, _, cell = makePanel(spec, guiName, 360)
	local titleLabel = makeText(panel, "TextLabel", "Title", spec.title or "MENU")
	titleLabel.LayoutOrder = 1
	titleLabel.Size = UDim2.new(1, 0, 0, 38)
	titleLabel.TextSize = 26
	if spec.subtitle then
		local subtitle = makeText(panel, "TextLabel", "Subtitle", spec.subtitle)
		subtitle.LayoutOrder = 2
		subtitle.Size = UDim2.new(1, 0, 0, 22)
		subtitle.TextColor3 = COLORS.muted
		subtitle.TextSize = 12
	end

	if spec.type == "codes_panel" then
		local codeInput = Instance.new("TextBox")
		codeInput.Name = "CodeInput"
		codeInput.LayoutOrder = 3
		codeInput.Size = UDim2.new(1, 0, 0, 44)
		codeInput.BackgroundColor3 = cell
		codeInput.BorderSizePixel = 0
		codeInput.PlaceholderText = tostring(spec.placeholder or "ENTER CODE")
		codeInput.Text = ""
		codeInput.TextColor3 = COLORS.text
		codeInput.Font = Enum.Font.GothamBold
		codeInput.TextSize = 14
		corner(codeInput, 9)
		codeInput.Parent = panel
		local redeem = Instance.new("TextButton")
		redeem.Name = "RedeemButton"
		redeem.LayoutOrder = 4
		redeem.Size = UDim2.new(1, 0, 0, 44)
		redeem.BackgroundColor3 = accent
		redeem.BorderSizePixel = 0
		redeem.Text = tostring(spec.button_label or "REDEEM")
		redeem.TextColor3 = Color3.fromRGB(5, 14, 24)
		redeem.Font = Enum.Font.GothamBold
		corner(redeem, 9)
		redeem.Parent = panel
	else
		local rows = Instance.new("Frame")
		rows.Name = "Rows"
		rows.LayoutOrder = 3
		rows.Size = UDim2.new(1, 0, 0, 0)
		rows.AutomaticSize = Enum.AutomaticSize.Y
		rows.BackgroundTransparency = 1
		rows.Parent = panel
		local rowsLayout = Instance.new("UIListLayout")
		rowsLayout.Padding = UDim.new(0, 8)
		rowsLayout.Parent = rows
		local sourceRows = spec.type == "main_menu" and spec.actions or spec.toggles
		for index, item in ipairs(type(sourceRows) == "table" and sourceRows or {}) do
			if index > 8 then break end
			local text = tostring(item.label or "Action")
			if spec.type == "settings_panel" then text ..= "     " .. (item.enabled == false and "OFF" or "ON") end
			local button = Instance.new("TextButton")
			button.Name = sanitizeName(item.label, "Action" .. index)
			button.Size = UDim2.new(1, 0, 0, 44)
			button.BackgroundColor3 = cell
			button.BorderSizePixel = 0
			button.Text = text
			button.TextColor3 = COLORS.text
			button.Font = Enum.Font.GothamBold
			button.TextSize = 14
			corner(button, 9)
			button.Parent = rows
		end
	end
	addController(gui, "BuildGUIController", "-- Connect these native controls to your game systems.")
	return gui
end

local builders = {
	shop_panel = buildShop,
	inventory_grid = buildInventory,
	status_hud = buildHud,
	main_menu = buildAction,
	settings_panel = buildAction,
	codes_panel = buildAction,
}

local function decodeTransfer(raw)
	if type(raw) ~= "string" then return nil, "Transfer code is missing." end
	raw = raw:gsub("^%s+", "")
	if raw:sub(1, 11) ~= "BUILDGUI/1\n" then
		return nil, "Expected a BUILDGUI/1 transfer code."
	end
	if #raw > 100000 then return nil, "Transfer code is too large." end
	local ok, spec = pcall(HttpService.JSONDecode, HttpService, raw:sub(12))
	if not ok or type(spec) ~= "table" then return nil, "The transfer JSON is invalid." end
	if type(spec.type) ~= "string" or not builders[spec.type] then return nil, "Unsupported or missing GUI type." end
	return spec
end

local function setStatus(message, kind)
	status.Text = message
	status.TextColor3 = kind == "success" and COLORS.success or kind == "error" and COLORS.danger or COLORS.muted
end

local busy = false
importButton.MouseButton1Click:Connect(function()
	if busy then return end
	busy = true
	importButton.Text = "IMPORTING…"
	local spec, decodeError = decodeTransfer(input.Text)
	if not spec then
		setStatus(decodeError, "error")
		importButton.Text = "IMPORT INTO STARTERGUI"
		busy = false
		return
	end

	local recording = ChangeHistoryService:TryBeginRecording("Import BuildGUI interface")
	if not recording then
		setStatus("Studio is already recording another plugin change. Try again.", "error")
		importButton.Text = "IMPORT INTO STARTERGUI"
		busy = false
		return
	end

	local ok, result = pcall(builders[spec.type], spec)
	if not ok or not result then
		ChangeHistoryService:FinishRecording(recording, Enum.FinishRecordingOperation.Cancel)
		setStatus("Import failed: " .. tostring(result), "error")
		importButton.Text = "IMPORT INTO STARTERGUI"
		busy = false
		return
	end

	local existing = StarterGui:FindFirstChild(result.Name)
	if existing and existing:GetAttribute("BuildGUIVersion") then existing:Destroy() end
	result.Parent = StarterGui
	Selection:Set({ result })
	ChangeHistoryService:FinishRecording(recording, Enum.FinishRecordingOperation.Commit)
	plugin:SetSetting("BuildGUI.LastType", spec.type)
	setStatus("Imported " .. result.Name .. ". It is selected in StarterGui and can be undone.", "success")
	importButton.Text = "IMPORTED ✓"
	task.delay(1.4, function()
		importButton.Text = "IMPORT INTO STARTERGUI"
		busy = false
	end)
end)

undoButton.MouseButton1Click:Connect(function()
	if ChangeHistoryService:GetCanUndo() then
		ChangeHistoryService:Undo()
		setStatus("Undid the last Studio change.", "success")
	else
		setStatus("There is no Studio change to undo.", "error")
	end
end)

toolbarButton.Click:Connect(function()
	widget.Enabled = not widget.Enabled
end)

widget:BindToClose(function()
	widget.Enabled = false
end)
