local HttpService = game:GetService("HttpService")
local ChangeHistoryService = game:GetService("ChangeHistoryService")
local ServerScriptService = game:GetService("ServerScriptService")
local StarterPlayer = game:GetService("StarterPlayer")
local StarterGui = game:GetService("StarterGui")
local Workspace = game:GetService("Workspace")

local toolbar = plugin:CreateToolbar("dRoblox")
local openButton = toolbar:CreateButton(
	"dRoblox",
	"dRoblox ile Roblox oyunu tasarla ve Studio'ya ekle",
	"rbxassetid://14978048121"
)
openButton.ClickableWhenViewportHidden = true

local widgetInfo = DockWidgetPluginGuiInfo.new(
	Enum.InitialDockState.Right,
	false,
	false,
	390,
760,
	340,
700
)
local widget = plugin:CreateDockWidgetPluginGui("OyunAtolyeAIStudio", widgetInfo)
widget.Title = "dRoblox AI"

local function make(className, properties, parent)
	local object = Instance.new(className)
	for property, value in pairs(properties) do
		object[property] = value
	end
	object.Parent = parent
	return object
end

local panel = make("Frame", {
	BackgroundColor3 = Color3.fromRGB(20, 20, 29),
	BorderSizePixel = 0,
	Size = UDim2.fromScale(1, 1),
}, widget)

local padding = make("UIPadding", {
	PaddingTop = UDim.new(0, 17),
	PaddingBottom = UDim.new(0, 15),
	PaddingLeft = UDim.new(0, 16),
	PaddingRight = UDim.new(0, 16),
}, panel)

local layout = make("UIListLayout", {
	FillDirection = Enum.FillDirection.Vertical,
	SortOrder = Enum.SortOrder.LayoutOrder,
	Padding = UDim.new(0, 9),
}, panel)

local title = make("TextLabel", {
	BackgroundTransparency = 1,
	Size = UDim2.new(1, 0, 0, 30),
	Font = Enum.Font.GothamBold,
	Text = "dRoblox",
	TextColor3 = Color3.fromRGB(241, 236, 255),
	TextSize = 21,
	TextXAlignment = Enum.TextXAlignment.Left,
	LayoutOrder = 1,
}, panel)

local subtitle = make("TextLabel", {
	BackgroundTransparency = 1,
	Size = UDim2.new(1, 0, 0, 34),
	Font = Enum.Font.Gotham,
	Text = "Fikrini yaz; Gemini başlangıç sahnesini ve Luau scriptlerini hazırlasın.",
	TextColor3 = Color3.fromRGB(168, 165, 181),
	TextSize = 12,
	TextWrapped = true,
	TextXAlignment = Enum.TextXAlignment.Left,
	LayoutOrder = 2,
}, panel)

local endpointLabel = make("TextLabel", {
	BackgroundTransparency = 1,
	Size = UDim2.new(1, 0, 0, 17),
	Font = Enum.Font.GothamSemibold,
	Text = "SİTENİN ADRESİ",
	TextColor3 = Color3.fromRGB(166, 151, 211),
	TextSize = 10,
	TextXAlignment = Enum.TextXAlignment.Left,
	LayoutOrder = 3,
}, panel)

local endpointBox = make("TextBox", {
	BackgroundColor3 = Color3.fromRGB(29, 29, 41),
	BorderColor3 = Color3.fromRGB(57, 54, 70),
	ClearTextOnFocus = false,
	Font = Enum.Font.Gotham,
	PlaceholderText = "https://proje-adin.pages.dev",
	Size = UDim2.new(1, 0, 0, 36),
	Text = plugin:GetSetting("OyunAtolyeApiUrl") or "",
	TextColor3 = Color3.fromRGB(236, 233, 245),
	TextSize = 11,
	TextXAlignment = Enum.TextXAlignment.Left,
	LayoutOrder = 4,
}, panel)
make("UIPadding", { PaddingLeft = UDim.new(0, 10), PaddingRight = UDim.new(0, 8) }, endpointBox)

