--[[
			// SortCarousel.lua
			// Creates a sort carousel with data for the sort
]]
local CoreGui = Game:GetService("CoreGui")
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")

local EventHub = require(Modules:FindFirstChild('EventHub'))
local GameDataModule = require(Modules:FindFirstChild('GameData'))
local ImageSlider = require(Modules:FindFirstChild('ImageSlider'))
local SortData = require(Modules:FindFirstChild('SortData'))
local Utility = require(Modules:FindFirstChild('Utility'))
local ThumbnailLoader = require(Modules:FindFirstChild('ThumbnailLoader'))
local GlobalSettings = require(Modules:FindFirstChild('GlobalSettings'))
local LoadingWidget = require(Modules:FindFirstChild('LoadingWidget'))
local SoundManager = require(Modules:FindFirstChild('SoundManager'))
local AssetManager = require(Modules:FindFirstChild('AssetManager'))

local createSortCarousel = function(size, position, sortId, parent)
	local this = {}

	--[[ Constants ]]--
	local LOAD_COUNT = 20
	local IMAGE_COUNT = 9

	local carousel = ImageSlider(size, position)
	carousel:SetPadding(18)
	carousel:SetParent(parent)

	--[[ Variables ]]--
	local sortData = SortData.GetSort(sortId, false)
	local images = {}
	local gameData = {}
	local lastSelectedIndex = nil
	local lastLoadedCount = 0

	--[[ Event ]]--
	this.OnNewGameSelected = Utility.Signal()
	-- we need to fetch for description/isFavorited, so we send a late signal to update those
	this.OnNewGameSelectedLate = Utility.Signal()

	--[[ Private Functions ]]--
	local function insertSortData(page)
		if not page then
			print("Error: SortCarousel failed to get a valid page for insertSortData.")
			return
		end
		-- TODO: Get new square icons
		local ids = page:GetPagePlaceIds()
		local names = page:GetPagePlaceNames()
		local voteData = page:GetPageVoteData()
		local iconIds = page:GetPageIconIds()
		local creatorNames = page:GetCreatorNames()
		--
		for i = 1, #page.Data do
			local entry = {
				Name = names[i];
				PlaceId = ids[i];
				IconId = iconIds[i];
				VoteData = voteData[i];
				CreatorName = creatorNames[i];
				-- Description/IsFavorited needs to be queried for each game, do it only when needed
				-- we'll also cache gameData
				Description = nil;
				IsFavorited = nil;
				GameData = nil;
			}
			gameData[#gameData + 1] = entry
		end
		lastLoadedCount = #gameData
	end

	local function createCarouselImages()
		local thumbSize = ThumbnailLoader.Sizes.Medium
		local assetType = ThumbnailLoader.AssetType.Icon
		for i = 1, IMAGE_COUNT do
			local data = gameData[i]
			if data then
				local image = Utility.Create'ImageButton'
				{
					Name = "GameImage";
					BorderSizePixel = 0;
					BackgroundColor3 = GlobalSettings.GreyButtonColor;
					ZIndex = 2;

					SoundManager:CreateSound('MoveSelection');
					AssetManager.CreateShadow(1);
				}
				local thumbLoader = ThumbnailLoader:Create(image, data.IconId, thumbSize, assetType)
				spawn(function()
					if not thumbLoader:LoadAsync() then
						-- TODO
					end
				end)
				images[#images + 1] = image
				carousel:AddItem(image)

				-- connect button press based on current selected index mapped to gameData
				image.MouseButton1Click:connect(function()
					if lastSelectedIndex and gameData[lastSelectedIndex] then
						local currentData = gameData[lastSelectedIndex]
						EventHub:dispatchEvent(EventHub.Notifications["OpenGameDetail"], currentData.PlaceId,
							currentData.Name, currentData.IconId, currentData.GameData)
					end
				end)
			end
		end
	end

	--[[ Event Connections ]]--
	local nextLoadIndex = 0
	local lastSelectedObject = nil
	local onNewFocusCn = nil
	onNewFocusCn = carousel.OnNewFocusItem:connect(function(newIndex, isRight, selectedObject)
		lastSelectedObject = selectedObject
		lastSelectedIndex = newIndex
		--
		if gameData[newIndex] then
			local currentData = gameData[newIndex]
			if this then
				this.OnNewGameSelected:fire(currentData)
			end

			-- description/isFavorited needs to fetch, so send a late update
			spawn(function()
				if not currentData.GameData then
					local gameData = GameDataModule:GetGameDataAsync(currentData.PlaceId)
					if gameData then
						currentData.GameData = gameData
						currentData.Description = gameData:GetDescription()
						currentData.IsFavorited = gameData:GetIsFavoritedByUser()
					end
				end
				if this and selectedObject == lastSelectedObject then
					this.OnNewGameSelectedLate:fire(currentData.Description, currentData.IsFavorited)
				end
			end)
		end

		-- load more data
		if isRight and #gameData > IMAGE_COUNT and newIndex == nextLoadIndex then
			nextLoadIndex = nextLoadIndex + LOAD_COUNT
			local page = sortData:AdvanceToNextPageAsync(LOAD_COUNT)
			insertSortData(page)
			carousel:SetMaxItems(#gameData)
		end
	end)

	--[[ Public API ]]--
	function this:SetParent(newParent)
		carousel:SetParent(newParent)
	end

	function this:GetCurrentSelectedGameData()
		if gameData[lastSelectedIndex] then
			return gameData[lastSelectedIndex]
		end
	end

	function this:Destroy()
		carousel:Destroy()
		if onNewFocusCn then
			onNewFocusCn:disconnect()
			onNewFocusCn = nil
		end
		spawn(function()
			gameData = nil
			this = nil
		end)
	end

	--[[ Initialization ]]--
	local function loadSort()
		local page = sortData:GetCurrentPageAsync(LOAD_COUNT)
		insertSortData(page)
		createCarouselImages()
		if carousel then
			carousel:SetDataTable(gameData)
			carousel:SetMaxItems(#gameData)
			carousel:SetFocusPosition(1)
			nextLoadIndex = LOAD_COUNT / 2
		end
	end

	local loader = LoadingWidget(
		{ Parent = parent }, { loadSort }
	)

	spawn(function()
		loader:AwaitFinished()
		loader:Cleanup()
	end)

	return this
end

return createSortCarousel
