-- This module holds any type of remote execution functions (IE, 'dangerous')
local CATEGORY_NAME = "Rcon"

function ulx.rcon( calling_ply, command )
	game.ConsoleCommand( command .. "\n" )

	ulx.fancyLogAdmin( calling_ply, true, "#A ran rcon command: #s", command )
end
local rcon = ulx.command( CATEGORY_NAME, "ulx rcon", ulx.rcon, "!rcon", true, false, true )
rcon:addParam{type=ULib.cmds.StringArg, hint="command", ULib.cmds.takeRestOfLine}
rcon:defaultAccess( ULib.ACCESS_SUPERADMIN )
rcon:help( "Execute command on server console." )

function ulx.luaRun( calling_ply, command )
	RunString( command )

	ulx.fancyLogAdmin( calling_ply, true, "#A ran lua: #s", command )
end
local luarun = ulx.command( CATEGORY_NAME, "ulx luarun", ulx.luaRun, nil, false, false, true )
luarun:addParam{type=ULib.cmds.StringArg, hint="command", ULib.cmds.takeRestOfLine}
luarun:defaultAccess( ULib.ACCESS_SUPERADMIN )
luarun:help( "Executes lua in server console." )

function ulx.exec( calling_ply, target_plys, command )
	for _, v in ipairs( target_plys ) do
		v:ConCommand( command )
	end

	ulx.fancyLogAdmin( calling_ply, true, "#A ran #s on #T", command, target_plys )
end
local exec = ulx.command( CATEGORY_NAME, "ulx exec", ulx.exec, "!exec", false, false, true )
exec:addParam{type=ULib.cmds.PlayersArg}
exec:addParam{type=ULib.cmds.StringArg, hint="command", ULib.cmds.takeRestOfLine}
exec:defaultAccess( ULib.ACCESS_SUPERADMIN )
exec:help( "Run a command on console of target(s)." )

local function applyNPC( newEnt, classname )
	local NPCList = list.Get( "NPC" )
	local NPCData = NPCList[ classname ]

	if not NPCData then return end

	if NPCData.Model then
		newEnt:SetModel( NPCData.Model )
	end

	if NPCData.Material then
		newEnt:SetMaterial( NPCData.Material )
	end

	if NPCData.KeyValues then
		for k, v in pairs( NPCData.KeyValues ) do
			newEnt:SetKeyValue( k, v )
		end
	end

	if NPCData.Skin then
		newEnt:SetSkin( NPCData.Skin )
	end

	if NPCData.Weapons then
		local weapon = NPCData.Weapons[ math.random( #NPCData.Weapons ) ]

		if weapon then
			newEnt:SetKeyValue( "additionalequipment", weapon )
			newEnt.Equipment = weapon
		end
	end

	if NPCData.Health then
		newEnt:SetHealth( NPCData.Health )
	end

	if NPCData.BodyGroups then
		for k, v in pairs( NPCData.BodyGroups ) do
			newEnt:SetBodygroup( k, v )
		end
	end
end

local function applyNPCOffset( newEnt, classname, tr )
	local NPCList = list.Get( "NPC" )
	local NPCData = NPCList[ classname ]

	if not NPCData then return false end

	local offset = NPCData.Offset or 32
	newEnt:SetPos( tr.HitPos + tr.HitNormal * offset )

	return true
end

function ulx.ent( calling_ply, classname, model, health )
	if not calling_ply:IsValid() then
		Msg( "Can't create entities from dedicated server console.\n" )
		return
	end

	classname = classname:lower()

	local newEnt = ents.Create( classname )

	-- Make sure it's a valid entity
	if not IsValid(newEnt) then
		ULib.tsayError( calling_ply, "Unknown entity type (" .. classname .. "), aborting." )
		return
	end

	applyNPC( newEnt, classname )

	if model and model ~= "" and model ~= "model" and model ~= "model (leave empty for default)" then
		newEnt:SetModel( model )
	end

	local tr = calling_ply:GetEyeTrace()
	if newEnt.SpawnFunction then
		newEnt:SpawnFunction( calling_ply, tr, classname )
	else
		local pos = tr.HitPos
		local ang = calling_ply:GetAngles()
		ang.pitch = 0
		ang.roll = 0
		ang.yaw = ang.yaw + 180

		newEnt:SetPos( pos )
		newEnt:SetAngles( ang )

		pos = tr.HitPos - ( tr.HitNormal * 512 )
		pos = newEnt:NearestPoint( pos )
		pos = newEnt:GetPos() - pos
		pos = tr.HitPos + pos

		if applyNPCOffset( newEnt, classname, tr ) == false then
			newEnt:SetPos( pos )
		end

		newEnt:Spawn()
		newEnt:Activate()
	end

	if model and model ~= "" and model ~= "model" and model ~= "model (leave empty for default)" then
		newEnt:SetModel( model )
	end


	health = health and tonumber( health )
	if health ~= 0 then
		newEnt:SetHealth( health )
	end

	if FixInvalidPhysicsObject then
		FixInvalidPhysicsObject( newEnt )
	end
	if DoPropSpawnedEffect then
		DoPropSpawnedEffect( newEnt )
	end

	undo.Create( "ulx_ent" )
		undo.AddEntity( newEnt )
		undo.SetPlayer( calling_ply )
	undo.Finish()

	if newEnt.CPPIGetOwner then
		newEnt:CPPISetOwner()
	end

	if model and model ~= "" and model ~= "model" and model ~= "model (leave empty for default)" then
		ulx.fancyLogAdmin( calling_ply, true, "#A created entity #s with model #s", classname, model )
	else
		ulx.fancyLogAdmin( calling_ply, true, "#A created entity #s", classname )
	end
end
local ent = ulx.command( CATEGORY_NAME, "ulx ent", ulx.ent, "!ent", false, false, true )
ent:addParam{type=ULib.cmds.StringArg, hint="classname"}
ent:addParam{type=ULib.cmds.StringArg, hint="model (leave empty for default)", ULib.cmds.optional}
ent:addParam{type=ULib.cmds.NumArg, hint="health (0 = default)", min = 0, max = 100000, ULib.cmds.optional, ULib.cmds.round}
ent:defaultAccess( ULib.ACCESS_SUPERADMIN )
ent:help( "Spawn an entity.\nA few will crash the game." )