local promptLabel = make("TextLabel", {
	BackgroundTransparency = 1,
	Size = UDim2.new(1, 0, 0, 17),
	Font = Enum.Font.GothamSemibold,
	Text = "OYUN FİKRİN",
	TextColor3 = Color3.fromRGB(166, 151, 211),
	TextSize = 10,
	TextXAlignment = Enum.TextXAlignment.Left,
	LayoutOrder = 5,
}, panel)

local promptBox = make("TextBox", {
	BackgroundColor3 = Color3.fromRGB(17, 17, 25),
	BorderColor3 = Color3.fromRGB(57, 54, 70),
	ClearTextOnFocus = false,
	Font = Enum.Font.Gotham,
	MultiLine = true,
	PlaceholderText = "Örnek: Oyuncuların coin topladığı, puanın ekranda gösterildiği bir obby oyunu yap.",
	Size = UDim2.new(1, 0, 0, 122),
	Text = "",
	TextColor3 = Color3.fromRGB(236, 233, 245),
	TextSize = 12,
	TextWrapped = true,
	TextXAlignment = Enum.TextXAlignment.Left,
	TextYAlignment = Enum.TextYAlignment.Top,
	LayoutOrder = 6,
}, panel)
make("UIPadding", {
	PaddingTop = UDim.new(0, 9),
	PaddingBottom = UDim.new(0, 8),
	PaddingLeft = UDim.new(0, 10),
	PaddingRight = UDim.new(0, 10),
}, promptBox)

local generateButton = make("TextButton", {
	AutoButtonColor = true,
	BackgroundColor3 = Color3.fromRGB(142, 111, 224),
	BorderSizePixel = 0,
	Font = Enum.Font.GothamBold,
	Size = UDim2.new(1, 0, 0, 34),
	Text = "✦  Oyun taslağı oluştur",
	TextColor3 = Color3.fromRGB(255, 255, 255),
	TextSize = 12,
	LayoutOrder = 7,
}, panel)
make("UICorner", { CornerRadius = UDim.new(0, 7) }, generateButton)

local statusLabel = make("TextLabel", {
	BackgroundTransparency = 1,
	Size = UDim2.new(1, 0, 0, 52),
	Font = Enum.Font.Gotham,
	Text = "Sahne ve scriptler eklenmeden önce Studio içinde önizleme gösterilir.",
	TextColor3 = Color3.fromRGB(160, 158, 173),
	TextSize = 11,
	TextWrapped = true,
	TextXAlignment = Enum.TextXAlignment.Left,
	TextYAlignment = Enum.TextYAlignment.Top,
	LayoutOrder = 8,
}, panel)

local applyButton = make("TextButton", {
	AutoButtonColor = true,
	BackgroundColor3 = Color3.fromRGB(62, 145, 103),
	BorderSizePixel = 0,
	Font = Enum.Font.GothamBold,
	Size = UDim2.new(1, 0, 0, 39),
	Text = "Studio'ya uygula",
	TextColor3 = Color3.fromRGB(255, 255, 255),
	TextSize = 12,
	Visible = false,
	LayoutOrder = 9,
}, panel)
make("UICorner", { CornerRadius = UDim.new(0, 7) }, applyButton)

local safetyNote = make("TextLabel", {
	BackgroundTransparency = 1,
	Size = UDim2.new(1, 0, 0, 41),
	Font = Enum.Font.Gotham,
	Text = "Kodlar projeye eklenir; Play'e basmadan önce kaynaklarını incele. AI kodunu çalıştırmadan önce mutlaka gözden geçir.",
	TextColor3 = Color3.fromRGB(139, 136, 153),
	TextSize = 10,
	TextWrapped = true,
	TextXAlignment = Enum.TextXAlignment.Left,
	TextYAlignment = Enum.TextYAlignment.Top,
	LayoutOrder = 10,
}, panel)

local importLabel = make("TextLabel", {
	BackgroundTransparency = 1,
	Size = UDim2.new(1, 0, 0, 17),
	Font = Enum.Font.GothamSemibold,
	Text = "WEB SİTESİNDEN JSON TASLAĞI",
	TextColor3 = Color3.fromRGB(166, 151, 211),
	TextSize = 10,
	TextXAlignment = Enum.TextXAlignment.Left,
	LayoutOrder = 11,
}, panel)

