local PLUGIN = PLUGIN
local ITEM = ITEM

ITEM.name = "Spray Can"
ITEM.price = 100
ITEM.shipmentSize = 10
ITEM.model = "models/sprayca2.mdl"
ITEM.width = 1
ITEM.height = 1
ITEM.category = "Art"
ITEM.description =
"A spray can filled with vibrant paint. Use it to create graffiti art on surfaces. Only accepts square designs."
ITEM.maxUses = 10 -- Maximum uses before it runs out
ITEM.maximumGraffiti = 10

-- Add name function to show loaded design
function ITEM:GetName()
	local designData = self:GetData("design")

	if (designData and designData.name) then
		return self.name .. " (" .. designData.name .. ")"
	end

	return CLIENT and L(self.name) or self.name
end

-- Add tooltip to show design status
if (CLIENT) then
	function ITEM:PopulateTooltip(tooltip)
		local designData = self:GetData("design")

		if (designData) then
			local panel = tooltip:AddRowAfter("name", "design_status")
			panel:SetBackgroundColor(PLUGIN.THEME.success)
			panel:SetText("Design: " .. (designData.name or "Unnamed"))
			panel:SizeToContents()
		else
			local panel = tooltip:AddRowAfter("name", "design_status")
			panel:SetBackgroundColor(PLUGIN.THEME.warning)
			panel:SetText("No Design Loaded")
			panel:SizeToContents()
		end

		local usesUsed = self:GetData("uses_used", 0)
		local usesLeft = self.maxUses - usesUsed

		local panel = tooltip:AddRowAfter("design_status", "uses_status")
		panel:SetBackgroundColor(PLUGIN.THEME.primary)
		panel:SetText("Uses Left: " .. usesLeft)
		panel:SizeToContents()
	end
end

-- Use Design function - loads a design from a canvas
ITEM.functions.UseDesign = {
	name = "Use Design",
	tip = "Load a square design from a canvas into this spray can.",
	icon = "icon16/page_go.png",
	OnRun = function(item)
		if (SERVER) then
			net.Start("expSprayCanDesignSelector")
			net.WriteUInt(item:GetID(), 32)
			net.Send(item.player)
		end

		-- Don't lose item
		return false
	end,
	OnCanRun = function(item)
		return item.player:GetCharacter() and item.invID == item.player:GetCharacter():GetInventory():GetID()
	end
}

ITEM.functions.SpawnInWorld = {
	name = "Spray Graffiti",
	tip = "Spray this artwork as graffiti on a wall.",
	icon = "icon16/paintbrush.png",
	OnRun = function(item)
		if (SERVER) then
			local client = item.player
			local trace = client:GetEyeTrace()

			-- Make sure we hit something and it's not too far
			if (not trace.Hit) then
				client:Notify("You need to aim at a wall!")
				return false
			end

			-- Check distance - must be within 256 units
			local hitDistance = trace.StartPos:DistToSqr(trace.HitPos)

			if (hitDistance > 256 ^ 2) then
				client:Notify("You're too far from the wall! Get closer.")
				return false
			end

			if (client:IsObjectLimited("graffiti", item.maximumGraffiti)) then
				client:Notify(
					"You can not spray graffiti as you have reached the maximum amount of graffiti in the world!")
				return false
			end

			-- Get the canvas design data to determine actual size
			local designData = item:GetData("design")
			if (not designData) then
				client:Notify("No design loaded in spray can!")
				return false
			end

			-- Validate that the design is square
			local canvasWidth = designData.width or PLUGIN.CANVAS_DEFAULT_WIDTH
			local canvasHeight = designData.height or PLUGIN.CANVAS_DEFAULT_HEIGHT

			-- Because we use render targets when drawing compositeAlpha in DrawCanvas, we must be square so we can scale it up to a power of 2 easily
			if (canvasWidth ~= canvasHeight) then
				client:Notify("Error: Spray can contains non-square design!")
				return false
			end

			-- Use actual canvas dimensions from design
			local canvasSize = canvasWidth -- Since it's square, width = height

			-- Scale factor for world graffiti (adjust this to make graffiti smaller/larger in world)
			local worldScale = 0.2 -- This makes the graffiti 20% of the canvas design size
			local worldCanvasSize = canvasSize * worldScale

			-- Position the graffiti on the surface
			local spawnPos = trace.HitPos + trace.HitNormal * 2
			local surfaceNormal = trace.HitNormal
			local playerPos = client:GetPos()

			-- Start with surface normal to make graffiti flush with any surface
			local angles = surfaceNormal:Angle()

			-- Make graffiti face outward from surface
			angles:RotateAroundAxis(angles:Up(), 180)

			-- Calculate direction to player projected onto the surface
			local toPlayer = (playerPos - spawnPos):GetNormalized()

			-- Project player direction onto the surface plane
			local surfaceRight = angles:Right()
			local surfaceUp = angles:Up()

			-- Get the component of player direction along the surface
			local rightComponent = toPlayer:Dot(surfaceRight)
			local upComponent = toPlayer:Dot(surfaceUp)

			-- Calculate rotation angle to face player (on the surface plane)
			local rotationAngle = math.atan2(upComponent, rightComponent) * (180 / math.pi)

			-- Rotate around the surface normal to face toward player
			angles:RotateAroundAxis(surfaceNormal, rotationAngle)

			-- Validate surface at all 4 corners of the square canvas
			local halfSize = worldCanvasSize * 0.5

			-- Get the four corner positions relative to the canvas center
			local right = angles:Right()
			local up = angles:Up()

			local corners = {
				spawnPos + right * halfSize + up * halfSize, -- Top right
				spawnPos - right * halfSize + up * halfSize, -- Top left
				spawnPos + right * halfSize - up * halfSize, -- Bottom right
				spawnPos - right * halfSize - up * halfSize -- Bottom left
			}

			-- Check each corner
			for i, cornerPos in ipairs(corners) do
				-- Trace from slightly behind the surface to slightly in front
				local startPos = cornerPos - surfaceNormal * 10
				local endPos = cornerPos + surfaceNormal * 20

				local cornerTrace = util.TraceLine({
					start = startPos,
					endpos = endPos,
					filter = client
				})

				-- Check if we hit something at this corner
				if (not cornerTrace.Hit) then
					client:Notify("Cannot place graffiti where it wouldn't fit the surface!")
					return false
				end
			end

			-- All validation passed, create the entity
			local entity = ents.Create("exp_world_canvas_viewer")
			entity:SetPos(spawnPos)
			entity:SetAngles(angles)
			entity:SetCanvasScale(worldScale) -- Set the world scale
			entity:Spawn()

			entity:SetCanvasFromItem(item:GetID())

			client:AddLimitedObject("graffiti", entity)
			client:RegisterEntityToRemoveOnLeave(entity)

			local usesUsed = (item:GetData("uses_used", 0) or 0) + 1

			if (usesUsed < item.maxUses) then
				client:Notify("Graffiti sprayed!")

				item:SetData("uses_used", usesUsed)
			else
				client:Notify("Graffiti sprayed! Your spray can is now empty, you toss it away.")

				-- Max uses reached, remove item
				return true
			end
		end

		-- Don't lose item
		return false
	end,
	OnCanRun = function(item)
		local designData = item:GetData("design")

		if (not designData) then
			return false
		end

		return designData and item.player:GetCharacter() and
			item.invID == item.player:GetCharacter():GetInventory():GetID()
	end
}
