local CoreGui = game:GetService("CoreGui")
local CorePackages = game:GetService("CorePackages")
local ContextActionService = game:GetService("ContextActionService")
local LocalizationService = game:GetService("LocalizationService")
local UserInputService = game:GetService("UserInputService")

local RobloxGui = CoreGui:WaitForChild("RobloxGui")

local Utility = require(RobloxGui.Modules.Settings.Utility)
local Constants =
	require(RobloxGui.Modules:WaitForChild("InGameMenu"):WaitForChild("Resources"):WaitForChild("Constants"))
local React = require(CorePackages.Packages.React)
local Foundation = require(CorePackages.Packages.Foundation)
local Signals = require(CorePackages.Packages.Signals)
local SignalsReact = require(CorePackages.Packages.SignalsReact)
local Responsive = require(CorePackages.Workspace.Packages.Responsive)
local Localization = require(CorePackages.Workspace.Packages.InExperienceLocales).Localization
local LocalizationProvider = require(CorePackages.Workspace.Packages.Localization).LocalizationProvider
local useLocalization = require(CorePackages.Workspace.Packages.Localization).Hooks.useLocalization

local MenuButton = require(script.Parent.MenuButton)

local useSignalState = SignalsReact.useSignalState
local useLastInput = Responsive.useLastInput

local FoundationProvider = Foundation.FoundationProvider
local View = Foundation.View

local SharedFlags = require(CorePackages.Workspace.Packages.SharedFlags)
local FFlagFixMenuButtonsDisablePolyfill = SharedFlags.FFlagFixMenuButtonsDisablePolyfill
local FIntRelocateMobileMenuButtonsVariant = require(RobloxGui.Modules.Settings.Flags.FIntRelocateMobileMenuButtonsVariant)

type Props = {
	onLeaveGame: (source: string) -> (),
	onRespawn: (source: string) -> (),
	onResume: (source: string) -> (),
	setAddMenuKeyBindings: (addMenuKeyBindings: () -> ()) -> (),
	setRemoveMenuKeyBindings: (removeMenuKeyBindings: () -> ()) -> (),
	getVisibility: () -> boolean,
	getCanRespawn: Signals.getter<boolean>,
}

local MenuButtons

if FFlagFixMenuButtonsDisablePolyfill then
	MenuButtons = require(script.Parent.MenuButtons)
