--[[
			// GameGenre.lua
			// Displays a game genre page for a certain sort

			TODO:
				Clean up code
]]
local CoreGui = Game:GetService("CoreGui")
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")
local ContextActionService = game:GetService("ContextActionService")
local GuiService = game:GetService('GuiService')
local PlatformService = nil
pcall(function() PlatformService = Game:GetService('PlatformService') end)

local Utility = require(Modules:FindFirstChild('Utility'))
local GlobalSettings = require(Modules:FindFirstChild('GlobalSettings'))
local GameDataModule = require(Modules:FindFirstChild('GameData'))
local SideBarModule = require(Modules:FindFirstChild('SideBar'))
local VoteFrameModule = require(Modules:FindFirstChild('VoteFrame'))
local Strings = require(Modules:FindFirstChild('LocalizedStrings'))
local SortCarousel = require(Modules:FindFirstChild('SortCarousel'))
local ScreenManager = require(Modules:FindFirstChild('ScreenManager'))
local AssetManager = require(Modules:FindFirstChild('AssetManager'))
local SortData = require(Modules:FindFirstChild('SortData'))
local GameJoinModule = require(Modules:FindFirstChild('GameJoin'))
local SoundManager = require(Modules:FindFirstChild('SoundManager'))
local Errors = require(Modules:FindFirstChild('Errors'))
local ErrorOverlayModule = require(Modules:FindFirstChild('ErrorOverlay'))

local CanShowDevNames = Utility.IsFastFlagEnabled("ShowDevNameInXboxApp")

local SORTS_TO_INDEX = { -- map of sort ids to index (used for selecting correct button in side bar)
	["MyFavorite"] = 1;
	["MyRecent"] = 2;
	["3"] = 3; 				-- Featured
	["1"] = 4;				-- Popular
	["11"] = 5;				-- Top Rated
	["8"] = 6;				-- Top Earning
}

