--[[---------------- FUNCTIONS -----------------]]
--

local function isAValidNearbyInteractable(targetObj)
	if not targetObj then return end
	if not targetObj:IsA("BasePart") then return end
	local interactable = targetObj:GetAttribute("Interactable")
	if not interactable then return end
	local module = interactables:FindFirstChild(targetObj.Name)
	if not module then return end
	local dist = (targetObj.Position - hrp.Position).magnitude	
	if dist > MAX_INTERACTION_DIST + math.max(targetObj.Size.X, targetObj.Size.Y, targetObj.Size.Z) / 2 then return end

	return module
end

local function samePlayer(rPly)
	if rPly ~= ply then rPly:Kick(_G.EXPLOITER_KICK_MESSAGE) return false end
	return true
end

local function interact()
	if downedVal.Value then return end 
	
	if holdingInputVal.Value and mouseHoverObjectVal.Value then		
		local interactableModule = isAValidNearbyInteractable(mouseHoverObjectVal.Value)	
		local success = false
		local serverChecksFunc = nil
		if interactableModule then
			local mod = require(interactableModule)	
			if mod and mod.serverChecks and typeof(mod.serverChecks) == "function" then
				success = mod.serverChecks(mouseHoverObjectVal.Value)
				serverChecksFunc = mod.serverChecks
			else
				success = true
			end
		end
		
		if success then
				
			local interactionSuccessful = CIH.determineInteraction(ply, mouseHoverObjectVal.Value)	
			local shouldKeepHolding = true
			local interacted = nil

			while interactionSuccessful and shouldKeepHolding do
				interacted, shouldKeepHolding = CIH.interact(ply, mouseHoverObjectVal.Value)
				if shouldKeepHolding then
					interactionSuccessful = CIH.determineInteraction(ply, mouseHoverObjectVal.Value)	
				end
			end
			
			if serverChecksFunc and not serverChecksFunc(mouseHoverObjectVal.Value) then
				deleteInteractionUIEvent:FireClient(ply, mouseHoverObjectVal.Value)
			end
		end
	end
end

local function onUpdateInputHoldEvent(rPly, inputState)
	if not samePlayer(rPly) then return end
	if downedVal.Value then return end
	
	if inputState ~= nil and typeof(inputState) == "boolean" then
		holdingInputVal.Value = inputState
	else
		holdingInputVal.Value = false
	end	
	
	interact()
end

local globalObjChangedConn = nil

local function onUpdateHoverObjectEvent(rPly, newObj)
	if not samePlayer(rPly) then return end
	if downedVal.Value then return end
	
	if globalObjChangedConn then globalObjChangedConn:Disconnect() end
	mouseHoverObjectVal.Value = nil
	
	local interactableModule = isAValidNearbyInteractable(newObj)	
	
	if interactableModule then
		mouseHoverObjectVal.Value = newObj
		
		if globalObjChangedConn then globalObjChangedConn:Disconnect() end
		globalObjChangedConn = newObj.Changed:Connect(function()
			if globalObjChangedConn then globalObjChangedConn:Disconnect() end
			mouseHoverObjectVal.Value = nil
			onUpdateHoverObjectEvent(rPly, newObj)
		end)
	end
	
	interact()
end

local function onDown(val)
	if val then
		onUpdateHoverObjectEvent(ply, nil)
		mouseHoverObjectVal.Value = nil
		holdingInputVal.Value = false
	end
end
