--- Provides permissions for entities based on CPPI if present

local owneraccess
if SERVER then
	owneraccess = CreateConVar("sf_permissions_entity_owneraccess", "0", { FCVAR_ARCHIVE }, "Allows starfall chip's owner to access their player entity")
end

local P = {}
P.id = "entities"
P.name = "Entity Permissions"
P.settingsoptions = { "Owner Only", "Can Tool", "Can Physgun", "Anything" }
P.defaultsetting = 2
local truefunc = function() return true end
P.checks = {truefunc, truefunc, truefunc, truefunc}
SF.Permissions.registerProvider(P)

local ENT_META,PLY_META = FindMetaTable("Entity"),FindMetaTable("Player")
local Ent_GetNWEntity,Ent_GetTable,Ent_IsValid,Ent_SetNWEntity = ENT_META.GetNWEntity,ENT_META.GetTable,ENT_META.IsValid,ENT_META.SetNWEntity
local Ply_IsSuperAdmin,Ply_SteamID64 = PLY_META.IsSuperAdmin,PLY_META.SteamID64

if CPPI then
	function SF.Permissions.getOwner(ent)
		return ent:CPPIGetOwner()
	end

	if SERVER then
		P.checks = {
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target == instance.player and owneraccess:GetBool() or
					Ply_IsSuperAdmin(instance.player) or
					target:CPPIGetOwner()==instance.player then return true end

				return false, "You're not the owner of this prop"
			end,
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target == instance.player and owneraccess:GetBool() or
					target:CPPICanTool(instance.player, "starfall_ent_lib") then return true end

				return false, "You can't toolgun this entity"
			end,
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target == instance.player and owneraccess:GetBool() or
					target:CPPICanPhysgun(instance.player) then return true end

				return false, "You can't physgun this entity"
			end,
			"allow"
		}
	else
		P.checks = {
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target==instance.player or
					LocalPlayer()==instance.player or
					Ply_IsSuperAdmin(instance.player) or
					target:CPPIGetOwner()==instance.player then return true end

				return false, "You're not the owner of this prop"
			end,
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target==instance.player or
					LocalPlayer()==instance.player or
					Ply_IsSuperAdmin(instance.player) or
					target:CPPICanTool(instance.player, "starfall_ent_lib") then return true end

				return false, "You can't toolgun this entity"
			end,
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target==instance.player or
					LocalPlayer()==instance.player or
					Ply_IsSuperAdmin(instance.player) or
					target:CPPICanPhysgun(instance.player) then return true end

				return false, "You can't physgun this entity"
			end,
			"allow"
		}
		if not ENT_META.CPPICanTool then P.checks[2] = P.checks[1] end
		if not ENT_META.CPPICanPhysgun then P.checks[3] = P.checks[1] end
	end
else
	if SERVER then
		P.checks = {
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target == instance.player and owneraccess:GetBool() or
					Ply_IsSuperAdmin(instance.player) or
					P.props[target]==instance.player then return true end

				return false, "You're not the owner of this prop"
			end,
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target == instance.player and owneraccess:GetBool() or
					hook.Run("CanTool", instance.player, SF.dumbTrace(target), "starfall_ent_lib") ~= false then return true end

				return false, "Target doesn't have toolgun access"
			end,
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target == instance.player and owneraccess:GetBool() then return true end

				if hook.Run("PhysgunPickup", instance.player, target) ~= false then
					-- Some mods expect a release when there's a pickup involved.
					hook.Run("PhysgunDrop", instance.player, target)
					return true
				end

				return false, "Target doesn't have physgun access"
			end,
			"allow"
		}

		P.props = SF.EntityTable("PropProtection")
		function SF.Permissions.getOwner(ent)
			return P.props[ent] or NULL
		end

		local function PropOwn(ply,ent)
			P.props[ent] = ply
			Ent_SetNWEntity(ent, "SFPP", ply)
		end

		if(cleanup) then
			local backupcleanupAdd = cleanup.Add
			function cleanup.Add(ply, enttype, ent)
				if Ent_IsValid(ent) and ply:IsPlayer() then
					PropOwn(ply, ent)
				end
				backupcleanupAdd(ply, enttype, ent)
			end
		end
		local metaply = FindMetaTable("Player")
		if(metaply.AddCount) then
			local backupAddCount = metaply.AddCount
			function metaply:AddCount(enttype, ent)
				PropOwn(self, ent)
				backupAddCount(self, enttype, ent)
			end
		end
		hook.Add("PlayerSpawnedSENT", "SFPP.PlayerSpawnedSENT", PropOwn)
		hook.Add("PlayerSpawnedVehicle", "SFPP.PlayerSpawnedVehicle", PropOwn)
		hook.Add("PlayerSpawnedSWEP", "SFPP.PlayerSpawnedSWEP", PropOwn)
		hook.Add("PlayerInitialSpawn","SFPP.PlayerInitialSpawn", function(ply)
			local steamid = Ply_SteamID64(ply)
			for k, v in pairs(P.props) do
				if v==steamid then
					PropOwn(ply,k)
				end
			end
		end)
		hook.Add("PlayerDisconnected","SFPP.PlayerDisconnected", function(ply)
			local steamid = Ply_SteamID64(ply)
			for k, v in pairs(P.props) do
				if v==ply then
					P.props[k] = steamid
				end
			end
		end)

	else
		P.checks = {
			function(instance, target)
				if not Ent_IsValid(target) then return false, "Entity is invalid" end
				if target==instance.player or
					LocalPlayer()==instance.player or
					Ply_IsSuperAdmin(instance.player) or
					Ent_GetNWEntity(target, "SFPP")==instance.player or
					target.SFHoloOwner==instance.player then return true end

				return false, "You're not the owner of this prop"
			end,
			nil,
			nil,
			"allow"
		}
		P.checks[2] = P.checks[1]
		P.checks[3] = P.checks[1]

		function SF.Permissions.getOwner(ent)
			return Ent_GetTable(ent).SFHoloOwner or Ent_GetNWEntity(ent, "SFPP")
		end
	end
end
