--[[
			// GameDetail.lua
]]
local CoreGui = Game:GetService("CoreGui")
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")
local GuiService = game:GetService('GuiService')
local ContextActionService = game:GetService("ContextActionService")
local PlatformService = nil
pcall(function() PlatformService = Game:GetService('PlatformService') end)
local GameOptionsSettings = settings():FindFirstChild("Game Options")

local AssetManager = require(Modules:FindFirstChild('AssetManager'))
local GameData = require(Modules:FindFirstChild('GameData'))
local GlobalSettings = require(Modules:FindFirstChild('GlobalSettings'))
local Strings = require(Modules:FindFirstChild('LocalizedStrings'))
local ScreenManager = require(Modules:FindFirstChild('ScreenManager'))
local Utility = require(Modules:FindFirstChild('Utility'))
local EventHub = require(Modules:FindFirstChild('EventHub'))
local ImageOverlayModule = require(Modules:FindFirstChild('ImageOverlay'))
local ReportOverlayModule = require(Modules:FindFirstChild('ReportOverlay'))
local BadgeSortModule = require(Modules:FindFirstChild('BadgeSort'))
local ScrollingTextBox = require(Modules:FindFirstChild('ScrollingTextBox'))
local PopupText = require(Modules:FindFirstChild('PopupText'))
local LoadingWidget = require(Modules:FindFirstChild('LoadingWidget'))
local Errors = require(Modules:FindFirstChild('Errors'))
local ErrorOverlayModule = require(Modules:FindFirstChild('ErrorOverlay'))
local GameJoinModule = require(Modules:FindFirstChild('GameJoin'))
local ThumbnailLoader = require(Modules:FindFirstChild('ThumbnailLoader'))
local SoundManager = require(Modules:FindFirstChild('SoundManager'))
local VoteViewModule = require(Modules:FindFirstChild('VoteView'))
local BaseScreen = require(Modules:FindFirstChild('BaseScreen'))

local CanShowDevNames = Utility.IsFastFlagEnabled("ShowDevNameInXboxApp")

local function CreateGameDetail(placeId, placeName, iconId, gameData)
	local this = BaseScreen()

	local LEFT_MARGIN = 8
	local TWEEN_TIME = 0.5
	local joinOnShow = false
	local isFavorited = false

	local baseButtonTextColor = GlobalSettings.WhiteTextColor
	local selectedButtonTextColor = GlobalSettings.TextSelectedColor

	local selectionChangedCn = nil
	local gameJoinSuccessCn = nil

	-- tween content container
	local leftTweenContainer = nil
	local rightTweenContainer = nil

	--[[ Cache Game Data ]]--
	local getGameDataDebounce = false
	local function getDataAsync()
		while getGameDataDebounce do
			wait()
		end
		getGameDataDebounce = true

		if not gameData then
			gameData = GameData:GetGameDataAsync(placeId)
		end
		getGameDataDebounce = false
		return gameData
	end

	-- override selection image
	local edgeSelectionImage = Utility.Create'ImageLabel'
	{
		Name = "EdgeSelectionImage";
		Size = UDim2.new(1, 32, 1, 32);
		Position = UDim2.new(0, -16, 0, -16);
		Image = 'rbxasset://textures/ui/SelectionBox.png';
		ScaleType = Enum.ScaleType.Slice;
		SliceCenter = Rect.new(21,21,41,41);
		BackgroundTransparency = 1;
	}

