-- @author DoomTero 2026
-- @copyright 2026 DoomTero - ZomboRut original work. ref:51120cc6
-- @license Proprietary. Not licensed for reuse, redistribution or derivative works without written permission from DoomTero. Ask - permission is obtainable. See ZomboRut/LICENSE.txt

local ZomboRutScene = require "ZomboRut/ZomboRutScene"
local ZR_MenuUtil   = require "ZomboRut/ContextMenu/ZR_MenuUtil"

local banditsAvailable        = ZR_MenuUtil.banditsAvailable
local findOnTilesAndNeighbors = ZR_MenuUtil.findOnTilesAndNeighbors
local setIcon                 = ZR_MenuUtil.icon
local sceneLabel              = ZR_MenuUtil.sceneLabel

local function isSceneCorpse(obj)
	if not instanceof(obj, "IsoDeadBody") then return false end
	if obj.isAnimal and obj:isAnimal() then return false end
	return true
end

local function findDeadBodyAt(worldobjects)
	local picked = ISWorldObjectContextMenu
		and ISWorldObjectContextMenu.fetchVars
		and ISWorldObjectContextMenu.fetchVars.body
	if picked and isSceneCorpse(picked) then
		return picked, true
	end
	return findOnTilesAndNeighbors(worldobjects, "static", isSceneCorpse), false
end

local function isSubduedTarget(obj)
	local md = obj.getModData and obj:getModData() or nil
	return md and md.zrSubdued == true
end

local function isSubduedZombie(obj)
	return instanceof(obj, "IsoZombie")
		and not obj:isDead()
		and isSubduedTarget(obj)
end

local function isDummyBandit(obj)
	if not banditsAvailable() then return false end
	return instanceof(obj, "IsoZombie")
		and obj:getVariableBoolean("Bandit")
		and obj:getModData().zrDummyBandit
		and not obj:isDead()
		and not isSubduedTarget(obj)
end

local function isDummyZombie(obj)
	return instanceof(obj, "IsoZombie")
		and obj:getModData().zrDummyZombie
		and not obj:getVariableBoolean("Bandit")
		and not obj:isDead()
		and not isSubduedTarget(obj)
end

local function findLiveSceneTarget(worldobjects)
	local bandit = findOnTilesAndNeighbors(worldobjects, "moving", isDummyBandit)
	if bandit then return bandit, "bandit" end
	local zombie = findOnTilesAndNeighbors(worldobjects, "moving", isDummyZombie)
	if zombie then return zombie, "zombie" end
	return nil, nil
end

return function(ContextMenu, playerObj, context, worldobjects, getRoot)
	if not playerObj then return end

	local sceneIds = ZomboRutScene.listLogical()
	if #sceneIds == 0 then return end

	if playerObj:isDraggingCorpse() then
		local active = ZomboRutScene._active and ZomboRutScene._active[playerObj]
		local captive = active and active.liveOriginal
		local isCaptiveDrag = captive and captive.getModData
			and captive:getModData().zrSubdued == true
		setIcon(getRoot():addOption(
			getText(isCaptiveDrag and "ContextMenu_ZR_DropVictim" or "ContextMenu_ZR_SceneEnd"),
			worldobjects, function()
				ZomboRutScene.endScene(playerObj)
			end), isCaptiveDrag and "Drag" or "Scene_End")
		return
	end

	local liveTarget, liveKind = findLiveSceneTarget(worldobjects)
	local deadBody, deadBodyPicked
	if not liveTarget then
		deadBody, deadBodyPicked = findDeadBodyAt(worldobjects)
	end

	if deadBody and not deadBodyPicked
		and findOnTilesAndNeighbors(worldobjects, "moving", isSubduedZombie)
	then
		deadBody = nil
	end

	if not liveTarget and not deadBody then return end

	local zrMenu = getRoot()
	local rootOption = zrMenu:addOption(getText("ContextMenu_ZR_SceneMenu"), worldobjects, nil)
	setIcon(rootOption, "Scene")
	local rootSub = ISContextMenu:getNew(context)
	zrMenu:addSubMenu(rootOption, rootSub)

	local highlightTarget = liveTarget or deadBody
	if highlightTarget then
		ISWorldObjectContextMenu.initWorldItemHighlightOption(rootOption, highlightTarget)
	end

	local debugOn = isDebugEnabled and isDebugEnabled()
	for _, id in ipairs(sceneIds) do
		repeat
			local cfg = ZomboRutScene.getLogical(id)
			local label = (cfg and cfg.label) or id
			if cfg and cfg.friendlyOnly and (not liveTarget or liveKind ~= "bandit") then
				break
			end
			if cfg and cfg.corpseOnly and not deadBody then
				break
			end
			if deadBody and not debugOn and not (cfg and cfg.corpseOnly) then
				break
			end
			if deadBody and not debugOn
				and not ZomboRutScene._resolveGender(playerObj, deadBody, id)
			then
				break
			end
			if cfg and cfg.debugOnly and not debugOn then
				break
			end
			local opt
			if liveTarget then
				local launcher = (liveKind == "bandit")
					and ZomboRutScene.playSceneFromLive
					or ZomboRutScene.playSceneFromAttacker
				opt = rootSub:addOption(sceneLabel(label), worldobjects, function()
					launcher(playerObj, liveTarget, id)
				end)
			else
				opt = rootSub:addOption(sceneLabel(label), worldobjects, function()
					ZomboRutScene.playSceneFromCorpse(playerObj, deadBody, id)
				end)
			end
			setIcon(opt, (cfg and cfg.icon) or "Scene_Leaf")
			if highlightTarget then
				ISWorldObjectContextMenu.initWorldItemHighlightOption(opt, highlightTarget)
			end
		until true
	end

	if debugOn then
		local literalIds = ZomboRutScene.list()
		if #literalIds > 0 then
			local debugRoot = rootSub:addOption("[DEBUG] Any Scene", worldobjects, nil)
			setIcon(debugRoot, "Debug")
			local debugSub = ISContextMenu:getNew(context)
			rootSub:addSubMenu(debugRoot, debugSub)
			for _, id in ipairs(literalIds) do
				local opt = debugSub:addOption(id, worldobjects, function()
					if liveTarget then
						local launcher = (liveKind == "bandit")
							and ZomboRutScene.playSceneFromLive
							or ZomboRutScene.playSceneFromAttacker
						launcher(playerObj, liveTarget, id)
					else
						ZomboRutScene.playSceneFromCorpse(playerObj, deadBody, id)
					end
				end)
				setIcon(opt, "Scene_Leaf")
				if highlightTarget then
					ISWorldObjectContextMenu.initWorldItemHighlightOption(opt, highlightTarget)
				end
			end
		end
	end
end
