-- Assign grouping hotkeys
AssignHotkey({ 'LeftShift', 'G' }, Support.Call(GroupSelection, 'Model'))
AssignHotkey({ 'RightShift', 'G' }, Support.Call(GroupSelection, 'Model'))
AssignHotkey({ 'LeftShift', 'F' }, Support.Call(GroupSelection, 'Folder'))
AssignHotkey({ 'RightShift', 'F' }, Support.Call(GroupSelection, 'Folder'))
AssignHotkey({ 'LeftShift', 'U' }, UngroupSelection)
AssignHotkey({ 'RightShift', 'U' }, UngroupSelection)

function GetPartsFromSelection(Selection)
	local Parts = {}

	-- Get parts from selection
	for _, Item in pairs(Selection) do
		if Item:IsA 'BasePart' then
			Parts[#Parts + 1] = Item

		-- Get parts within other items
		else
			for _, Descendant in pairs(Item:GetDescendants()) do
				if Descendant:IsA 'BasePart' then
					Parts[#Parts + 1] = Descendant
				end
			end
		end
	end

	-- Return parts
	return Parts
end

function IsSelectable(Items)
	-- Returns whether `Items` can be selected

	-- Check each item
	for _, Item in pairs(Items) do

		-- Ensure item exists and is not locked
		if (not Item) or (not Item.Parent) or (Item:IsA 'BasePart' and Item.Locked) then
			return false
		end

		-- Ensure item can be modified
		if not Security.IsItemAllowed(Item, Player) then
			return false
		end
	end

	-- Check if parts intruding into private areas
	local Parts = GetPartsFromSelection(Items)
	if Security.ArePartsViolatingAreas(Parts, Player, true) then
		return false
	end

	-- If no checks fail, items are selectable
	return true

end

function ExportSelection()
	-- Exports the selected parts

	-- Make sure that there are items in the selection
	if #Selection.Items == 0 then
		return;
	end;

	-- Start an export dialog
	local DialogHandle
	local DialogComponent = require(Tool:WaitForChild('UI'):WaitForChild('ExportDialog'))
	local DialogDismissCallback = function ()
		DialogHandle = Roact.unmount(DialogHandle)
	end
	local DialogElement = Roact.createElement(DialogComponent, {
		Text = 'Uploading selection...';
		OnDismiss = DialogDismissCallback;
	})
	DialogHandle = Roact.mount(DialogElement, UI, 'ExportDialog')

	-- Send the exporting request to the server
	Try(SyncAPI.Invoke, SyncAPI, 'Export', Selection.Items)

	-- Display creation ID on success
	:Then(function (CreationId)
		Roact.update(DialogHandle, Roact.createElement(DialogComponent, {
			Text = 'Your creation\'s ID:<font size="5"><br /></font>\n' ..
				'<font face="GothamBlack" size="18">' .. CreationId .. '</font><font size="6"><br /></font>\n' ..
				'<font face="Gotham" size="10">Use the code above to import your creation using the plugin in Studio.</font>';
			OnDismiss = DialogDismissCallback;
		}))
		print('[Building Tools by F3X] Uploaded Export:', CreationId);
	end)

	-- Display error messages on failure
	:Catch('Http requests are not enabled', function ()
		Roact.update(DialogHandle, Roact.createElement(DialogComponent, {
			Text = 'Please enable HTTP requests.';
			OnDismiss = DialogDismissCallback;
		}))
	end)
	:Catch('Export failed due to server-side error', function ()
		Roact.update(DialogHandle, Roact.createElement(DialogComponent, {
			Text = 'An error occurred — please try again.';
			OnDismiss = DialogDismissCallback;
		}))
	end)
	:Catch('Post data too large', function ()
		Roact.update(DialogHandle, Roact.createElement(DialogComponent, {
			Text = 'Try splitting up your build.';
			OnDismiss = DialogDismissCallback;
		}))
	end)
	:Catch(function (Error, Stack, Attempt)
		Roact.update(DialogHandle, Roact.createElement(DialogComponent, {
			Text = 'An unknown error occurred — please try again.';
			OnDismiss = DialogDismissCallback;
		}))
		warn('❌ [Building Tools by F3X] Failed to export selection', '\n\nError:\n', Error, '\n\nStack:\n', Stack)
	end)

end;