--[[
			// FriendsView.lua

			// Creates a view for the users friends.
			// Handles user input, updating view

			TODO:
				Connect selected/deselected to change color
]]
local CoreGui = Game:GetService("CoreGui")
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")
local ShellModules = Modules:FindFirstChild("Shell")
local PlatformService = nil
pcall(function() PlatformService = game:GetService('PlatformService') end)
local UserInputService = game:GetService('UserInputService')
local GuiService = game:GetService('GuiService')

local FriendsData = require(ShellModules:FindFirstChild('FriendsData'))
local FriendPresenceItem = require(ShellModules:FindFirstChild('FriendPresenceItem'))
local SideBarModule = require(ShellModules:FindFirstChild('SideBar'))
local Strings = require(ShellModules:FindFirstChild('LocalizedStrings'))
local GameJoinModule = require(ShellModules:FindFirstChild('GameJoin'))
local Errors = require(ShellModules:FindFirstChild('Errors'))
local ErrorOverlayModule = require(ShellModules:FindFirstChild('ErrorOverlay'))
local EventHub = require(ShellModules:FindFirstChild('EventHub'))
local ScreenManager = require(ShellModules:FindFirstChild('ScreenManager'))
local Analytics = require(ShellModules:FindFirstChild('Analytics'))

-- Array of tables
	-- see FriendsData - fetchXboxFriends() for full documentation
local myFriendsData = nil

local FOLLOW_MODE = 2

local SIDE_BAR_ITEMS = {
	JoinGame =  string.upper(Strings:LocalizedString("JoinGameWord"));
	ViewDetails = string.upper(Strings:LocalizedString("ViewGameDetailsWord"));
	ViewProfile = string.upper(Strings:LocalizedString("ViewGamerCardWord"));
}

-- side bar is shared between all views
local SideBar = SideBarModule()

local function setPresenceData(item, data)
	if UserSettings().GameSettings:InStudioMode() or game:GetService('UserInputService'):GetPlatform() == Enum.Platform.Windows then
		item:SetAvatarImage(data.UserId)
		item:SetNameText(data.Name)
		item:SetPresence(data.LastLocation, data.PlaceId ~= nil)
	elseif UserInputService:GetPlatform() == Enum.Platform.XBoxOne then
		local rbxuid = data["robloxuid"]
		item:SetAvatarImage(rbxuid)
		item:SetNameText(data["display"])
		if data["PlaceId"] and data["LastLocation"] then
			item:SetPresence(data["LastLocation"], true)
		elseif data["rich"] then
			local richTbl = data["rich"]
			local presence = richTbl[#richTbl]
			item:SetPresence(presence["title"], false)
		end
	end
end

-- viewGridContainer - ScrollingGrid
-- friendData - FriendsData
-- sizeConstraint - limit view to this many items
-- updateFunc - function that will be called when FriendData update
local createFriendsView = function(viewGridContainer, friendsData, sizeConstraint, updateFunc)
	local this = {}

	-- map of userId to presenceItem
	local presenceItems = {}
	local selectedItemOnFocus = nil
	local guiObjectToSortIndex = {}
	local presenceItemToData = {}

	local count = #friendsData
	if sizeConstraint then
		count = math.min(count, sizeConstraint)
	end

	local function connectSideBar(item)
		local container = item:GetContainer()
		container.MouseButton1Click:connect(function()
			local data = presenceItemToData[item]
			if data then
				-- rebuild side bar based on current data
				SideBar:RemoveAllItems()
				function SideBar:GetAnalyticsInfo()
					return {[Analytics.WidgetNames('WidgetId')] = "FriendsSideBar"}
				end
				local inGame = data["PlaceId"] ~= nil
				if inGame and not data["IsPrivateSession"] then
					SideBar:AddItem(SIDE_BAR_ITEMS.JoinGame, function()
						GameJoinModule:StartGame(GameJoinModule.JoinType.Follow, data["robloxuid"])
					end)
					SideBar:AddItem(SIDE_BAR_ITEMS.ViewDetails, function()
						-- pass nil for iconId, gameDetail will fetch
						EventHub:dispatchEvent(EventHub.Notifications["OpenGameDetail"], data["PlaceId"], data["LastLocation"], nil)
					end)
				end
				SideBar:AddItem(SIDE_BAR_ITEMS.ViewProfile, function()
					if PlatformService and data["xuid"] then
						local success, result = pcall(function()
							PlatformService:PopupProfileUI(Enum.UserInputType.Gamepad1, data["xuid"])
						end)
						-- NOTE: This will try to pop up the xbox system gamer card, failure will be handled
						-- by the xbox.
						if not success then
							print("PlatformService:PopupProfileUI failed because,", result)
						end
					end
				end)
				ScreenManager:OpenScreen(SideBar, false)
			else
				ScreenManager:OpenScreen(ErrorOverlayModule(Errors.Default), false)
			end
		end)
	end

	-- initialize view
	for i = 1, count do
		local data = friendsData[i]
		if data then
			local idStr = tostring(data.UserId or data["robloxuid"])
			local presenceItem = FriendPresenceItem(UDim2.new(0, 446, 0, 114), idStr)
			presenceItems[idStr] = presenceItem
			presenceItemToData[presenceItem] = data
			viewGridContainer:AddItem(presenceItem:GetContainer())
			setPresenceData(presenceItem, data)
			connectSideBar(presenceItem)
			if not selectedItemOnFocus then
				selectedItemOnFocus = presenceItem:GetContainer()
			end
			guiObjectToSortIndex[presenceItem:GetContainer()] = i
		end
	end

	local function onFriendsUpdated(newFriendsData)
		local size = #newFriendsData
		if sizeConstraint then
			size = math.min(size, sizeConstraint)
		end

		-- map of valid userIds to bool
		local validEntries = {}

		-- a,b are guiObjects
		local function sortGridItems(a, b)
			if guiObjectToSortIndex[a] and guiObjectToSortIndex[b] then
				return guiObjectToSortIndex[a] < guiObjectToSortIndex[b]
			end
			if guiObjectToSortIndex[a] then return true end
			if guiObjectToSortIndex[b] then return false end
			return a.Name < b.Name
		end

		-- refresh view
		for i = 1, size do
			local data = newFriendsData[i]
			if data then
				local idStr = tostring(data.UserId or data["robloxuid"])
				local presenceItem = presenceItems[idStr]
				if not presenceItem then
					presenceItem = FriendPresenceItem(UDim2.new(0, 446, 0, 114), idStr)
					presenceItems[idStr] = presenceItem
					viewGridContainer:AddItem(presenceItem:GetContainer())
					connectSideBar(presenceItem)
				end
				presenceItemToData[presenceItem] = data
				setPresenceData(presenceItem, data)
				validEntries[idStr] = true
				guiObjectToSortIndex[presenceItem:GetContainer()] = i
				if i == 1 then
					selectedItemOnFocus = presenceItem:GetContainer()
				end
			end
		end

		-- remove items if needed
		for userId,presenceItem in pairs(presenceItems) do
			if not validEntries[userId] then
				local container = presenceItem:GetContainer()
				guiObjectToSortIndex[container] = nil
				viewGridContainer:RemoveItem(container)
				presenceItems[userId] = nil
				presenceItem:Destroy()
				presenceItem = nil
			end
		end

		viewGridContainer:SortItems(sortGridItems)

		if updateFunc then
			updateFunc(#newFriendsData)
		end
	end

	FriendsData.ConnectUpdateEvent(onFriendsUpdated)

	function this:GetDefaultFocusItem()
		return selectedItemOnFocus
	end

	return this
end

return createFriendsView