local function CreateGameGenre(sortName, sortId)
	local this = {}

	local gameLoadCount = 20
	local sideBarSorts = {} -- array or sort names and ids for the side bar
	local baseButtonTextColor = GlobalSettings.WhiteTextColor
	local selectedButtonTextColor = GlobalSettings.TextSelectedColor

	local currentShownSortId = sortId
	--[[ Top Level Elements ]]--
	local GameGenreContainer = Utility.Create'Frame'
	{
		Name = "GameGenreContainer";
		Size = UDim2.new(1, 0, 1, 0);
		Position = UDim2.new(0, 0, 0, 0);
		BackgroundTransparency = 1;
		Visible = false;
		Parent = parent;
	}
	local BackLabel = Utility.Create'ImageLabel'
	{
		Name = "BackLabel";
		Position = UDim2.new(0, 0, 0, 0);
		BackgroundTransparency = 1;
		ZIndex = 2;
		Parent = GameGenreContainer;
	}
	AssetManager.LocalImage(BackLabel,
		'rbxasset://textures/ui/Shell/Icons/BackIcon', {['720'] = UDim2.new(0,32,0,32); ['1080'] = UDim2.new(0,48,0,48);})

	local BackText = Utility.Create'TextLabel'
	{
		Name = "BackText";
		Size = UDim2.new(0, 0, 0, BackLabel.Size.Y.Offset);
		Position = UDim2.new(0, BackLabel.Size.X.Offset + 8, 0, 0);
		BackgroundTransparency = 1;
		Font = GlobalSettings.RegularFont;
		FontSize = GlobalSettings.ButtonSize;
		TextXAlignment = Enum.TextXAlignment.Left;
		TextColor3 = GlobalSettings.WhiteTextColor;
		Text = '';
		Parent = GameGenreContainer;
	}
	local SideBarButton = Utility.Create'ImageButton'
	{
		Name = "SideBarButton";
		Size = UDim2.new(0, 450, 0, 75);
		Position = UDim2.new(0, 0, 0, BackLabel.Size.Y.Offset + 60);
		BackgroundTransparency = 1;
		BorderSizePixel = 0;
		BackgroundColor3 = GlobalSettings.GreySelectionColor;
		Parent = GameGenreContainer;

		SoundManager:CreateSound('MoveSelection');
	}
	SideBarButton.NextSelectionRight = SideBarButton
	SideBarButton.NextSelectionLeft = SideBarButton
	SideBarButton.SelectionGained:connect(function()
		SideBarButton.BackgroundTransparency = 0
	end)
	SideBarButton.SelectionLost:connect(function()
		SideBarButton.BackgroundTransparency = 1
	end)

	local DropDownImage = Utility.Create'ImageLabel'
	{
		Name = "DropDownImage";
		BackgroundTransparency = 1;
		Parent = SideBarButton;
	}
	AssetManager.LocalImage(DropDownImage,
		'rbxasset://textures/ui/Shell/Icons/Dropdown02', {['720'] = UDim2.new(0,29,0,29); ['1080'] = UDim2.new(0,44,0,44);})
	DropDownImage.Position = UDim2.new(1, -DropDownImage.Size.X.Offset - 12, 0.5, -DropDownImage.Size.Y.Offset / 2 + 4)

	local SideBar = SideBarModule()
	SideBarButton.MouseButton1Click:connect(function()
		SideBar:SetSelectedObject(SORTS_TO_INDEX[tostring(currentShownSortId)])
		ScreenManager:OpenScreen(SideBar, false)
	end)

	local TitleLabel = Utility.Create'TextLabel'
	{
		Name = "TitleLabel";
		Size = UDim2.new(0, 0, 0, 0);
		Position = UDim2.new(0, 18, 0.5, 0);
		BackgroundTransparency = 1;
		Text = string.upper(sortName);
		TextColor3 = GlobalSettings.WhiteTextColor;
		TextXAlignment = Enum.TextXAlignment.Left;
		Font = GlobalSettings.LightFont;
		FontSize = GlobalSettings.HeaderSize;
		ZIndex = 2;
		Parent = SideBarButton;
	}
	local GameTitleLabel = Utility.Create'TextLabel'
	{
		Name = "GameTitleLabel";
		Size = UDim2.new(0, 0, 0, 0);
		Position = UDim2.new(0, 18, 0, SideBarButton.Position.Y.Offset + SideBarButton.Size.Y.Offset + 550);
		BackgroundTransparency = 1;
		Text = "";
		TextColor3 = GlobalSettings.WhiteTextColor;
		TextXAlignment = Enum.TextXAlignment.Left;
		Font = GlobalSettings.LightFont;
		FontSize = GlobalSettings.HeaderSize;
		Parent = GameGenreContainer;
	}
	local ThumbsUpImage = Utility.Create'ImageLabel'
	{
		Name = "ThumbsUpImage";
		BackgroundTransparency = 1;
		ZIndex = 2;
		Visible = false;
		Parent = GameGenreContainer;
	}
	local ThumbsDownImage = Utility.Create'ImageLabel'
	{
		Name = "ThumbsDownImage";
		BackgroundTransparency = 1;
		ZIndex = 2;
		Visible = false;
		Parent = GameGenreContainer;
	}
	AssetManager.LocalImage(ThumbsUpImage,
		'rbxasset://textures/ui/Shell/Icons/ThumbsUpIcon', {['720'] = UDim2.new(0,19,0,19); ['1080'] = UDim2.new(0,28,0,28);})
	AssetManager.LocalImage(ThumbsDownImage,
		'rbxasset://textures/ui/Shell/Icons/ThumbsDownIcon', {['720'] = UDim2.new(0,19,0,19); ['1080'] = UDim2.new(0,28,0,28);})

	local VoteWidget = VoteFrameModule(GameGenreContainer,
		UDim2.new(0, 60, 0, GameTitleLabel.Position.Y.Offset + 46))
	local VoteContainer = VoteWidget:GetContainer()
	ThumbsUpImage.Position = UDim2.new(0, VoteContainer.Position.X.Offset - ThumbsUpImage.Size.X.Offset - 10, 0,
		VoteContainer.Position.Y.Offset + VoteContainer.Size.Y.Offset - ThumbsUpImage.Size.Y.Offset)
	ThumbsDownImage.Position = UDim2.new(0, VoteContainer.Position.X.Offset + VoteContainer.Size.X.Offset + 10, 0,
		VoteContainer.Position.Y.Offset)

	local SeparatorDot = Utility.Create'ImageLabel'
	{
		Name = "SeparatorDot";
		BackgroundTransparency = 1;
		Visible = false;
		Parent = GameGenreContainer;
	}
	AssetManager.LocalImage(SeparatorDot,
		'rbxasset://textures/ui/Shell/Icons/SeparatorDot', {['720'] = UDim2.new(0,7,0,7); ['1080'] = UDim2.new(0,10,0,10);})
	SeparatorDot.Position = UDim2.new(0, ThumbsDownImage.Position.X.Offset + ThumbsDownImage.Size.X.Offset + 32, 0,
		VoteContainer.Position.Y.Offset + (VoteContainer.Size.Y.Offset/2) - (SeparatorDot.Size.Y.Offset/2))

	local CreatorIcon = Utility.Create'ImageLabel'
	{
		Name = "CreatorIcon";
		Size = UDim2.new(0, 24, 0, 24);
		Position = UDim2.new(0, SeparatorDot.Position.X.Offset + SeparatorDot.Size.X.Offset + 32, 0,
			SeparatorDot.Position.Y.Offset + SeparatorDot.Size.Y.Offset/2 - 2 - 10);
		BackgroundTransparency = 1;
		Image = 'rbxasset://textures/ui/Shell/Icons/RobloxIcon.png';
		Parent = GameGenreContainer;
	}

	local CreatorNameLabel = Utility. Create'TextLabel'
	{
		Name = "CreatorNameLabel";
		Size = UDim2.new(0, 0, 0, 0);
		Position = UDim2.new(0, CreatorIcon.Position.X.Offset + CreatorIcon.Size.X.Offset + 8, 0,
			SeparatorDot.Position.Y.Offset + SeparatorDot.Size.Y.Offset/2 - 2);
		BackgroundTransparency = 1;
		Font = GlobalSettings.RegularFont;
		FontSize = GlobalSettings.DescriptionSize;
		TextColor3 = GlobalSettings.LightGreyTextColor;
		TextXAlignment = Enum.TextXAlignment.Left;
		Text = "";
		Parent = GameGenreContainer;
	}

	local DescriptionTextLabel = Utility.Create'TextLabel'
	{
		Name = "DescriptionTextLabel";
		Size = UDim2.new(0, 850, 0, 56);
		Position = UDim2.new(0, GameTitleLabel.Position.X.Offset, 0, VoteContainer.Position.Y.Offset + VoteContainer.Size.Y.Offset + 20);
		BackgroundTransparency = 1;
		Text = "";
		TextColor3 = GlobalSettings.LightGreyTextColor;
		TextXAlignment = Enum.TextXAlignment.Left;
		TextYAlignment = Enum.TextYAlignment.Top;
		Font = GlobalSettings.LightFont;
		TextWrapped = true;
		FontSize = GlobalSettings.DescriptionSize;
		Parent = GameGenreContainer;
	}
	local PlayButton = Utility.Create'ImageButton'
	{
		Name = "PlayButton";
		Position = UDim2.new(0, 0, 1, -77);
		Size = UDim2.new(0, 228, 0, 72);
		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 = GameGenreContainer;

		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";
		Position = UDim2.new(0, PlayButton.Size.X.Offset + 10, 1, -77);
		Size = UDim2.new(0, 228, 0, 72);
		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));
		ZIndex = 2;
		Parent = GameGenreContainer;

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

	FavoriteButton.NextSelectionRight = FavoriteButton
	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)

	-- Selection Overrides
	-- NOTE: This is a fix to prevent unintended selection in the carousel do to the nature of
	-- how selection works for a ScrollingFrame.
	PlayButton.NextSelectionLeft = PlayButton
	FavoriteButton.NextSelectionRight = FavoriteButton
	SideBarButton.NextSelectionLeft = SideBarButton
	SideBarButton.NextSelectionRight = SideBarButton

	--[[ Page Events ]]--
	local function toggleFavoriteButton(isFavorited)
		if isFavorited == 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 isFavorited == 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
	FavoriteButton.SelectionGained:connect(function()
		FavoriteButton.ImageColor3 = GlobalSettings.GreySelectedButtonColor
		FavoriteText.TextColor3 = selectedButtonTextColor
	end)
	FavoriteButton.SelectionLost:connect(function()
		FavoriteButton.ImageColor3 = GlobalSettings.GreyButtonColor
		FavoriteText.TextColor3 = baseButtonTextColor
	end)
	PlayButton.SelectionGained:connect(function()
		PlayButton.ImageColor3 = GlobalSettings.GreenSelectedButtonColor
		PlayText.TextColor3 = selectedButtonTextColor
	end)
	PlayButton.SelectionLost:connect(function()
		PlayButton.ImageColor3 = GlobalSettings.GreenButtonColor
		PlayText.TextColor3 = baseButtonTextColor
	end)

	--[[ Content Initialization ]]--
	local function setItemsVisible(value)
		ThumbsUpImage.Visible = value
		ThumbsDownImage.Visible = value
		VoteWidget:SetVisible(value)
		GameTitleLabel.Visible = value
		DescriptionTextLabel.Visible = value
		--
		SeparatorDot.Visible = CanShowDevNames and value or false
		CreatorIcon.Visible = CanShowDevNames and value or false
		CreatorNameLabel.Visible = CanShowDevNames and value or false
	end

	local currentSortCarousel = nil
	local currentItemData = nil
	local onNewGameSelectedCn = nil
	local onNewGameSelectedLateCn = nil
	local function setCurrentSortCarousel()
		setItemsVisible(false)
		toggleFavoriteButton(false)
		currentSortCarousel = SortCarousel(UDim2.new(1, 0, 0, 450),
			UDim2.new(0, 0, 0, SideBarButton.Position.Y.Offset + SideBarButton.Size.Y.Offset + 56), currentShownSortId, GameGenreContainer)
		onNewGameSelectedCn = currentSortCarousel.OnNewGameSelected:connect(function(itemData)
			if itemData then
				currentItemData = itemData
				GameTitleLabel.Text = itemData.Name
				DescriptionTextLabel.Text = itemData.Description or ""
				CreatorNameLabel.Text = itemData.CreatorName
				toggleFavoriteButton(itemData.IsFavorited)
				local voteData = itemData.VoteData
				if voteData then
					local upvotes = voteData.UpVotes
					local downvotes = voteData.DownVotes
					if upvotes == 0 and downvotes == 0 then
						VoteWidget:SetPercentFilled(nil)
					else
						VoteWidget:SetPercentFilled(upvotes / (upvotes + downvotes))
					end
				end
				setItemsVisible(true)
			end
		end)
		onNewGameSelectedLateCn = currentSortCarousel.OnNewGameSelectedLate:connect(function(description, isFavorited)
			toggleFavoriteButton(isFavorited)
			DescriptionTextLabel.Text = description or ""
		end)
	end
	setCurrentSortCarousel()

	local function canShowFavorites()
		local favorties = SortData.GetSort('MyFavorite', false)
		local favoritesPage = favorties:GetCurrentPageAsync(1)
		return favoritesPage and #favoritesPage:GetPagePlaceIds() >= 1
	end
	local function canShowRecent()
		local recent = SortData.GetSort('MyRecent', false)
		local recentPage = recent:GetCurrentPageAsync(1)
		return recentPage and #recentPage:GetPagePlaceIds() >= 1
	end
	local function buildSideBarList()
		if canShowFavorites() then
			table.insert(sideBarSorts,
				{ Name = string.upper(Strings:LocalizedString("FavoritedWord")), Id = "MyFavorite"})
		end
		if canShowRecent() then
			table.insert(sideBarSorts,
				{ Name = string.upper(Strings:LocalizedString("RecentlyPlayedSortTitle")), Id = "MyRecent" })
		end
		table.insert(sideBarSorts, { Name = string.upper(Strings:LocalizedString("FeaturedTitle")), Id = "3" })
		table.insert(sideBarSorts, { Name = string.upper(Strings:LocalizedString("PopularTitle")), Id = "1" })
		table.insert(sideBarSorts, { Name = string.upper(Strings:LocalizedString("TopRatedTitle")), Id = "11" })
		table.insert(sideBarSorts, { Name = string.upper(Strings:LocalizedString("TopEarningTitle")), Id = "8" })
	end
	--
	spawn(function()
		buildSideBarList()
		for i = 1, #sideBarSorts do
			local sort = sideBarSorts[i]
			SideBar:AddItem(sort.Name, function()
				if sort.Id ~= currentShownSortId then
					currentSortCarousel:Destroy()
					currentShownSortId = sort.Id
					TitleLabel.Text = sort.Name
					SideBarButton.BackgroundTransparency = 1;
					setCurrentSortCarousel()
					if this.TransitionTweens then
						ScreenManager:DefaultCancelFade(this.TransitionTweens)
						this.TransitionTweens = ScreenManager:DefaultFadeIn(GameGenreContainer)
					end
				end
			end)
		end
	end)

	--[[ Input Events ]]--
	PlayButton.MouseButton1Click:connect(function()
		SoundManager:Play('ButtonPress')
		local gameData = currentSortCarousel:GetCurrentSelectedGameData()
		if gameData then
			local placeId = gameData.PlaceId
			GameJoinModule:StartGame(GameJoinModule.JoinType.Normal, placeId)
		end
	end)

	FavoriteButton.MouseButton1Click:connect(function()
		SoundManager:Play('ButtonPress')
		if currentItemData and currentItemData.GameData then
			local success, reason = currentItemData.GameData:PostFavoriteAsync()
			if success then
				currentItemData.IsFavorited = currentItemData.GameData:GetIsFavoritedByUser()
				toggleFavoriteButton(currentItemData.IsFavorited)
			elseif reason then
				local err = Errors.Favorite[reason]
				ScreenManager:OpenScreen(ErrorOverlayModule(err), false)
			end
		end
	end)

	--[[ Public API ]]--
	function this:SetPosition(newPosition)
		GameGenreContainer.Position = newPosition
	end

	function this:SetParent(newParent)
		GameGenreContainer.Parent = newParent
	end

	function this:GetName()
		return TitleLabel.Text
	end

	function this:Show()
		GameGenreContainer.Visible = true

		local prevScreen = ScreenManager:GetScreenBelow(self)
		if prevScreen and prevScreen.GetName then
			BackText.Text = prevScreen:GetName()
		else
			BackText.Text = ''
		end

		self.TransitionTweens = ScreenManager:DefaultFadeIn(GameGenreContainer)
		ScreenManager:PlayDefaultOpenSound()
	end

	function this:Hide()
		GameGenreContainer.Visible = false
		ScreenManager:DefaultCancelFade(self.TransitionTweens)
		self.TransitionTweens = nil
	end

	function this:Destroy()
		if onNewGameSelectedCn then
			onNewGameSelectedCn:disconnect()
			onNewGameSelectedCn = nil
		end
		currentSortCarousel:Destroy()
		VoteWidget:Destroy()
		GameGenreContainer:Destroy()
	end

	function this:Focus()
		if self.SavedSelectedObject and self.SavedSelectedObject:IsDescendantOf(GameGenreContainer) then
			GuiService.SelectedCoreObject = self.SavedSelectedObject
		end
		ContextActionService:BindCoreAction("ReturnFromGameGenreScreen",
			function(actionName, inputState, inputObject)
				if inputState == Enum.UserInputState.End then
					ScreenManager:CloseCurrent()
					self:Destroy()
				end
			end,
			false,
			Enum.KeyCode.ButtonB)
	end

	function this:RemoveFocus()
		local selectedObject = GuiService.SelectedCoreObject
		if selectedObject and selectedObject:IsDescendantOf(GameGenreContainer) then
			self.SavedSelectedObject = selectedObject
			GuiService.SelectedCoreObject = nil
		end
		ContextActionService:UnbindCoreAction("ReturnFromGameGenreScreen")
	end

	return this
end

return CreateGameGenre
