local vm = require 'vm'

VM = {}

local hookParamTypes = {
	IntermissionThinker = { "boolean" },
	LinedefExecute = { "line_t", "mobj_t", "sector_t" },
	MapChange = { "integer" },
	MapLoad = { "integer" },
	ThinkFrame = {},
	PreThinkFrame = {},
	PostThinkFrame = {},
	GameQuit = { "boolean" },
	BotAI = { "mobj_t", "mobj_t" },
	BotTiccmd = { "player_t", "ticcmd_t" },
	BotRespawn = { "mobj_t", "mobj_t" },
	HurtMsg = { "player_t", "mobj_t", "mobj_t", "integer" },
	NetVars = { "fun(value: any): any" },
	PlayerJoin = { "integer" },
	PlayerQuit = { "player_t", "integer" },
	PlayerMsg = { "player_t", "integer", "player_t", "string" },
	TeamSwitch = { "player_t", "integer", "boolean", "boolean", "boolean" },
	ViewpointSwitch = { "player_t", "player_t", "boolean" },
	SeenPlayer = { "player_t", "player_t" },
	PlayerThink = { "player_t" },
	PlayerCanDamage = { "player_t", "mobj_t" },
	PlayerSpawn = { "player_t" },
	PlayerHeight = { "player_t" },
	PlayerCanEnterSpinGaps = { "player_t" },
	ShieldSpawn = { "player_t" },
	AbilitySpecial = { "player_t" },
	JumpSpecial = { "player_t" },
	JumpSpinSpecial = { "player_t" },
	SpinSpecial = { "player_t" },
	ShieldSpecial = { "player_t" },
	MapThingSpawn = { "mobj_t", "mapthing_t" },
	MobjSpawn = { "mobj_t" },
	MobjRemoved = { "mobj_t" },
	MobjThinker = { "mobj_t" },
	MobjFuse = { "mobj_t" },
	BossThinker = { "mobj_t" },
	ShouldDamage = { "mobj_t", "mobj_t", "mobj_t", "integer", "integer" },
	MobjDamage = { "mobj_t", "mobj_t", "mobj_t", "integer", "integer" },
	MobjDeath = { "mobj_t", "mobj_t", "mobj_t", "integer" },
	BossDeath = { "mobj_t" },
	FollowMobj = { "player_t", "mobj_t" },
	MobjCollide = { "mobj_t", "mobj_t" },
	MobjLineCollide = { "mobj_t", "line_t" },
	MobjMoveBlocked = { "mobj_t", "mobj_t", "line_t" },
	MobjMoveCollide = { "mobj_t", "mobj_t" },
	TouchSpecial = { "mobj_t", "mobj_t" },
	MusicChange = { "string", "string", "integer", "boolean", "integer", "integer", "integer" },
	ShouldJingleContinue = { "player_t", "string" },
	KeyDown = { "keyevent_t" },
	KeyUp = { "keyevent_t" },
	PlayerCmd = { "player_t", "ticcmd_t" },
	HUD = { "videolib", "camera_t", "player_t" },
	AddonLoaded = {},
}

function VM.OnCompileFunctionParam(next, hookCallback, hookParam)
	if next(hookCallback, hookParam) then return true end

	local addHookArgs = hookCallback.parent
	if addHookArgs.type ~= "callargs" then return end

	local addHookCall = addHookArgs.parent
	local addHookName = addHookCall.node[1]
	if addHookName ~= "addHook" then return end

	if addHookArgs[1].type ~= "string" then return end

	local hookType = addHookArgs[1][1]
	if not hookParamTypes[hookType] then return end

	local hookParams = hookParam.parent
	local hookParamName = hookParam[1]

	local hookParamIndex = nil
	for i = 1, #hookParams do
		local otherParamName = hookParams[i][1]
		if otherParamName == hookParamName then
			hookParamIndex = i
			break
		end
	end

	if not hookParamIndex then return end

	local hookParamType = hookParamTypes[hookType][hookParamIndex]
	if not hookParamType then return end

	vm.setNode(hookParam, vm.createNode(vm.declareGlobal("type", hookParamType), hookParam))

	return true
end