--[[ Top Level Elements ]]--
	--this:SetParent(parent)
	local GameDetailContainer = this.Container
	this:SetTitle(string.upper(placeName or ''))

	local ContentContainer = Utility.Create'Frame'
	{
		Name = "ContentContainer";
		Size = UDim2.new(1, 0, 0, 632);
		Position = UDim2.new(0, LEFT_MARGIN, 0, 210);
		BackgroundTransparency = 1;
		Parent = GameDetailContainer;
	}
	local PlayButton = Utility.Create'ImageButton'
	{
		Name = "PlayButton";
		Size = UDim2.new(0, 228, 0, 72);
		Position = UDim2.new(0, 0, 1, -77);
		BackgroundTransparency = 1;
		ImageColor3 = GlobalSettings.GreenButtonColor;
		Image = 'rbxasset://textures/ui/Shell/Buttons/Generic9ScaleButton@720.png';
		ScaleType = Enum.ScaleType.Slice;
		SliceCenter = Rect.new(Vector2.new(4, 4), Vector2.new(28, 28));
		Parent = GameDetailContainer;

		SoundManager:CreateSound('MoveSelection');
		ZIndex = 2;
		AssetManager.CreateShadow(1)
	}

	local PlayText = Utility.Create'TextLabel'
	{
		Name = "PlayText";
		Size = UDim2.new(1, 0, 1, 0);
		BackgroundTransparency = 1;
		Text = string.upper(Strings:LocalizedString("PlayWord"));
		Font = GlobalSettings.RegularFont;
		FontSize = GlobalSettings.ButtonSize;
		TextColor3 = baseButtonTextColor;
		ZIndex = 2;
		Parent = PlayButton;
	}
	local FavoriteButton = Utility.Create'ImageButton'
	{
		Name = "FavoriteButton";
		Size = UDim2.new(0, 228, 0, 72);
		Position = UDim2.new(0, PlayButton.Size.X.Offset + 10, 1, -77);
		BackgroundTransparency = 1;
		ImageColor3 = GlobalSettings.GreyButtonColor;
		Image = 'rbxasset://textures/ui/Shell/Buttons/Generic9ScaleButton@720.png';
		ScaleType = Enum.ScaleType.Slice;
		SliceCenter = Rect.new(Vector2.new(4, 4), Vector2.new(28, 28));
		Parent = GameDetailContainer;

		SoundManager:CreateSound('MoveSelection');
		ZIndex = 2;
		AssetManager.CreateShadow(1)
	}

	local FavoriteText = Utility.Create'TextLabel'
	{
		Name = "FavoriteText";
		Size = UDim2.new(1, 0, 1, 0);
		BackgroundTransparency = 1;
		Text = string.upper(Strings:LocalizedString("FavoriteWord"));
		Font = GlobalSettings.RegularFont;
		FontSize = GlobalSettings.ButtonSize;
		TextColor3 = baseButtonTextColor;
		ZIndex = 2;
		Parent = FavoriteButton;
	}
	local FavoriteStarImage = Utility.Create'ImageLabel'
	{
		Name = "FavoriteStarImage";
		BackgroundTransparency = 1;
		Visible = false;
		ZIndex = 2;
		Parent = FavoriteButton;
	}
	AssetManager.LocalImage(FavoriteStarImage,
		'rbxasset://textures/ui/Shell/Icons/FavoriteStar', {['720'] = UDim2.new(0,21,0,21); ['1080'] = UDim2.new(0,32,0,31);})
	FavoriteStarImage.Position = UDim2.new(0, 16, 0.5, -FavoriteStarImage.Size.Y.Offset / 2)

	local FavoriteRedirectFrame = Utility.Create'Frame'
	{
		Name = "FavoriteRedirectFrame";
		Size = UDim2.new(1, 0, 0, FavoriteButton.Size.Y.Offset);
		Position = UDim2.new(0, FavoriteButton.Position.X.Offset + FavoriteButton.Size.X.Offset, 1, FavoriteButton.Position.Y.Offset);
		BackgroundTransparency = 1;
		Selectable = true;
		Parent = GameDetailContainer;
	}

--[[ Scrolling Content Items ]]--

	--[[ Icon Image ]]--
	local GameIconContainer = Utility.Create'Frame'
	{
		Name = "GameIconContainer";
		Size = UDim2.new(0, 566, 1, 0);
		Position = UDim2.new(0, 0, 0, 0);
		BackgroundTransparency = 1;
		Parent = ContentContainer;
	}
		local GameIconImage = Utility.Create'ImageLabel'
		{
			Name = "GameIconImage";
			Size = UDim2.new(1, 0, 0, 566);
			Position = UDim2.new(0, 0, 0.5, -566/2);
			BackgroundTransparency = 0;
			BorderSizePixel = 0;
			BackgroundColor3 = Color3.new();
			ZIndex = 2;
			Parent = GameIconContainer;
			AssetManager.CreateShadow(1);
		}
		local function loadGameIcon(assetId)
			local gameIconLoader = ThumbnailLoader:Create(GameIconImage, assetId,
				ThumbnailLoader.Sizes.Medium, ThumbnailLoader.AssetType.Icon)
			spawn(function()
				gameIconLoader:LoadAsync()
			end)
		end
		if iconId and type(iconId) == "number" then
			loadGameIcon(iconId)
		else
			spawn(function()
				local data = getDataAsync()
				local id = data:GetGameIconIdAsync()
				loadGameIcon(id)
			end)
		end

	--[[ Rating and Description ]]--
	local RatingDescriptionContainer = Utility.Create'Frame'
	{
		Name = "RatingDescriptionContainer";
		Size = UDim2.new(0, 394, 1, 0);
		Position = UDim2.new(0, GameIconContainer.Size.X.Offset + 38, 0, 0);
		BackgroundTransparency = 1;
		Parent = ContentContainer;
	}
	local RatingDescriptionTitle = Utility.Create'TextLabel'
	{
		Name = "RatingDescriptionTitle";
		Size = UDim2.new(0, 0, 0, 33);
		Position = UDim2.new(0, 0, 0, 0);
		BackgroundTransparency = 1;
		Text = string.upper(Strings:LocalizedString("RatingDescriptionTitle"));
		TextXAlignment = Enum.TextXAlignment.Left;
		Font = GlobalSettings.RegularFont;
		FontSize = GlobalSettings.SubHeaderSize;
		TextColor3 = GlobalSettings.WhiteTextColor;
		Parent = RatingDescriptionContainer;
	}
	local VoteView = VoteViewModule()
	VoteView:SetPosition(UDim2.new(0, 0, 0, RatingDescriptionTitle.Size.Y.Offset))
	local VoteViewContainer = VoteView.Container

	local RatingDescriptionLineBreak = Utility.Create'Frame'
	{
		Name = "RatingDescriptionLineBreak";
		Size = UDim2.new(0, 362, 0, 2);
		Position = UDim2.new(0, 0, 0, VoteViewContainer.Position.Y.Offset + VoteViewContainer.Size.Y.Offset);
		BorderSizePixel = 0;
		BackgroundColor3 = GlobalSettings.LineBreakColor;
		Parent = RatingDescriptionContainer;
	}

	--[[ Description Container ]]--
	local DescriptionContainer = Utility.Create'Frame'
	{
		Name = "DescriptionContainer";
		Size = UDim2.new(1, 0, 0, 430);
		Position = UDim2.new(0, 0, 0, RatingDescriptionLineBreak.Position.Y.Offset + RatingDescriptionLineBreak.Size.Y.Offset + 20);
		BackgroundTransparency = 1;
		Parent = RatingDescriptionContainer;
	}
	local DescriptionScrollingTextBox = ScrollingTextBox(UDim2.new(1, 0, 1, 0), UDim2.new(0, 0, 0), DescriptionContainer)