else
	type ButtonsData = { MenuButton.ButtonData }

	local function createMenuButtons(buttonsData: ButtonsData, lastInput: string, isSmall: boolean)
		local buttonElems: { [string]: React.ReactNode } = {}
		for i = 1, #buttonsData do
			buttonElems["MenuButtonContainer" .. i] = React.createElement(View, {
				tag = "fill row align-y-center",
				LayoutOrder = i,
			}, {
				MenuButton = React.createElement(MenuButton, {
					text = buttonsData[i].text,
					lastInput = lastInput,
					keyboardHint = buttonsData[i].hint.keyboard,
					gamepadButtonImageHint = buttonsData[i].hint.gamepadButtonImage,
					onActivated = buttonsData[i].onActivated,
					layoutOrder = 1,
					isEmphasized = buttonsData[i].isEmphasized,
					isSmall = isSmall,
					isDisabled = buttonsData[i].getIsDisabled(),
				})
			})
		end
		return buttonElems
	end

	MenuButtons = function(props: Props)
		local buttonsData: ButtonsData, setButtonsData = React.useState({} :: ButtonsData)
		local isSmallScreen, _setIsSmallScreen = React.useState(Utility:IsSmallTouchScreen())

		-- Used to force re-render when the respawn button changes isDisabled state
		local _canRespawn = useSignalState(props.getCanRespawn)

		local leaveHintImage, setLeaveHintImage = React.useBinding("")
		local resetHintImage, setResetHintImage = React.useBinding("")
		local resumeHintImage, setResumeHintImage = React.useBinding("")

		local localizedText = useLocalization({
			LeaveGame = Constants.LeaveGameLocalizedKey,
			Respawn = Constants.RespawnLocalizedKey,
			Resume = Constants.ResumeLocalizedKey,
		}) 
		local lastInput = useLastInput()

		local initialButtonsData = React.useMemo(function()  
			return {
				{
					name = "LeaveGameButton",
					text = localizedText.LeaveGame,
					hint = {
						keyboard = "L",
						gamepadButton = Enum.KeyCode.ButtonX,
						gamepadButtonImage = leaveHintImage,
						setGamepadButtonImage = setLeaveHintImage,
					},
					isEmphasized = false,
					getIsDisabled = function()
						return false
					end,
					onActivated = function()
						props.onLeaveGame(Constants.AnalyticsMenuButtonSource)
					end,
					hotkeys = { Enum.KeyCode.L, Enum.KeyCode.ButtonX },
					hotkeyFunc = function()
						props.onLeaveGame(Constants.AnalyticsMenuHotkeySource)
					end,
				},
				{
					name = "ResetButton",
					text = localizedText.Respawn,
					hint = {
						keyboard = "R",
						gamepadButton = Enum.KeyCode.ButtonY,
						gamepadButtonImage = resetHintImage,
						setGamepadButtonImage = setResetHintImage,
					},
					isEmphasized = false,
					getIsDisabled = function()
						return not props.getCanRespawn(false)
					end,
					onActivated = function()
						props.onRespawn(Constants.AnalyticsMenuButtonSource)
					end,
					hotkeys = { Enum.KeyCode.R, Enum.KeyCode.ButtonY },
					hotkeyFunc = function()
						props.onRespawn(Constants.AnalyticsMenuHotkeySource)
					end,
				},
				{
					name = "ResumeButton",
					text = localizedText.Resume,
					hint = {
						keyboard = "ESC",
						gamepadButton = Enum.KeyCode.ButtonStart,
						gamepadButtonImage = resumeHintImage,
						setGamepadButtonImage = setResumeHintImage,
					},
					isEmphasized = not (FIntRelocateMobileMenuButtonsVariant == 1),
					getIsDisabled = function()
						return false
					end,
					onActivated = function()
						props.onResume(Constants.AnalyticsMenuButtonSource)
					end,
					hotkeyFunc = function()
						props.onResume(Constants.AnalyticsMenuHotkeySource)
					end,
					hotkeys = { Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonStart },
				},
			}
		end, { localizedText.LeaveGame, localizedText.Respawn, localizedText.Resume })

		local addKeyBindings = React.useCallback(function(buttonsData: ButtonsData)
			if not props.getVisibility() then
				return
			end

			for i = 1, #buttonsData do
				if buttonsData[i].hotkeyFunc ~= nil then
					ContextActionService:BindCoreAction(
						buttonsData[i].name,
						buttonsData[i].hotkeyFunc,
						false,
						unpack(buttonsData[i].hotkeys)
					)
				end
			end
		end, {})

		local removeKeyBindings = React.useCallback(function(buttonsData: ButtonsData)
			for i = 1, #buttonsData do
				ContextActionService:UnbindCoreAction(buttonsData[i].name)
			end
		end, {})

		local initializeHotkeyFunc = React.useCallback(function(buttonsData: ButtonsData)
			local addRemoveBindingsToFunc = function(onActivatedFunc: () -> (), getIsDisabled: () -> boolean)
				return function()
					if not getIsDisabled() then
						removeKeyBindings(buttonsData)
						onActivatedFunc()
					end
				end
			end

			local createHotkeyFunc = function(onActivatedFunc: () -> (), getIsDisabled: () -> boolean)
				return function(contextName, inputState, inputObject)
					if inputState == Enum.UserInputState.Begin then
						addRemoveBindingsToFunc(onActivatedFunc, getIsDisabled)()
					end
				end
			end

			for i = 1, #buttonsData do
				buttonsData[i].onActivated = addRemoveBindingsToFunc(buttonsData[i].onActivated, buttonsData[i].getIsDisabled)
				buttonsData[i].hotkeyFunc = createHotkeyFunc(buttonsData[i].hotkeyFunc, buttonsData[i].getIsDisabled)
				buttonsData[i].hint.setGamepadButtonImage(
					UserInputService:GetImageForKeyCode(buttonsData[i].hint.gamepadButton)
				)
			end

			props.setAddMenuKeyBindings(function()
				addKeyBindings(buttonsData)
			end)
			props.setRemoveMenuKeyBindings(function()
				removeKeyBindings(buttonsData)
			end)

			return buttonsData
		end, {})

		React.useEffect(function()
			local buttonsData = initializeHotkeyFunc(initialButtonsData)
			setButtonsData(buttonsData)
		end, { initialButtonsData })

		React.useEffect(function()
			UserInputService.GamepadConnected:Connect(function()
				for i = 1, #buttonsData do
					buttonsData[i].hint.setGamepadButtonImage(
						UserInputService:GetImageForKeyCode(buttonsData[i].hint.gamepadButton)
					)
				end
			end)
		end, { buttonsData })

		return React.createElement(View, {
			tag = {
				["size-full row align-y-center"] = true,
				["gap-small"] = not isSmallScreen,
				["gap-xsmall"] = isSmallScreen,
			},
		}, createMenuButtons(buttonsData, lastInput, isSmallScreen))
	end
end

local function Container(props: Props)
	local localization = Localization.new(LocalizationService.RobloxLocaleId)

	return React.createElement(LocalizationProvider, {
		localization = localization,
	}, {
		FoundationProvider = React.createElement(FoundationProvider, {
			theme = Foundation.Enums.Theme.Dark,
		}, {
			MenuButtons = React.createElement(MenuButtons, props),
		}),
	})
end

return Container
