-- Written by Kip Turner, Copyright ROBLOX 2015

local CoreGui = game:GetService("CoreGui")
local ContextActionService = game:GetService("ContextActionService")
local PlatformService = game:GetService('PlatformService')
local UserInputService = game:GetService("UserInputService")
local GuiService = game:GetService('GuiService')
local TextService = game:GetService('TextService')

local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")

local Utility = require(Modules:FindFirstChild('Utility'))
local GlobalSettings = require(Modules:FindFirstChild('GlobalSettings'))
local AppTabDockModule = require(Modules:FindFirstChild('TabDock'))
local AppTabDockItemModule = require(Modules:FindFirstChild('TabDockItem'))
local HomePaneModule = require(Modules:FindFirstChild('HomePane'))
local GamePaneModule = require(Modules:FindFirstChild('GamePane'))
local AvatarPaneModule = require(Modules:FindFirstChild('AvatarPane'))
local Errors = require(Modules:FindFirstChild('Errors'))
local ErrorOverlay = require(Modules:FindFirstChild('ErrorOverlay'))
local EventHub = require(Modules:FindFirstChild('EventHub'))
local ScreenManager = require(Modules:FindFirstChild('ScreenManager'))
local SocialPaneModule = require(Modules:FindFirstChild('SocialPane'))
local StorePaneModule = require(Modules:FindFirstChild('StorePane'))
local Strings = require(Modules:FindFirstChild('LocalizedStrings'))
local AssetManager = require(Modules:FindFirstChild('AssetManager'))
local SoundManager = require(Modules:FindFirstChild('SoundManager'))
local SettingsScreen = require(Modules:FindFirstChild('SettingsScreen'))

local AccountLinkingEnabled = Utility.IsFastFlagEnabled("AccountLinkEnabled")