--[[ Line Break ]]--
	local RatingThumbsLineBreak = Utility.Create'Frame'
	{
		Name = "LineBreak";
		Size = UDim2.new(0, 2, 0, 566);
		Position = UDim2.new(0, RatingDescriptionContainer.Position.X.Offset + RatingDescriptionContainer.Size.X.Offset + 32, 0, 33);
		BackgroundTransparency = 0;
		BorderSizePixel = 0;
		BackgroundColor3 = Color3.new(78/255, 78/255, 78/255);
		BorderSizePixel = 0;
		Parent = ContentContainer;
	}

--[[ Additional Thumbs ]]--
	local ThumbsContainer = Utility.Create'Frame'
	{
		Name = "ThumbsContainer";
		Size = UDim2.new(0, 630, 1, 0);
		Position = UDim2.new(0, RatingThumbsLineBreak.Position.X.Offset + RatingThumbsLineBreak.Size.X.Offset + 52, 0, 0);
		BackgroundTransparency = 1;
		Parent = ContentContainer;
	}
	local ThumbsTitle = RatingDescriptionTitle:Clone()
	ThumbsTitle.Text = string.upper(Strings:LocalizedString("GameImagesTitle"))
	ThumbsTitle.Parent = ThumbsContainer

	local ThumbsContent = Utility.Create'Frame'
	{
		Name = "ThumbsContent";
		Size = UDim2.new(1, 0, 1, 0);
		Position = UDim2.new(0, 0, 0, 0);
		BackgroundTransparency = 1;
		Parent = ThumbsContainer;
	}

	local MainThumbImage = Utility.Create'ImageButton'
	{
		Name = "MainThumbImage";
		Size = UDim2.new(1, 0, 0, 374);
		Position = UDim2.new(0, 0, 0, ThumbsTitle.Size.Y.Offset);
		BackgroundTransparency = 0;
		BorderSizePixel = 0;
		BackgroundColor3 = Color3.new();
		ZIndex = 2;
		Parent = ThumbsContent;

		SoundManager:CreateSound('MoveSelection');
		AssetManager.CreateShadow(1);
	}
	local SmThumbLeft = Utility.Create'ImageButton'
	{
		Name = "SmThumbLeft";
		Size = UDim2.new(0, 310, 0, 184);
		Position = UDim2.new(0, 0, 0, MainThumbImage.Position.Y.Offset + MainThumbImage.Size.Y.Offset + 8);
		BackgroundTransparency = 0;
		BackgroundColor3 = Color3.new();
		BorderSizePixel = 0;
		ZIndex = 2;
		Parent = ThumbsContent;

		SoundManager:CreateSound('MoveSelection');
		AssetManager.CreateShadow(1);
	}
	SmThumbRight = SmThumbLeft:Clone()
	SmThumbRight.Position = UDim2.new(0, SmThumbLeft.Size.X.Offset + 10, 0, SmThumbRight.Position.Y.Offset)
	SmThumbRight.Parent = ThumbsContent

	local MoreThumbsButton = Utility.Create'ImageButton'
	{
		Name = "MoreThumbsButton";
		BackgroundTransparency = 1;
		Visible = false;
		Parent = ThumbsContent;

		SoundManager:CreateSound('MoveSelection');
		ZIndex = 2;
	}
	AssetManager.LocalImage(MoreThumbsButton,
		'rbxasset://textures/ui/Shell/Buttons/MoreButton', {['720'] = UDim2.new(0,72,0,33); ['1080'] = UDim2.new(0,108,0,50);})
	MoreThumbsButton.Position = UDim2.new(1, -MoreThumbsButton.Size.X.Offset + 3, 0,
		SmThumbRight.Position.Y.Offset + SmThumbRight.Size.Y.Offset + 12)