local importBox = make("TextBox", {
	BackgroundColor3 = Color3.fromRGB(17, 17, 25),
	BorderColor3 = Color3.fromRGB(57, 54, 70),
	ClearTextOnFocus = false,
	Font = Enum.Font.Code,
	MultiLine = true,
	PlaceholderText = "Web sitesinde Studio JSON'u kopyala, buraya yapıştır.",
	Size = UDim2.new(1, 0, 0, 78),
	Text = "",
	TextColor3 = Color3.fromRGB(236, 233, 245),
	TextSize = 10,
	TextWrapped = true,
	TextXAlignment = Enum.TextXAlignment.Left,
	TextYAlignment = Enum.TextYAlignment.Top,
	LayoutOrder = 12,
}, panel)
make("UIPadding", {
	PaddingTop = UDim.new(0, 7),
	PaddingBottom = UDim.new(0, 7),
	PaddingLeft = UDim.new(0, 8),
	PaddingRight = UDim.new(0, 8),
}, importBox)

local importButton = make("TextButton", {
	AutoButtonColor = true,
	BackgroundColor3 = Color3.fromRGB(68, 99, 153),
	BorderSizePixel = 0,
	Font = Enum.Font.GothamBold,
	Size = UDim2.new(1, 0, 0, 34),
	Text = "Web taslağını içe aktar",
	TextColor3 = Color3.fromRGB(255, 255, 255),
	TextSize = 11,
	LayoutOrder = 13,
}, panel)
make("UICorner", { CornerRadius = UDim.new(0, 7) }, importButton)

local currentProject
local busy = false

local function setStatus(message, isError)
	statusLabel.Text = message
	statusLabel.TextColor3 = isError and Color3.fromRGB(242, 151, 157) or Color3.fromRGB(160, 158, 173)
end

local function projectIsValid(project)
	if type(project) ~= "table" or type(project.name) ~= "string" or type(project.description) ~= "string" then
		return false
	end
	if type(project.scripts) ~= "table" or #project.scripts < 1 or #project.scripts > 5 then
		return false
	end
	if type(project.parts) ~= "table" or #project.parts > 30 then
		return false
	end

	local allowedLocations = {
		ServerScriptService = true,
		StarterPlayerScripts = true,
		StarterGui = true,
	}
	for _, scriptData in ipairs(project.scripts) do
		if type(scriptData) ~= "table"
			or type(scriptData.name) ~= "string"
			or not allowedLocations[scriptData.location]
			or type(scriptData.source) ~= "string"
			or #scriptData.source == 0
			or #scriptData.source > 20000 then
			return false
		end
	end

	local allowedShapes = { Block = true, Ball = true, Cylinder = true }
	local allowedMaterials = {
		SmoothPlastic = true,
		Plastic = true,
		Wood = true,
		Concrete = true,
		Grass = true,
		Neon = true,
		Metal = true,
	}
	for _, partData in ipairs(project.parts) do
		if type(partData) ~= "table"
			or type(partData.name) ~= "string"
			or not allowedShapes[partData.shape]
			or not allowedMaterials[partData.material]
			or type(partData.color) ~= "string"
			or not string.match(partData.color, "^#%x%x%x%x%x%x$")
			or type(partData.position) ~= "table"
			or #partData.position ~= 3
			or type(partData.size) ~= "table"
			or #partData.size ~= 3 then
			return false
		end
		for axis = 1, 3 do
			local position = partData.position[axis]
			local size = partData.size[axis]
			if type(position) ~= "number" or position ~= position or math.abs(position) > 1000
				or type(size) ~= "number" or size ~= size or size <= 0 or size > 200 then
				return false
			end
		end
	end
	return true
end

local function safeName(value, fallback)
	local cleaned = string.gsub(value, "[^%w_%-]", "_")
	cleaned = string.sub(cleaned, 1, 28)
	if cleaned == "" then
		return fallback
	end
	return cleaned
end

local function makeProjectName(name)
	return "dRoblox_" .. safeName(name, "Oyun")
end