local function CreateAppHub()
	local this = {}
	-- Game.CoreGui.SelectionImageObject = Instance.new('ImageLabel')

	local AppTabDock = AppTabDockModule()
	local appHubCns = {}
	local selectionChangedConn = nil

	local lastSelectedContentPane = nil
	local lastParent = nil

	local HubContainer = Utility.Create'Frame'
	{
		Name = 'HubContainer';
		Size = UDim2.new(1, 0, 1, 0);
		BackgroundTransparency = 1;
		Visible = false;
	}

	local PaneContainer = Utility.Create'Frame'
	{
		Name = 'PaneContainer';
		Size = UDim2.new(1, 0, 0.786, 0);
		Position = UDim2.new(0,0,0.214,0);
		BackgroundTransparency = 1;
		Parent = HubContainer;
	}

	AppTabDock:SetParent(HubContainer)
	AppTabDock:SetPosition(UDim2.new(0,0,0.132,0))
	local HomeTab = AppTabDock:AddTab(AppTabDockItemModule(Strings:LocalizedString('HomeWord'):upper(), HomePaneModule(PaneContainer)))
	local AvatarTab = AppTabDock:AddTab(AppTabDockItemModule(Strings:LocalizedString('AvatarWord'):upper(), AvatarPaneModule(PaneContainer)))
	local GameTab = AppTabDock:AddTab(AppTabDockItemModule(Strings:LocalizedString('GameWord'):upper(), GamePaneModule(PaneContainer)))
	local SocialTab = AppTabDock:AddTab(AppTabDockItemModule(Strings:LocalizedString('FriendsWord'):upper(), SocialPaneModule(PaneContainer)))
	local StoreTab = AppTabDock:AddTab(AppTabDockItemModule(Strings:LocalizedString('CatalogWord'):upper(), StorePaneModule(PaneContainer)))


	local RobloxLogo = Utility.Create'ImageLabel'
	{
		Name = 'RobloxLogo';
		Position = UDim2.new(0,0,0,0);
		BackgroundTransparency = 1;
		Parent = HubContainer;
	}
	AssetManager.LocalImage(RobloxLogo, 'rbxasset://textures/ui/Shell/Icons/ROBLOXLogoSmall', {['720'] = UDim2.new(0,145,0,37); ['1080'] = UDim2.new(0,215,0,55);})

	-- Positin/Size set after text bounds set
	local BoundHintContainer = Utility.Create'Frame'
	{
		Name = "BoundHintContainer";
		BackgroundTransparency = 1;
		Visible = false;
		Parent = AccountLinkingEnabled and HubContainer or nil;
	}
	local BoundHintText = Utility.Create'TextLabel'
	{
		Name = "BoundHintText";
		BackgroundTransparency = 1;
		Font = GlobalSettings.RegularFont;
		FontSize = GlobalSettings.TitleSize;
		TextColor3 = GlobalSettings.WhiteTextColor;
		TextXAlignment = GlobalSettings.Right;
		Text = "";
		Parent = BoundHintContainer;
	}
	local BoundHintImage = Utility.Create'ImageLabel'
	{
		Name = "BoundHintImage";
		Size = UDim2.new(0, 83, 0, 83);
		BackgroundTransparency = 1;
		Image = 'rbxasset://textures/ui/Shell/ButtonIcons/XButton.png';
		Parent = BoundHintContainer;
	}

	local function setHintText(newText)
		local textSize = TextService:GetTextSize(newText, 42, BoundHintText.Font, Vector2.new(0, 0))
		BoundHintText.Size = UDim2.new(0, textSize.x, 0, 83)
		BoundHintText.Position = UDim2.new(1, -textSize.x, 0, 0)
		BoundHintText.Text = newText
		BoundHintContainer.Size = UDim2.new(0, textSize.x + BoundHintImage.Size.X.Offset, 0, 83)
		BoundHintContainer.Position = UDim2.new(1, -BoundHintContainer.Size.X.Offset, 1, -BoundHintContainer.Size.Y.Offset)
		BoundHintContainer.Visible = true
	end

	local seenXButtonPressed = false
	local function onOpenSettings(actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Begin then
			seenXButtonPressed = true
		elseif inputState == Enum.UserInputState.End and seenXButtonPressed then
			local settingsScreen = SettingsScreen()
			EventHub:dispatchEvent(EventHub.Notifications["OpenSettingsScreen"], settingsScreen);
		end
	end

	local function onOpenPartyUI(actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Begin then
			seenXButtonPressed = true
		elseif inputState == Enum.UserInputState.End and seenXButtonPressed then
			if UserSettings().GameSettings:InStudioMode() then
				ScreenManager:OpenScreen(ErrorOverlay(Errors.Test.FeatureNotAvailableInStudio), false)
			else
				local success, result = pcall(function()
					return PlatformService:PopupPartyUI(inputObject.UserInputType)
				end)
				if not success then
					ScreenManager:OpenScreen(ErrorOverlay(Errors.PlatformError.PopupPartyUI), false)
				end
			end
		end
	end

	local function setHintAction(selectedTab)
		if AccountLinkingEnabled then
			ContextActionService:UnbindCoreAction("OpenHintAction")
			BoundHintContainer.Visible = false
			if selectedTab == HomeTab then
				setHintText(Strings:LocalizedString("SettingsWord"))
				ContextActionService:BindCoreAction("OpenHintAction", onOpenSettings, false, Enum.KeyCode.ButtonX)
			elseif selectedTab == SocialTab then
				setHintText(Strings:LocalizedString("StartPartyPhrase"))
				ContextActionService:BindCoreAction("OpenHintAction", onOpenPartyUI, false, Enum.KeyCode.ButtonX)
			end
		end
	end

	function this:GetName()
		-- print("Apphub get name called - lastSelectedContentPane:" , lastSelectedContentPane, "name:" , lastSelectedContentPane and lastSelectedContentPane:GetName())
		return lastSelectedContentPane and lastSelectedContentPane:GetName() or Strings:LocalizedString('HomeWord')
	end


	function this:Show()
		HubContainer.Visible = true
		HubContainer.Parent = lastParent

		EventHub:removeEventListener(EventHub.Notifications["NavigateToRobuxScreen"], 'AppHubListenToRobuxScreenSwitch')
		EventHub:addEventListener(EventHub.Notifications["NavigateToRobuxScreen"], 'AppHubListenToRobuxScreenSwitch', function()
			if ScreenManager:ContainsScreen(this) then
				while ScreenManager:GetTopScreen() ~= this and ScreenManager:ContainsScreen(this) do
					ScreenManager:CloseCurrent()
				end
				if ScreenManager:GetTopScreen() == this then
					if AppTabDock:GetSelectedTab() ~= StoreTab then
						AppTabDock:SetSelectedTab(StoreTab)
					end
				end
			end
		end)

		local openEquippedDebounce = false
		EventHub:removeEventListener(EventHub.Notifications["NavigateToEquippedAvatar"], 'AppHubListenToAvatarScreenSwitch')
		EventHub:addEventListener(EventHub.Notifications["NavigateToEquippedAvatar"], 'AppHubListenToAvatarScreenSwitch', function()
			if openEquippedDebounce then return end
			openEquippedDebounce = true
			if ScreenManager:ContainsScreen(this) then
				while ScreenManager:GetTopScreen() ~= this and ScreenManager:ContainsScreen(this) do
					ScreenManager:CloseCurrent()
				end
				if ScreenManager:GetTopScreen() == this then
					if AppTabDock:GetSelectedTab() ~= AvatarTab then
						AppTabDock:SetSelectedTab(AvatarTab)
						-- local avatarPane = AvatarTab:GetContentItem()
						-- if avatarPane then
						-- 	avatarPane:OpenEquippedPackage()
						-- end
					end
				end
			end
			openEquippedDebounce = false
		end)

		local currentlySelectedTab = AppTabDock:GetSelectedTab()
		AppTabDock:SetSelectedTab(currentlySelectedTab)
		if lastSelectedContentPane then
			lastSelectedContentPane:Show()
		end
	end

	function this:Hide()
		if not ScreenManager:ContainsScreen(self) then
			EventHub:removeEventListener(EventHub.Notifications["NavigateToRobuxScreen"], 'AppHubListenToRobuxScreenSwitch')
			EventHub:removeEventListener(EventHub.Notifications["NavigateToEquippedAvatar"], 'AppHubListenToAvatarScreenSwitch')
		end
		HubContainer.Visible = false
		HubContainer.Parent = nil
		if lastSelectedContentPane then
			lastSelectedContentPane:Hide()
		end
	end

	function this:Focus()
		AppTabDock:ConnectEvents()
		ContextActionService:BindCoreAction("CycleTabDock",
			function(actionName, inputState, inputObject)
				if inputState == Enum.UserInputState.End then
					if inputObject.KeyCode == Enum.KeyCode.ButtonL1 then
						local prevTab = AppTabDock:GetPreviousTab()
						if prevTab then
							AppTabDock:SetSelectedTab(prevTab)
						end
					elseif inputObject.KeyCode == Enum.KeyCode.ButtonR1 then
						local nextTab = AppTabDock:GetNextTab()
						if nextTab then
							AppTabDock:SetSelectedTab(nextTab)
						end
					end
				end
			end,
			false,
			Enum.KeyCode.ButtonL1, Enum.KeyCode.ButtonR1)

		local seenBButtonBegin = false
		ContextActionService:BindCoreAction("CloseAppHub",
			function(actionName, inputState, inputObject)
				if inputState == Enum.UserInputState.Begin then
					seenBButtonBegin = true
				elseif inputState == Enum.UserInputState.End then
					if seenBButtonBegin then
						local currentlySelectedTab = AppTabDock:GetSelectedTab()
						if currentlySelectedTab ~= HomeTab then
							AppTabDock:SetSelectedTab(HomeTab)
						end
					end
				end
			end,
			false,
			Enum.KeyCode.ButtonB)

		local function onSelectedTabChanged(selectedTab)
			if selectedTab then
				if lastSelectedContentPane then
					lastSelectedContentPane:Hide()
					lastSelectedContentPane:RemoveFocus()
				end
				local selectedContentPane = selectedTab:GetContentItem()
				if selectedContentPane then
					selectedContentPane:Show()
					if not AppTabDock:IsFocused() then
						AppTabDock:Focus()
						selectedContentPane:Focus()
					end
				end
				lastSelectedContentPane = selectedContentPane

				-- set X action
				setHintAction(selectedTab)
			end
		end
		table.insert(appHubCns, AppTabDock.SelectedTabChanged:connect(onSelectedTabChanged))

		local function onSelectedTabClicked(selectedTab)
			local selectedContentPane = selectedTab and selectedTab:GetContentItem()
			if selectedContentPane and selectedContentPane == lastSelectedContentPane then
				selectedContentPane:Focus()
			end
		end
		table.insert(appHubCns, AppTabDock.SelectedTabClicked:connect(onSelectedTabClicked))

		selectionChangedConn = Utility.DisconnectEvent(selectionChangedConn)
		selectionChangedConn = GuiService.Changed:connect(function(prop)
			if prop == "SelectedCoreObject" then
				local currentSelection = GuiService.SelectedCoreObject
				if currentSelection and lastSelectedContentPane then
					-- first condition checks if function exist
					if lastSelectedContentPane.IsFocused and not lastSelectedContentPane:IsFocused() and lastSelectedContentPane.IsAncestorOf then
						if lastSelectedContentPane:IsAncestorOf(currentSelection) then
							-- print("Doing our focus")
							lastSelectedContentPane:Focus()
						else
							-- lastSelectedContentPane:RemoveFocus()
						end
					end
				end
			end
		end)

		--set the Home tab to be the starting tab
		if AppTabDock:GetSelectedTab() == nil then
			AppTabDock:SetSelectedTab(HomeTab)
		end

		if lastSelectedContentPane then
			lastSelectedContentPane:Focus()
		end

		setHintAction(AppTabDock:GetSelectedTab())
	end

	function this:RemoveFocus()
		AppTabDock:DisconnectEvents()
		ContextActionService:UnbindCoreAction("CycleTabDock")
		ContextActionService:UnbindCoreAction("CloseAppHub")

		if lastSelectedContentPane then
			lastSelectedContentPane:RemoveFocus()
		end
		for k,v in pairs(appHubCns) do
			v:disconnect()
			v = nil
			appHubCns[k] = nil
		end

		selectionChangedConn = Utility.DisconnectEvent(selectionChangedConn)

		if AccountLinkingEnabled then
			ContextActionService:UnbindCoreAction("OpenHintAction")
		end
	end

	function this:SetParent(newParent)
		HubContainer.Parent = newParent
		lastParent = newParent
	end

	local hubID = "AppHub"
	--EventHub:addEventListener(EventHub.Notifications["OpenGameDetail"], hubID, function(data) AppTabDock:SetSelectedTab(GameTab); end);
	--EventHub:addEventListener(EventHub.Notifications["OpenGameGenre"],  hubID, function(data) AppTabDock:SetSelectedTab(GameTab); end);


	return this
end

return CreateAppHub