--[[ Badges ]]--
	local BadgeContainer = Utility.Create'Frame'
	{
		Name = "BadgeContainer";
		Size = UDim2.new(0, 568, 1, 0);
		Position = UDim2.new(0, ThumbsContainer.Position.X.Offset + ThumbsContainer.Size.X.Offset + 52, 0, 0);
		BackgroundTransparency = 1;
		Parent = ContentContainer;
	}
	local BadgeTitle = RatingDescriptionTitle:Clone()
	BadgeTitle.Text = string.upper(Strings:LocalizedString("GameBadgesTitle"))
	BadgeTitle.Parent = BadgeContainer

	local BadgeSort = BadgeSortModule(placeName, UDim2.new(1, 0, 0, 566), UDim2.new(0, 0, 0, BadgeTitle.Size.Y.Offset), BadgeContainer)

	--[[ Related Games ]]--
	local RelatedGamesContainer = Utility.Create'Frame'
	{
		Name = "RelatedGamesContainer";
		Size = BadgeContainer.Size;
		Position = UDim2.new(0, BadgeContainer.Position.X.Offset + BadgeContainer.Size.X.Offset + 52, 0, 0);
		BackgroundTransparency = 1;
		Parent = ContentContainer;
	}
	local RelatedGamesTitle = BadgeTitle:Clone()
	RelatedGamesTitle.Text = string.upper(Strings:LocalizedString("RelatedGamesTitle"))
	RelatedGamesTitle.Parent = RelatedGamesContainer

	local RelatedGamesImageFrame = Utility.Create'Frame'
	{
		Name = "RelatedGamesImageFrame";
		Size = UDim2.new(1, 0, 566, 0);
		Position = UDim2.new(0, 0, 0, RelatedGamesTitle.Size.Y.Offset);
		BackgroundTransparency = 1;
		Parent = RelatedGamesContainer;
	}
	-- 2x2 grid of related games
	local RelatedGameImages = {}
	local relatedIndex = 1
	local relatedMargin = 14
	local relatedSize = (566 - relatedMargin) / 2
	for i = 1, 2 do
		for j = 1, 2 do
			local image = Utility.Create'ImageButton'
			{
				Name = tostring(relatedIndex);
				Size = UDim2.new(0, relatedSize, 0, relatedSize);
				Position = UDim2.new(0, (i - 1) * relatedSize + (i - 1) * relatedMargin, 0, (j - 1) * relatedSize + (j - 1) * relatedMargin);
				BackgroundTransparency = 0;
				BackgroundColor3 = GlobalSettings.GreyButtonColor;
				BorderSizePixel = 0;
				ZIndex = 2;
				Parent = RelatedGamesImageFrame;

				SoundManager:CreateSound('MoveSelection');
				AssetManager.CreateShadow(1);
			}
			RelatedGameImages[relatedIndex] = image
			relatedIndex = relatedIndex + 1
		end
	end

	local RelatedGamesMoreDetailsLineBreak = RatingThumbsLineBreak:Clone()
	RelatedGamesMoreDetailsLineBreak.Position = UDim2.new(0,
		RelatedGamesContainer.Position.X.Offset + RelatedGamesContainer.Size.X.Offset + 52, 0,
		RelatedGamesMoreDetailsLineBreak.Position.Y.Offset)
	RelatedGamesMoreDetailsLineBreak.Parent = ContentContainer

	--[[ More Details ]]--
	local MoreDetailsContainer = Utility.Create'Frame'
	{
		Name = "MoreDetailsContainer";
		Size = UDim2.new(0, 386, 1, 0);
		Position = UDim2.new(0,
			RelatedGamesMoreDetailsLineBreak.Position.X.Offset + RelatedGamesMoreDetailsLineBreak.Size.X.Offset + 52, 0, 0);
		BackgroundTransparency = 1;
		Selectable = true;
		Parent = ContentContainer;
	}
	local MoreDetailsTitle = RelatedGamesTitle:Clone()
	MoreDetailsTitle.Text = string.upper(Strings:LocalizedString("MoreDetailsTitle"))
	MoreDetailsTitle.Parent = MoreDetailsContainer

	local MoreDetailsContent = Utility.Create'Frame'
	{
		Name = "MoreDetailsContent";
		Size = UDim2.new(1, 0, 1, 0);
		Position = UDim2.new(0, 0, 0, 0);
		BackgroundTransparency = 1;
		Parent = MoreDetailsContainer;
	}
	local UpdatedText = Utility.Create'TextLabel'
	{
		Name = "UpdatedText";
		Size = UDim2.new(0, 0, 0, 0);
		Position = UDim2.new(0, 0, 0, MoreDetailsTitle.Size.Y.Offset + 48);
		BackgroundTransparency = 1;
		Text = Strings:LocalizedString("LastUpdatedWord");
		Font = GlobalSettings.RegularFont;
		FontSize = GlobalSettings.SmallTitleSize;
		TextColor3 = GlobalSettings.WhiteTextColor;
		TextXAlignment = Enum.TextXAlignment.Left;
		Parent = MoreDetailsContent;
	}
	local LastUpdatedText = Utility.Create'TextLabel'
	{
		Name = "LastUpdatedText";
		Size = UDim2.new(0, 0, 0, 0);
		Position = UDim2.new(0, 0, 0, UpdatedText.Position.Y.Offset + 34);
		BackgroundTransparency = 1;
		Text = "";
		Font = GlobalSettings.LightFont;
		FontSize = GlobalSettings.TitleSize;
		TextColor3 = GlobalSettings.WhiteTextColor;
		TextXAlignment = Enum.TextXAlignment.Left;
		Parent = MoreDetailsContent;
	}
	local CreationText = UpdatedText:Clone()
	CreationText.Name = "CreationText"
	CreationText.Position = UDim2.new(0, 0, 0, LastUpdatedText.Position.Y.Offset + 70)
	CreationText.Text = Strings:LocalizedString("CreationDateWord")
	CreationText.Parent = MoreDetailsContent

	local CreationDateText = LastUpdatedText:Clone()
	CreationDateText.Name = "CreationDateText"
	CreationDateText.Position = UDim2.new(0, 0, 0, CreationText.Position.Y.Offset + 34)
	CreationDateText.Parent = MoreDetailsContent

	local MaxPlayersText = UpdatedText:Clone()
	MaxPlayersText.Name = "MaxPlayersText"
	MaxPlayersText.Position = UDim2.new(0, 0, 0, CreationDateText.Position.Y.Offset + 70)
	MaxPlayersText.Text = Strings:LocalizedString("MaxPlayersWord")
	MaxPlayersText.Parent = MoreDetailsContent

	local MaxPlayersCountText = LastUpdatedText:Clone()
	MaxPlayersCountText.Name = "MaxPlayersCountText"
	MaxPlayersCountText.Position = UDim2.new(0, 0, 0, MaxPlayersText.Position.Y.Offset + 34)
	MaxPlayersCountText.Parent = MoreDetailsContent

	local CreatorText = UpdatedText:Clone()
	CreatorText.Name = "CreatorText"
	CreatorText.Position = UDim2.new(0, 0, 0, MaxPlayersCountText.Position.Y.Offset + 70)
	CreatorText.Text = Strings:LocalizedString("CreatedByWord")
	CreatorText.Visible = CanShowDevNames
	CreatorText.Parent = MoreDetailsContent

	local CreatorIcon = Utility.Create'ImageLabel'
	{
		Name = "CreatorIcon";
		Size = UDim2.new(0, 32, 0, 32);
		Position = UDim2.new(0, 0, 0, CreatorText.Position.Y.Offset + 34 - 14);
		BackgroundTransparency = 1;
		Image = 'rbxasset://textures/ui/Shell/Icons/RobloxIcon.png';
		Visible = CanShowDevNames;
		Parent = MoreDetailsContent;
	}
	local CreatorNameText = LastUpdatedText:Clone()
	CreatorNameText.Name = "CreatorNameText"
	CreatorNameText.Position = UDim2.new(0, CreatorIcon.Size.X.Offset + 8, 0, CreatorText.Position.Y.Offset + 34)
	CreatorNameText.Visible = CanShowDevNames
	CreatorNameText.Parent = MoreDetailsContent

	local DetailsBottomLineBreak = Utility.Create'Frame'
	{
		Name = "DetailsBottomLineBreak";
		Size = UDim2.new(0, 308, 0, 2);
		Position = UDim2.new(0, 107, 0, MoreDetailsTitle.Size.Y.Offset + 566 - 2);
		BorderSizePixel = 0;
		BackgroundColor3 = GlobalSettings.LineBreakColor;
		Parent = MoreDetailsContainer;
	}
	local ReportFrame = Utility.Create'TextButton'
	{
		Name = "ReportFrame";
		Size = UDim2.new(0, 91, 0, 91);
		Position = UDim2.new(0, 0, 0, DetailsBottomLineBreak.Position.Y.Offset - 95);
		BackgroundColor3 = GlobalSettings.GreyButtonColor;
		BackgroundTransparency = 0;
		BorderSizePixel = 0;
		Text = "";
		Parent = MoreDetailsContainer;

		SoundManager:CreateSound('MoveSelection');
		ZIndex = 2;
		AssetManager.CreateShadow(1);
	}
	local ReportIcon = Utility.Create'ImageLabel'
	{
		Name = "ReportIcon";
		BackgroundTransparency = 1;
		ZIndex = 2;
		Parent = ReportFrame;
	}
	AssetManager.LocalImage(ReportIcon, 'rbxasset://textures/ui/Shell/Icons/ReportIcon',
		{['720'] = UDim2.new(0,35,0,29); ['1080'] = UDim2.new(0,52,0,43);})
	ReportIcon.Position = UDim2.new(0.5, -ReportIcon.Size.X.Offset / 2, 0.5, -ReportIcon.Size.Y.Offset / 2)
	local ReportText = Utility.Create'TextLabel'
	{
		Name = "ReportText";
		Size = UDim2.new(0, 0, 0, 0);
		Position = UDim2.new(1, 16, 0.5, 0);
		BackgroundTransparency = 1;
		Font = GlobalSettings.LightFont;
		FontSize = GlobalSettings.TitleSize;
		TextColor3 = GlobalSettings.WhiteTextColor;
		TextXAlignment = Enum.TextXAlignment.Left;
		Text = Strings:LocalizedString("ReportGameWord");
		Parent = ReportFrame;
	}
	ReportFrame.MouseButton1Click:connect(function()
		ScreenManager:OpenScreen(ReportOverlayModule:CreateReportOverlay(ReportOverlayModule.ReportType.REPORT_GAME, placeId), false)
	end)

	--[[ Custom Selection Logic ]]--
	PlayButton.NextSelectionRight = FavoriteButton
	SmThumbLeft.NextSelectionDown = MoreThumbsButton
	SmThumbLeft.NextSelectionRight = SmThumbRight

	local function JoinGame()
		GameJoinModule:StartGame(GameJoinModule.JoinType.Normal, placeId)
	end

	local function toggleFavoriteButton(value)
		if value == true then
			FavoriteStarImage.Visible = true
			FavoriteText.Position = UDim2.new(0, FavoriteStarImage.Position.X.Offset + FavoriteStarImage.Size.X.Offset + 12, 0, 0)
			FavoriteText.Text = string.upper(Strings:LocalizedString("FavoritedWord"))
			FavoriteText.TextXAlignment = Enum.TextXAlignment.Left
		elseif value == false then
			FavoriteStarImage.Visible = false
			FavoriteText.Position = UDim2.new(0, 0, 0, 0)
			FavoriteText.Text = string.upper(Strings:LocalizedString("FavoriteWord"))
			FavoriteText.TextXAlignment = Enum.TextXAlignment.Center
		end
	end

	--[[ SelectionGained/Lost Connections ]]--
	PlayButton.SelectionGained:connect(function()
		PlayButton.ImageColor3 = GlobalSettings.GreenSelectedButtonColor
		PlayText.TextColor3 = selectedButtonTextColor
	end)
	PlayButton.SelectionLost:connect(function()
		PlayButton.ImageColor3 = GlobalSettings.GreenButtonColor
		PlayText.TextColor3 = baseButtonTextColor
	end)
	FavoriteButton.SelectionGained:connect(function()
		FavoriteButton.ImageColor3 = GlobalSettings.GreySelectedButtonColor
		FavoriteText.TextColor3 = selectedButtonTextColor
	end)
	FavoriteButton.SelectionLost:connect(function()
		FavoriteButton.ImageColor3 = GlobalSettings.GreyButtonColor
		FavoriteText.TextColor3 = baseButtonTextColor
	end)
	MoreDetailsContainer.SelectionGained:connect(function()
		-- redirect
		GuiService.SelectedCoreObject = ReportFrame
	end)
	FavoriteRedirectFrame.SelectionGained:connect(function()
		GuiService.SelectedCoreObject = FavoriteButton
	end)
	local function updateMoreThumbsButton(isSelected)
		local uri = isSelected and 'rbxasset://textures/ui/Shell/Buttons/MoreButtonSelected' or 'rbxasset://textures/ui/Shell/Buttons/MoreButton'
		AssetManager.LocalImage(MoreThumbsButton, uri, {['720'] = UDim2.new(0,72,0,33); ['1080'] = UDim2.new(0,108,0,50);})
	end
	MoreThumbsButton.SelectionGained:connect(function()
		updateMoreThumbsButton(true)
	end)
	MoreThumbsButton.SelectionLost:connect(function()
		updateMoreThumbsButton(false)
	end)

	local function tweenContentFrame(final, duration)
		ContentContainer:TweenPosition(final, Enum.EasingDirection.InOut, Enum.EasingStyle.Quad, duration, true)
	end

	local function checkTweenContent(selectedObject)
		if selectedObject:IsDescendantOf(leftTweenContainer) then
			tweenContentFrame(UDim2.new(0, LEFT_MARGIN, 0, ContentContainer.Position.Y.Offset), TWEEN_TIME)
		elseif selectedObject:IsDescendantOf(rightTweenContainer) then
			tweenContentFrame(UDim2.new(-1, LEFT_MARGIN, 0, ContentContainer.Position.Y.Offset), TWEEN_TIME)
		end
	end

	--[[ Input Events ]]--
	PlayButton.MouseButton1Click:connect(function()
		SoundManager:Play('ButtonPress')
		local needToOverscan = false
		local success, errormsg = pcall(function()
			if GameOptionsSettings.OverscanPX < 0 or GameOptionsSettings.OverscanPY < 0 then
				needToOverscan = true
			end
		end)
		if not success then
			print("Error opening the Overscan Screen:" , errormsg)
		end

		if needToOverscan or UserSettings().GameSettings:InStudioMode() then
			EventHub:dispatchEvent(EventHub.Notifications["OpenOverscanScreen"], "")
			joinOnShow = true
		else
			JoinGame()
		end
	end)

	local favoriteDebounce = false
	FavoriteButton.MouseButton1Click:connect(function()
		if favoriteDebounce then return end
		favoriteDebounce = true

		SoundManager:Play('ButtonPress')
		local data = getDataAsync()
		if data then
			local result, reason = data:PostFavoriteAsync()
			if result == true then
				isFavorited = not isFavorited
				toggleFavoriteButton(isFavorited)
			elseif reason then
				local err = Errors.Favorite[reason]
				ScreenManager:OpenScreen(ErrorOverlayModule(err), false)
			end
		end
		favoriteDebounce = false
	end)

	--[[ Content Set Functions ]]--
	local function setBadgeContainer(hasBadges, badgeData)
		-- currently only content that may not be on page is badges if they have between 0 and 4
		-- update positions of content containers
		leftTweenContainer = ThumbsContainer
		if hasBadges then
			BadgeSort:Initialize(badgeData)
			rightTweenContainer = BadgeContainer
		else
			rightTweenContainer = RelatedGamesContainer
			RelatedGamesContainer.Position = BadgeContainer.Position
			RelatedGamesMoreDetailsLineBreak.Position = UDim2.new(0,
				RelatedGamesContainer.Position.X.Offset + RelatedGamesContainer.Size.X.Offset + 52, 0,
				RelatedGamesMoreDetailsLineBreak.Position.Y.Offset)
			MoreDetailsContainer.Position = UDim2.new(0,
				RelatedGamesMoreDetailsLineBreak.Position.X.Offset + RelatedGamesMoreDetailsLineBreak.Size.X.Offset + 52, 0, 0);
			BadgeContainer:Destroy()
			BadgeSort:Destroy()
		end
	end

	local function connectThumbImage(image, index, thumbIds)
		local loader = ThumbnailLoader:Create(image, thumbIds[index], ThumbnailLoader.Sizes.Large,
			ThumbnailLoader.AssetType.Icon, false)
		image.MouseButton1Click:connect(function()
			SoundManager:Play('ScreenChange');
			ImageOverlayModule(thumbIds, index)
		end)
		spawn(function()
			loader:LoadAsync()
		end)
	end
	local function setAdditionalThumbs(thumbIds)
		if #thumbIds >= 3 then
			connectThumbImage(MainThumbImage, 1, thumbIds)
			connectThumbImage(SmThumbLeft, 2, thumbIds)
			connectThumbImage(SmThumbRight, 3, thumbIds)

			if #thumbIds > 3 then
				MoreThumbsButton.Visible = true
				MoreThumbsButton.MouseButton1Click:connect(function()
					SoundManager:Play('ScreenChange');
					ImageOverlayModule(thumbIds, 1)
				end)
			end
		end
	end
	local function setRelatedGames(data)
		for i = 1, #RelatedGameImages do
			local image = RelatedGameImages[i]
			if data[i] then
				local thisData = data[i]
				local thumbLoader = ThumbnailLoader:Create(image, thisData.IconId,
					ThumbnailLoader.Sizes.Medium, ThumbnailLoader.AssetType.Icon)
				spawn(function()
					thumbLoader:LoadAsync()
				end)
				-- connect open detail event
				image.MouseButton1Click:connect(function()
					EventHub:dispatchEvent(EventHub.Notifications["OpenGameDetail"], thisData.PlaceId, thisData.Name, thisData.IconId)
				end)
				PopupText(image, thisData["Name"])
			end
		end
	end
	local function setScrollingTextBoxSelections(isSelectable)
		if isSelectable then
			local descriptionSelectionObject = DescriptionScrollingTextBox:GetSelectableObject()
			FavoriteButton.NextSelectionRight = descriptionSelectionObject
			descriptionSelectionObject.NextSelectionRight = MainThumbImage
			descriptionSelectionObject.NextSelectionLeft = FavoriteButton
		end
	end
	local function setVotingSelection()
		local defaultSelection = VoteView:GetDefaultSelection()
		if defaultSelection then
			defaultSelection.NextSelectionLeft = FavoriteButton
			FavoriteButton.NextSelectionRight = defaultSelection
			FavoriteButton.NextSelectionUp = defaultSelection
			DescriptionScrollingTextBox:GetSelectableObject().NextSelectionUp = defaultSelection
		end
	end
	local function setOverrideAvatarDisplay()
		local overrideFrame = Utility.Create'Frame'
		{
			Name = "OverrideFrame";
			Size = UDim2.new(1, 0, 0.1, 0);
			BackgroundTransparency = 1;
			Parent = DescriptionContainer;
		}
		local overrideText = Utility.Create'TextLabel'
		{
			Name = "OverrideText";
			Size = UDim2.new(0, 0, 0, 0);
			Position = UDim2.new(0, 190, 0.25, 0);
			BackgroundTransparency = 1;
			Font = GlobalSettings.BoldFont;
			FontSize = GlobalSettings.SubHeaderSize;
			TextColor3 = GlobalSettings.GreyTextColor;
			Text = Strings:LocalizedString("CustomAvatarPhrase");
			Parent = overrideFrame;
		}
		DescriptionScrollingTextBox:SetPosition(UDim2.new(0, 0, 0.1, 0))
		DescriptionScrollingTextBox:SetSize(UDim2.new(1, 0, 0.9, 0))
	end

	--[[ Initialize Content - Don't Block ]]--
	local scrollingTextBoxSelectableChangedCn = nil

	local function waitForTweensToFinish()
		while this and this.TransitionTweens and this.TransitionTweens[1] and not this.TransitionTweens[1]:IsFinished() do
			wait()
		end
	end
	local function concatTables(t1, t2)
		for _, value in pairs(t2) do
			table.insert(t1, value)
		end
	end
	do
		RatingDescriptionLineBreak.Visible = false
		DescriptionContainer.Visible = false

		local function loadFavoritedDataAsync()
			local data = getDataAsync()
			if not data then
				print("GameDetail:loadFavoritedDataAsync() could not fetch data.")
				return
			end

			-- set favorite
			isFavorited = data:GetIsFavoritedByUser()
			toggleFavoriteButton(isFavorited)
		end

		local function loadDescriptionDataAsync()
			local data = getDataAsync()
			if not data then
				print("GameDetail:loadDescriptionDataAsync() could not fetch data.")
				return
			end

			local descriptionData = data:GetDescription()
			local overridesDefaultAvatar = data:GetOverridesDefaultAvatar()
			if overridesDefaultAvatar then
				setOverrideAvatarDisplay()
			end

			DescriptionScrollingTextBox:SetText(descriptionData)
			scrollingTextBoxSelectableChangedCn = DescriptionScrollingTextBox.OnSelectableChaged:connect(function(value)
				setScrollingTextBoxSelections(value)
			end)
		end

		local function loadVoteDataAsync()
			local data = getDataAsync()
			if not data then
				print("GameDetail:loadVoteDataAsync() could not fetch data.")
				return
			end

			VoteView:SetParent(RatingDescriptionContainer)
			VoteView:InitializeAsync(data)
			local defaultSelection = VoteView:GetDefaultSelection()
			if defaultSelection then
				defaultSelection.NextSelectionLeft = FavoriteButton
			end
			FavoriteButton.NextSelectionRight = FavoriteButton.NextSelectionRight or defaultSelection
			FavoriteButton.NextSelectionUp = defaultSelection
			DescriptionScrollingTextBox:GetSelectableObject().NextSelectionUp = defaultSelection
		end

		local loader = LoadingWidget({Parent = RatingDescriptionContainer}, {loadFavoritedDataAsync, loadDescriptionDataAsync, loadVoteDataAsync, waitForTweensToFinish})
		spawn(function()
			loader:AwaitFinished()
			loader:Cleanup()
			loader = nil
			RatingDescriptionLineBreak.Visible = true
			DescriptionContainer.Visible = true
			VoteView:SetVisible(true)

			if this then
				this.TransitionTweens = this.TransitionTweens or {}
				concatTables(this.TransitionTweens, ScreenManager:FadeInSitu(RatingDescriptionLineBreak))
				concatTables(this.TransitionTweens, ScreenManager:FadeInSitu(DescriptionContainer))
			end
		end)
	end

	do
		local function loadMoreGameDetailsAsync()
			local data = getDataAsync()
			if not data then
				print("GameDetail:loadMoreGameDetailsAsync() could not fetch data.")
				return
			end

			-- set related games sort data
			local recommendedGames = data:GetRecommendedGamesAsync()
			setRelatedGames(recommendedGames)

			-- set more details
			LastUpdatedText.Text = data:GetLastUpdated()
			CreationDateText.Text = data:GetCreationDate()
			CreatorNameText.Text = data:GetCreatorName()
			MaxPlayersCountText.Text = data:GetMaxPlayers()
		end

		MoreDetailsContent.Visible = false
		local loader = LoadingWidget({Parent = MoreDetailsContainer}, {loadMoreGameDetailsAsync, waitForTweensToFinish})
		spawn(function()
			loader:AwaitFinished()
			loader:Cleanup()
			loader = nil
			MoreDetailsContent.Visible = true

			if this then
				this.TransitionTweens = this.TransitionTweens or {}
				concatTables(this.TransitionTweens, ScreenManager:FadeInSitu(MoreDetailsContent))
			end
		end)
	end

	do
		local gameThumbIds = nil
		local badgeData = nil
		local function loadThumbsAsync()
			local data = getDataAsync()
			if not data then
				print("GameDetail:loadThumbsAsync() could not fetch data.")
				return
			end

			gameThumbIds = data:GetThumbnailIdsAsync()
		end
		local function loadBadgeDataAsync()
			local data = getDataAsync()
			if not data then
				print("GameDetail:loadBadgeDataAsync() could not fetch data.")
				return
			end
			-- set badge data
			badgeData = data:GetBadgeDataAsync()
		end

		ThumbsContent.Visible = false
		local loader = LoadingWidget({Parent = ThumbsContainer}, {loadThumbsAsync, loadBadgeDataAsync, waitForTweensToFinish})
		spawn(function()
			loader:AwaitFinished()
			loader:Cleanup()
			loader = nil
			ThumbsContent.Visible = true

			-- set additional thumbnails
			setAdditionalThumbs(gameThumbIds)

			-- set badges
			local hasBadges = #badgeData >= 4
			setBadgeContainer(hasBadges, badgeData)

			if this then
				this.TransitionTweens = this.TransitionTweens or {}
				concatTables(this.TransitionTweens, ScreenManager:FadeInSitu(ThumbsContent))
				if BadgeContainer and BadgeContainer.Parent then
					concatTables(this.TransitionTweens, ScreenManager:FadeInSitu(BadgeContainer))
				end
			end
		end)
	end

	--[[ Public API ]]--

	--Override
	function this:GetDefaultSelectionObject()
		return PlayButton
	end

	-- Override
	local baseShow = this.Show
	function this:Show()
		baseShow(self)
		if joinOnShow then
			joinOnShow = false
			JoinGame()
		end
	end

	-- Override
	local baseFocus = this.Focus
	function this:Focus()
		baseFocus(self)
		selectionChangedCn = GuiService.Changed:connect(function(property)
			if property == 'SelectedCoreObject' then
				local newSelectedObject = GuiService.SelectedCoreObject
				if newSelectedObject and newSelectedObject:IsDescendantOf(GameDetailContainer) then
					checkTweenContent(newSelectedObject)
				end
			end
		end)
		gameJoinSuccessCn = GameJoinModule.OnGameJoinSuccess:connect(function(success)
			if success then
				VoteView:SetCanVote(true)
				setVotingSelection()
			end
		end)
	end

	-- Override
	local baseRemoveFocus = this.RemoveFocus
	function this:RemoveFocus()
		baseRemoveFocus(self)
		selectionChangedCn = Utility.DisconnectEvent(selectionChangedCn)
		gameJoinSuccessCn = Utility.DisconnectEvent(gameJoinSuccessCn)
		scrollingTextBoxSelectableChangedCn = Utility.DisconnectEvent(scrollingTextBoxSelectableChangedCn)
	end

	return this
end

return CreateGameDetail
