--[[
	Provides various properties for cchecking if the user is interfacing with a
	keyboard, gamepad, or touch-enabled device.
]]


local GuiService = game:GetService("GuiService")
local UserInputService = game:GetService("UserInputService")

local Cryo = require(script.Parent.Parent.Packages.Cryo)
local Roact = require(script.Parent.Parent.Packages.Roact)
local ConfigurationContext = require(script.Parent.Parent.Libraries.Configuration).ConfigurationContext
local withConfiguration = ConfigurationContext.withConfiguration
local ExternalEventConnection = require(script.Parent.Parent.Components.ExternalEventConnection)

local Context = Roact.createContext({})

local InputContextProvider = Roact.Component:extend("InputContextProvider")

export type State = {
	isAppFocusedByGamepad: boolean,
	isUsingKeyboard: boolean,
	isUsingGamepad: boolean,
	isUsingTouch: boolean,
}

function InputContextProvider:init()
	self.selectedObjectTracker = Roact.createRef()

	local state: State = {
		isAppFocusedByGamepad = false,
		isUsingGamepad = false,
		isUsingKeyboard = false,
		isUsingTouch = false,
	}
	self.state = state

	self.onSelectedObjectChanged = function()
		local selectedObject = GuiService.SelectedObject
		local tracker = self.selectedObjectTracker:getValue()

		self:setState(function()
			if selectedObject and tracker then
				if selectedObject:IsDescendantOf(tracker.Parent) then
					return {
						isAppFocusedByGamepad = true,
					}
				end
			end

			return {
				isAppFocusedByGamepad = false,
			}
		end)
	end

	self.onInputTypeChanged = function(inputType: Enum.UserInputType)
		self:setState(function()
			if inputType.Name:match("^Gamepad%d") then
				return {
					isUsingGamepad = true,
					isUsingKeyboard = false,
					isUsingTouch = false,
				}
			elseif inputType == Enum.UserInputType.Touch then
				return {
					isUsingGamepad = false,
					isUsingKeyboard = false,
					isUsingTouch = true,
				}
			else
				return {
					isUsingGamepad = false,
					isUsingKeyboard = true,
					isUsingTouch = false,
				}
			end
		end)
	end
end

function InputContextProvider:render()
	return Roact.createFragment({
		SelectedObjectTracker = Roact.createElement("Folder", {
			[Roact.Ref] = self.selectedObjectTracker,
		}),

		SelectedObjectChanged = Roact.createElement(ExternalEventConnection, {
			event = GuiService:GetPropertyChangedSignal("SelectedObject"),
			callback = self.onSelectedObjectChanged,
		}),

		LastInputTypeChanged = Roact.createElement(ExternalEventConnection, {
			event = UserInputService.LastInputTypeChanged,
			callback = self.onInputTypeChanged,
		}),

		Provider = Roact.createElement(Context.Provider, {
			value = self.state,
		}, self.props[Roact.Children]),
	})
end

function InputContextProvider:didMount()
	self.onInputTypeChanged(UserInputService:GetLastInputType())
end

function InputContextProvider:didUpdate(prevProps)
	-- This is for stories so that if the various states are changed by a
	-- storybook control the provider rerenders.
	if self.props ~= prevProps then
		self:setState(self.props)
	end
end
