-- Host-side Team Menu actions.
HT.TrollMenu = {
    teamGodMode = false,
    _hooked = false,
    bagTypes = { "money", "gold", "diamonds", "coke", "weapon", "painting" },
    equipmentTypes = { "ammo", "medic", "ecm", "sentry", "trip_mine", "bodybag" }
}

local function eachPlayer(fn)
    local session = managers.network and managers.network:session()
    if not session then return end
    for _, peer in pairs(session:peers()) do
        local unit = peer:unit()
        if alive(unit) then pcall(fn, peer, unit) end
    end
    local peer = session:local_peer()
    local unit = managers.player and managers.player:player_unit()
    if peer and alive(unit) then pcall(fn, peer, unit) end
end

function HT.TrollMenu:installHooks()
    if self._hooked then return end
    self._hooked = true
    pcall(function()
        if _G.SentryGunBase then
            _G.CloneClass(SentryGunBase)
            function SentryGunBase:pre_destroy(...)
                if self._sentry_uid == nil then self._sentry_uid = "ht_orphan_sentry" end
                return SentryGunBase.orig.pre_destroy(self, ...)
            end
        end
    end)
    pcall(function()
        if _G.UnitNetworkHandler then
            _G.CloneClass(UnitNetworkHandler)
            function UnitNetworkHandler:set_health(unit, percent, max_mul, sender)
                local protect = HT.TrollMenu.teamGodMode or HT:getSetting("enable_team_fall_protection")
                local result = UnitNetworkHandler.orig.set_health(self, unit, percent, max_mul, sender)
                if protect and alive(unit) and percent and percent < 100 then
                    pcall(function()
                        unit:network():send_to_unit({ "spawn_dropin_penalty", false, false, 1, 0, 0, 0 })
                    end)
                end
                return result
            end
        end
    end)
end

function HT.TrollMenu:selectedPeers()
    local session = managers.network and managers.network:session()
    if not session then return {} end
    local peers = {}
    for _, peer in pairs(session:peers()) do table.insert(peers, peer) end
    table.sort(peers, function(a, b) return a:id() < b:id() end)
    local target = tonumber(HT:getSetting("team_target")) or 1
    if target == 1 then return peers end
    return peers[target - 1] and { peers[target - 1] } or {}
end

function HT.TrollMenu:setTeamTarget(value)
    HT:setSetting("team_target", tonumber(value) or 1)
end

function HT.TrollMenu:setTeamGodMode(value)
    self:installHooks()
    self.teamGodMode = value and true or false
    HT:setSetting("enable_troll_team_god_mode", self.teamGodMode)
    for _, peer in ipairs(self:selectedPeers()) do
        local unit = peer:unit()
        if alive(unit) then
            pcall(function() unit:character_damage():set_mission_damage_blockers("invulnerable", self.teamGodMode) end)
            if self.teamGodMode then
                pcall(function() unit:network():send_to_unit({ "spawn_dropin_penalty", false, false, 1, 0, 0, 0 }) end)
            end
        end
    end
end

function HT.TrollMenu:spawnBagsOnAll()
    local bag = self.bagTypes[tonumber(HT:getSetting("troll_bag_type")) or 1] or "money"
    if not (tweak_data.carry and tweak_data.carry[bag]) then
        HT:addAlert("Invalid bag type '" .. bag .. "'", HT.colors.warning, false)
        return
    end
    local count = 0
    eachPlayer(function(_, unit)
        local value = 1
        pcall(function() value = managers.money:get_bag_value(bag) end)
        managers.player:server_drop_carry(bag, value, true, true, 1,
            unit:position() + Vector3(0, 0, 100), unit:rotation(), Vector3(0, 0, 50), 0, nil, nil)
        count = count + 1
    end)
    HT:addAlert("Dropped '" .. bag .. "' on " .. count .. " players", HT.colors.success, false)
end

function HT.TrollMenu:giveEquipmentToAll()
    local kind = self.equipmentTypes[tonumber(HT:getSetting("troll_equipment_type")) or 1] or "ammo"
    self:installHooks()
    local session = managers.network and managers.network:session()
    if not session then return end
    local localPeer = session:local_peer()
    local player = managers.player:player_unit()
    local count = 0
    eachPlayer(function(_, unit)
        local pos, rot = unit:position(), unit:rotation()
        pcall(function()
            if kind == "ammo" then
                AmmoBagBase.spawn(pos, rot, 1)
            elseif kind == "medic" then
                DoctorBagBase.spawn(pos, rot, 1)
            elseif kind == "bodybag" then
                BodyBagsBagBase.spawn(pos, rot, 1)
            elseif kind == "ecm" then
                local spawned = ECMJammerBase.spawn(pos, rot, 1, player, localPeer:id())
                spawned:base():set_active(true)
            elseif kind == "trip_mine" then
                local spawned = TripMineBase.spawn(pos, rot, false, localPeer:id())
                spawned:base():set_active(true, player)
            elseif kind == "sentry" then
                local spawned, spread, rotation = SentryGunBase.spawn(player, pos, rot, localPeer:id())
                if alive(spawned) then
                    pcall(function() spawned:base():post_setup(1) end)
                    pcall(function()
                        session:send_to_peers("from_server_sentry_gun_place_result",
                            localPeer:id(), nil, spawned, rotation or 1, spread or 1, false, nil, 1)
                    end)
                end
            end
        end)
        count = count + 1
    end)
    HT:addAlert("Gave '" .. kind .. "' to " .. count .. " players", HT.colors.success, false)
