-- @author SolarEdge 2026

print("[ZR Debug] ZR_DebugSpawnDummy.lua loaded")

local ZomboRutScene = require "ZomboRut/ZomboRutScene"

local DUMMY_TAG = "ZomboRutDummy"

local function banditsAvailable()
	return Bandit ~= nil and BanditCustom ~= nil and BanditBrain ~= nil
end

local function findDeadBodyAt(worldobjects)
	for i = 1, #worldobjects do
		local obj = worldobjects[i]
		if instanceof(obj, "IsoDeadBody") then return obj end
	end
	for i = 1, #worldobjects do
		local obj = worldobjects[i]
		local sq = obj and obj.getSquare and obj:getSquare()
		if sq then
			local statics = sq:getStaticMovingObjects()
			if statics then
				for j = 0, statics:size() - 1 do
					local s = statics:get(j)
					if instanceof(s, "IsoDeadBody") then return s end
				end
			end
		end
	end
	return nil
end

local function pickSquareFromContext(worldobjects)
	for _, v in ipairs(worldobjects) do
		if v and v.getSquare then
			local sq = v:getSquare()
			if sq then return sq end
		end
	end
	return nil
end

local function silenceZombie(zombie)
	local desc = zombie:getDescriptor()
	if desc and desc.setVoicePrefix then
		desc:setVoicePrefix("NotAZombie")
	end
	local emitter = zombie:getEmitter()
	if emitter and emitter.stopSoundByName then
		emitter:stopSoundByName("FemaleZombieVoiceA")
		emitter:stopSoundByName("FemaleZombieVoiceB")
		emitter:stopSoundByName("FemaleZombieVoiceC")
		emitter:stopSoundByName("MaleZombieVoiceA")
		emitter:stopSoundByName("MaleZombieVoiceB")
		emitter:stopSoundByName("MaleZombieVoiceC")
	end
end

local function spawnDummyZombie(worldobjects, playerObj, square, genderChoice)
	print("[ZR Debug] spawnDummyZombie fired: gender=" .. tostring(genderChoice))
	if not square then
		playerObj:Say("ZR Debug: no valid square under the cursor")
		return
	end

	local wantFemale
	if genderChoice == "female" then
		wantFemale = true
	elseif genderChoice == "male" then
		wantFemale = false
	else
		wantFemale = not playerObj:isFemale()
	end

	local zombie
	pcall(function()
		if createZombie then
			zombie = createZombie(
				square:getX(), square:getY(), square:getZ(),
				nil, 0, IsoDirections.S
			)
		end
	end)
	if not zombie then
		playerObj:Say("ZR Debug: createZombie failed")
		print("[ZR Debug] createZombie returned nil — abort")
		return
	end

	zombie:setVariable(DUMMY_TAG, true)
	local md = zombie:getModData()
	md.zomborutDummy = true
	md.zrDummyZombie = true
	md.zrDummyZombieConfigured = true

	if zombie.setFemale then zombie:setFemale(wantFemale) end
	if zombie.resetModelNextFrame then zombie:resetModelNextFrame() end

	pcall(function()
		zombie:setUseless(true)
		zombie:setNoTeeth(true)
		zombie:setCanWalk(false)
		zombie:clearAggroList()
		zombie:setTarget(nil)
	end)

	playerObj:Say("ZR Debug: dummy zombie spawned (" ..
		(wantFemale and "F" or "M") .. ")")
	print("[ZR Debug] dummy zombie configured: id=" .. zombie:getID())
end

local AVOID_CLAN_KEYWORDS = {
	"army", "militia", "military", "legion", "officer", "soldier",
	"spike",
	"medieval",
	"prison",
}