local function getApiUrl()
	local value = string.gsub(endpointBox.Text, "^%s*(.-)%s*$", "%1")
	if not string.match(value, "^https://") or string.find(value, "%s") then
		return nil, "Site adresi https:// ile başlamalı."
	end
	if string.sub(value, -13) ~= "/api/generate" then
		value = string.gsub(value, "/+$", "") .. "/api/generate"
	end
	plugin:SetSetting("OyunAtolyeApiUrl", endpointBox.Text)
	return value
end

local function requestProject(prompt)
	local url, urlError = getApiUrl()
	if not url then
		return nil, urlError
	end
	local ok, response = pcall(function()
		return HttpService:RequestAsync({
			Url = url,
			Method = "POST",
			Headers = { ["Content-Type"] = "application/json" },
			Body = HttpService:JSONEncode({
				prompt = prompt,
				mode = "roblox-project",
			}),
		})
	end)
	if not ok then
		return nil, "Cloudflare API'ye bağlanılamadı. Site adresini ve Studio'nun HTTP izinlerini kontrol et."
	end
	if not response.Success then
		local decodedOk, decoded = pcall(function()
			return HttpService:JSONDecode(response.Body)
		end)
		if decodedOk and type(decoded) == "table" and type(decoded.error) == "string" then
			return nil, decoded.error
		end
		return nil, "API isteği başarısız oldu (HTTP " .. tostring(response.StatusCode) .. ")."
	end

	local decodedOk, decoded = pcall(function()
		return HttpService:JSONDecode(response.Body)
	end)
	if not decodedOk or type(decoded) ~= "table" or not projectIsValid(decoded.project) then
		return nil, "AI yanıtı geçerli oyun taslağı biçiminde değil. Tekrar deneyebilirsin."
	end
	return decoded.project
end

local function colorFromHex(value)
	local red = tonumber(string.sub(value, 2, 3), 16)
	local green = tonumber(string.sub(value, 4, 5), 16)
	local blue = tonumber(string.sub(value, 6, 7), 16)
	return Color3.fromRGB(red, green, blue)
end

local function applyProject(project)
	local rootName = makeProjectName(project.name)
	local starterPlayerScripts = StarterPlayer:WaitForChild("StarterPlayerScripts")
	local destinations = {
		{
			service = ServerScriptService,
			scripts = {},
		},
		{
			service = starterPlayerScripts,
			scripts = {},
		},
		{
			service = StarterGui,
			scripts = {},
		},
		{
			service = Workspace,
			scripts = {},
		},
	}
	local destinationByName = {
		ServerScriptService = destinations[1],
		StarterPlayerScripts = destinations[2],
		StarterGui = destinations[3],
	}

	for _, scriptData in ipairs(project.scripts) do
		table.insert(destinationByName[scriptData.location].scripts, scriptData)
	end
	for _, destination in ipairs(destinations) do
		if #destination.scripts > 0 or destination.service == Workspace then
			if destination.service:FindFirstChild(rootName) then
				return false, rootName .. " zaten var. Eski oluşturulan klasörü silip tekrar deneyebilirsin."
			end
		end
	end

	ChangeHistoryService:SetWaypoint("OyunAtölye öncesi")
	local createdFolders = {}
	local ok, err = pcall(function()
		for _, destination in ipairs(destinations) do
			if #destination.scripts > 0 or destination.service == Workspace then
				local folder = Instance.new("Folder")
				folder.Name = rootName
				folder.Parent = destination.service
				table.insert(createdFolders, folder)

				for index, scriptData in ipairs(destination.scripts) do
					local className = destination.service == ServerScriptService and "Script" or "LocalScript"
					local generatedScript = Instance.new(className)
					generatedScript.Name = safeName(scriptData.name, className .. index)
					generatedScript.Source = scriptData.source
					generatedScript.Parent = folder
				end

				if destination.service == Workspace then
					local floor = Instance.new("Part")
					floor.Name = "OyunAtolye_Zemin"
					floor.Anchored = true
					floor.Size = Vector3.new(160, 1, 160)
					floor.Position = Vector3.new(0, -0.5, 0)
					floor.Material = Enum.Material.SmoothPlastic
					floor.Color = Color3.fromRGB(48, 51, 68)
					floor.Parent = folder

					for index, partData in ipairs(project.parts) do
						local part = Instance.new("Part")
						part.Name = safeName(partData.name, "SahneParcasi" .. index)
						part.Shape = Enum.PartType[partData.shape]
						part.Size = Vector3.new(partData.size[1], partData.size[2], partData.size[3])
						part.Position = Vector3.new(partData.position[1], partData.position[2], partData.position[3])
						part.Anchored = true
						part.CanCollide = true
						part.Material = Enum.Material[partData.material]
						part.Color = colorFromHex(partData.color)
						part.Parent = folder
					end
				end
			end
		end
	end)

	if not ok then
		for _, folder in ipairs(createdFolders) do
			folder:Destroy()
		end
		ChangeHistoryService:SetWaypoint("OyunAtölye oluşturma hatası")
		return false, "Studio'ya ekleme tamamlanamadı: " .. tostring(err)
	end

	ChangeHistoryService:SetWaypoint("OyunAtölye oyun taslağı oluşturuldu")
	return true, rootName