end

function HT.TrollMenu:reviveSelected()
    local count = 0
    for _, peer in ipairs(self:selectedPeers()) do
        local unit = peer:unit()
        if alive(unit) then
            pcall(function() unit:character_damage():revive(true) end)
            pcall(function() unit:network():send_to_unit({ "revive_player" }) end)
            count = count + 1
        end
    end
    HT:addAlert("Revived " .. count .. " teammate(s)", HT.colors.success, false)
end

function HT.TrollMenu:releaseSelected()
    local count = 0
    for _, peer in ipairs(self:selectedPeers()) do
        pcall(function() IngameWaitingForRespawnState.request_player_spawn(peer:id()) end)
        count = count + 1
    end
    HT:addAlert("Released " .. count .. " teammate(s)", HT.colors.success, false)
end

function HT.TrollMenu:teleportSelected()
    local host = managers.player and managers.player:player_unit()
    if not alive(host) then return end
    local count = 0
    for _, peer in ipairs(self:selectedPeers()) do
        local unit = peer:unit()
        if alive(unit) then
            local position = host:position() + Vector3(0, 0, 25)
            pcall(function() unit:movement():set_position(position) end)
            pcall(function() unit:set_position(position) end)
            count = count + 1
        end
    end
    HT:addAlert("Teleported " .. count .. " teammate(s)", HT.colors.success, false)
end

function HT.TrollMenu:giveSelectedSupply(kind)
    local count = 0
    for _, peer in ipairs(self:selectedPeers()) do
        local unit = peer:unit()
        if alive(unit) then
            if kind == "refill" then
                pcall(function() unit:base():replenish() end)
                pcall(function() unit:character_damage():replenish() end)
            else
                pcall(function() unit:network():send_to_unit({ "give_equipment", kind, 6 }) end)
            end
            count = count + 1
        end
    end
    HT:addAlert("Gave " .. kind .. " to " .. count .. " teammate(s)", HT.colors.success, false)
end

function HT.TrollMenu:setTeamFallProtection(value)
    self:installHooks()
    value = value and true or false
    HT:setSetting("enable_team_fall_protection", value)
    for _, peer in ipairs(self:selectedPeers()) do
        local unit = peer:unit()
        if alive(unit) then
            pcall(function() unit:character_damage():set_mission_damage_blockers("damage_fall_disabled", value) end)
            if value then
                pcall(function() unit:network():send_to_unit({ "spawn_dropin_penalty", false, false, 1, 0, 0, 0 }) end)
            end
        end
    end
end

function HT.TrollMenu:markAllEnemies()
    local count = 0
    for _, data in pairs(managers.enemy and managers.enemy:all_enemies() or {}) do
        if alive(data.unit) then
            pcall(function() data.unit:contour():add("mark_enemy", true, 1000) end)
            count = count + 1
        end
    end
    HT:addAlert("Marked " .. count .. " enemies for the lobby", HT.colors.success, false)
end

function HT.TrollMenu:disableLobbySecurity()
    pcall(function() HT.Extra:setDisableCameras(true) end)
    local count = 0
    for _, unit in pairs(World:find_units_quick("all")) do
        pcall(function()
            if alive(unit) and unit:base() and
                (unit:base()._tweak_table == "swat_van_turret_module" or unit:base().is_sentry_gun) then
                if unit:brain() then unit:brain():set_active(false) end
                count = count + 1
            end
        end)
    end
    HT:addAlert("Disabled cameras and " .. count .. " turret(s)", HT.colors.success, false)
end

function HT.TrollMenu:announce(message)
    if HT.Utils:isEmptyString(message) then return end
    pcall(function()
        managers.chat:_receive_message(1, "HOST", message, tweak_data.system_chat_color)
        managers.network:session():send_to_peers("send_chat_message", ChatManager.GAME, "[HOST] " .. message)
    end)
end

function HT.TrollMenu:reapply()
    self:installHooks()
    self.teamGodMode = HT:getSetting("enable_troll_team_god_mode") and true or false
    if self.teamGodMode then self:setTeamGodMode(true) end
    if HT:getSetting("enable_team_fall_protection") then self:setTeamFallProtection(true) end
end

function HT.TrollMenu:disableAll()
    self.teamGodMode = false
end