local function pickNonSoldierClanId()
	if not banditsAvailable() then return nil end
	BanditCustom.Load()
	local clans = BanditCustom.ClanGetAllSorted()

	local candidates = {}
	for cid, clan in pairs(clans) do
		local name = (clan and clan.general and clan.general.name or ""):lower()
		local skip = false
		for _, kw in ipairs(AVOID_CLAN_KEYWORDS) do
			if string.find(name, kw, 1, true) then
				skip = true
				break
			end
		end
		if not skip and name ~= "" then
			candidates[#candidates + 1] = { cid = cid, name = name }
		end
	end

	if #candidates > 0 then
		local pick = candidates[ZombRand(#candidates) + 1]
		print("[ZR Debug] clan pick: " .. pick.name .. " (cid=" .. tostring(pick.cid) .. ")")
		return pick.cid
	end

	print("[ZR Debug] WARN no non-soldier clan found, using first available")
	for cid, _ in pairs(clans) do return cid end
end

local function spawnDummyBandit(worldobjects, playerObj, square, genderChoice)
	print("[ZR Debug] spawnDummyBandit fired: gender=" .. tostring(genderChoice))
	if not square then
		playerObj:Say("ZR Debug: no valid square under the cursor")
		return
	end
	if not banditsAvailable() then
		playerObj:Say("ZR Debug: Bandits mod required for dummy bandits")
		print("[ZR Debug] Bandits not loaded — abort bandit spawn")
		return
	end

	local cid = pickNonSoldierClanId()
	if not cid then
		playerObj:Say("ZR Debug: no bandit clans available")
		print("[ZR Debug] no clans loaded — abort bandit spawn")
		return
	end

	local preExisting = {}
	local zl = getWorld():getCell():getZombieList()
	for i = 0, zl:size() - 1 do
		local z = zl:get(i)
		if z:getVariableBoolean("Bandit") then
			preExisting[z:getID()] = true
		end
	end

	sendClientCommand(playerObj, 'Spawner', 'Clan', {
		cid = cid,
		x = square:getX(), y = square:getY(), z = square:getZ(),
		program = "Companion", size = 1,
		hostile = false, hostileP = false,
	})

	local wantFemale
	if genderChoice == "female" then
		wantFemale = true
	elseif genderChoice == "male" then
		wantFemale = false
	else
		wantFemale = not playerObj:isFemale()
	end

	local setupHandler
	setupHandler = function(zombie)
		if not zombie:getVariableBoolean("Bandit") then return end
		if preExisting[zombie:getID()] then return end
		if zombie:DistTo(playerObj) > 10 then return end
		if zombie:getModData().zrDummyBanditConfigured then return end

		zombie:getModData().zrDummyBanditConfigured = true
		zombie:setVariable(DUMMY_TAG, true)
		zombie:getModData().zomborutDummy = true
		zombie:getModData().zrDummyBandit = true

		Bandit.SetHostile(zombie, false); Bandit.SetHostileP(zombie, false)
		Bandit.ForceStationary(zombie, true)
		Bandit.ClearTasks(zombie)

		zombie:setPrimaryHandItem(nil); zombie:setSecondaryHandItem(nil)
		local brain = BanditBrain.Get(zombie)
		if brain and brain.weapons then
			brain.weapons.melee = "Base.BareHands"
			brain.weapons.primary = { bulletsLeft = 0, magCount = 0 }
			brain.weapons.secondary = { bulletsLeft = 0, magCount = 0 }
		end
		zombie:setVariable("BanditPrimary", "")
		zombie:setVariable("BanditSecondary", "")
		zombie:setVariable("BanditPrimaryType", "")

		if brain then brain.zrDummyBandit = true end

		if zombie.setFemale then zombie:setFemale(wantFemale) end
		if zombie.resetModelNextFrame then zombie:resetModelNextFrame() end

		Events.OnZombieUpdate.Remove(setupHandler)

		playerObj:Say("ZR Debug: pacified dummy bandit spawned (" ..
			(wantFemale and "F" or "M") .. ")")
		print("[ZR Debug] dummy bandit configured: id=" .. zombie:getID() ..
			" name=" .. tostring(brain and brain.fullname))
	end
	Events.OnZombieUpdate.Add(setupHandler)
end

local function removeAllDummies(worldobjects, playerObj)
	local removed = 0
	local cell = getWorld():getCell()
	local zList = cell and cell:getZombieList()
	if zList then
		for i = zList:size() - 1, 0, -1 do
			local z = zList:get(i)
			if z and z:getVariableBoolean(DUMMY_TAG) then
				z:removeFromWorld()
				removed = removed + 1
			end
		end
	end
	playerObj:Say("ZR Debug: removed " .. tostring(removed) .. " dummy NPC(s)")
	print("[ZR Debug] removeAllDummies: " .. tostring(removed))
end

local function onFillWorldObjectContextMenu(playerIndex, context, worldobjects, test)
	if test == true then return end
	if not isDebugEnabled() then return end

	local playerObj = getSpecificPlayer(playerIndex)
	if not playerObj then return end

	local square = pickSquareFromContext(worldobjects)

	local rootOption = context:addOption("ZR Debug", worldobjects, nil)
	local rootSub = ISContextMenu:getNew(context)
	context:addSubMenu(rootOption, rootSub)

	local hasBandits = banditsAvailable()

	if square then
		local spawnHeader = rootSub:addOption("Spawn Dummy Zombie", worldobjects, nil)
		local spawnSub = ISContextMenu:getNew(rootSub)
		rootSub:addSubMenu(spawnHeader, spawnSub)

		spawnSub:addOption("Opposite Gender (pairing)", worldobjects,
			spawnDummyZombie, playerObj, square, "opposite")
		spawnSub:addOption("Male", worldobjects,
			spawnDummyZombie, playerObj, square, "male")
		spawnSub:addOption("Female", worldobjects,
			spawnDummyZombie, playerObj, square, "female")

		if hasBandits then
			local spawnBanditHeader = rootSub:addOption("Spawn Dummy Bandit", worldobjects, nil)
			local spawnBanditSub = ISContextMenu:getNew(rootSub)
			rootSub:addSubMenu(spawnBanditHeader, spawnBanditSub)

			spawnBanditSub:addOption("Opposite Gender (pairing)", worldobjects,
				spawnDummyBandit, playerObj, square, "opposite")
			spawnBanditSub:addOption("Male", worldobjects,
				spawnDummyBandit, playerObj, square, "male")
			spawnBanditSub:addOption("Female", worldobjects,
				spawnDummyBandit, playerObj, square, "female")
		else
			local disabledBandit = rootSub:addOption("Spawn Dummy Bandit (Bandits mod required)", worldobjects, nil)
			disabledBandit.notAvailable = true
		end
	else
		local disabled = rootSub:addOption("Spawn Dummy Zombie (click on a tile)", worldobjects, nil)
		disabled.notAvailable = true
		local disabledBandit = rootSub:addOption("Spawn Dummy Bandit (click on a tile)", worldobjects, nil)
		disabledBandit.notAvailable = true
	end

	rootSub:addOption("Remove All Dummies", worldobjects, removeAllDummies, playerObj)

end

Events.OnFillWorldObjectContextMenu.Add(onFillWorldObjectContextMenu)

local function pinTaggedDummy(zombie)
	if not zombie then return end

	local isDummyZombie = zombie:getVariableBoolean(DUMMY_TAG)
	local isDummyBandit = false
	local hasBanditVar = zombie:getVariableBoolean("Bandit")
	local brain = nil
	if hasBanditVar and BanditBrain and BanditBrain.Get then
		brain = BanditBrain.Get(zombie)
		if brain and brain.zrDummyBandit then isDummyBandit = true end
	end

	if hasBanditVar and not brain then
		pcall(function() zombie:setVariable("Bandit", false) end)
		pcall(function() zombie:setVariable("BanditPrimary", "") end)
		pcall(function() zombie:setVariable("BanditSecondary", "") end)
		print("[ZR Heal] cleared Bandit=true on brain-less zombie id=" .. tostring(zombie:getID()))
	end

	if isDummyZombie or isDummyBandit then
		zombie:clearAggroList()
		zombie:setTarget(nil)
		zombie:setCanWalk(false)
	end

	if isDummyZombie and not isDummyBandit then
		pcall(function()
			zombie:setUseless(true)
			zombie:setNoTeeth(true)
			zombie:setCollidable(true)
			zombie:setInvincible(false)
		end)
	end

	if isDummyBandit then
		if not isDummyZombie then
			zombie:setVariable(DUMMY_TAG, true)
		end
		local md = zombie:getModData()
		md.zrDummyBandit = true
		md.zomborutDummy = true
		md.zrDummyBanditConfigured = true
		if Bandit and Bandit.IsHostile and Bandit.IsHostile(zombie) then
			Bandit.SetHostile(zombie, false)
		end
		if Bandit and Bandit.IsForceStationary and not Bandit.IsForceStationary(zombie) then
			Bandit.ForceStationary(zombie, true)
		end
	end
end
Events.OnZombieUpdate.Add(pinTaggedDummy)