end

local function setBusy(value)
	busy = value
	generateButton.Active = not value
	generateButton.AutoButtonColor = not value
	generateButton.Text = value and "Gemini hazırlıyor..." or "✦  Oyun taslağı oluştur"
	importButton.Active = not value
	importButton.AutoButtonColor = not value
end

openButton.Click:Connect(function()
	widget.Enabled = not widget.Enabled
end)

generateButton.Activated:Connect(function()
	if busy then
		return
	end
	local prompt = string.gsub(promptBox.Text, "^%s*(.-)%s*$", "%1")
	if prompt == "" then
		setStatus("Önce nasıl bir oyun istediğini yaz.", true)
		return
	end
	if #prompt > 5000 then
		setStatus("Oyun fikri en fazla 5000 karakter olabilir.", true)
		return
	end

	currentProject = nil
	applyButton.Visible = false
	setBusy(true)
	setStatus("Gemini oyun fikrini değerlendiriyor ve sahne taslağını hazırlıyor...", false)
	local ok, project, requestError = pcall(requestProject, prompt)
	setBusy(false)
	if not ok then
		setStatus("Beklenmeyen bir hata oluştu: " .. tostring(project), true)
		return
	end
	if not project then
		setStatus("Oyun taslağı oluşturulamadı: " .. tostring(requestError), true)
		return
	end

	currentProject = project
	setStatus(
		project.name .. "\n" .. project.description ..
			"\n" .. #project.scripts .. " script · " .. #project.parts .. " sahne parçası",
		false
	)
	applyButton.Visible = true
end)

importButton.Activated:Connect(function()
	if busy then
		return
	end
	local rawJson = string.gsub(importBox.Text, "^%s*(.-)%s*$", "%1")
	if rawJson == "" then
		setStatus("Önce web sitesinden Studio JSON taslağını kopyalayıp alana yapıştır.", true)
		return
	end
	if #rawJson > 200000 then
		setStatus("Taslak 200 KB sınırını aşıyor. Daha küçük bir oyun taslağı üret.", true)
		return
	end
	local ok, decoded = pcall(function()
		return HttpService:JSONDecode(rawJson)
	end)
	if not ok or not projectIsValid(decoded) then
		setStatus("JSON geçersiz veya taslak güvenli sınırları aşıyor. Web sitesinden yeni bir Studio taslağı kopyala.", true)
		return
	end

	currentProject = decoded
	applyButton.Visible = true
	setStatus(
		decoded.name .. "\n" .. decoded.description ..
			"\n" .. #decoded.scripts .. " script · " .. #decoded.parts .. " sahne parçası · web'den aktarıldı",
		false
	)
end)

applyButton.Activated:Connect(function()
	if busy or not currentProject then
		return
	end
	local ok, result, detail = pcall(applyProject, currentProject)
	if not ok then
		setStatus("Studio'ya ekleme sırasında hata oluştu: " .. tostring(result), true)
		return
	end
	if not result then
		setStatus(tostring(detail), true)
		return
	end
	setStatus("Oyun Studio'ya eklendi: " .. tostring(detail) .. ". Play'e basmadan önce scriptleri incele.", false)
	applyButton.Visible = false
end)
