-- Prevent running if menu is disabled
if not TX_MENU_ENABLED then return end

-- =============================================
--  Client PlayerList handler
-- =============================================

-- Optimizations
local tonumber = tonumber
local tostring = tostring
local floor = math.floor

-- Variables & Consts
LOCAL_PLAYERLIST = {} -- available globally in tx
local requirePlayerNames = false
local vTypeMap = {
    ["0"] = "walking",
    ["1"] = "driving", --automobile
    ["2"] = "biking",
    ["3"] = "boating",
    ["4"] = "flying", --heli
    ["5"] = "flying", --plane
    ["6"] = "boating", --submarine
    ["7"] = "driving", --trailer
    ["8"] = "driving", --train
}


-- Transforms the playerlist and sends to react
-- The playerlist is converted to an object array to save refactor time
function sendReactPlayerlist()
    local upload = {}
    for pids, playerData in pairs(LOCAL_PLAYERLIST) do
        upload[#upload + 1] = {
            id = tonumber(pids),
            name = playerData.name or "unknown",
            health = playerData.health,
            dist = playerData.dist,
            vType = playerData.vType,
            admin = playerData.admin
        }
    end
    -- print("========== function sendReactPlayerlist()")
    -- print(json.encode(upload))
    -- print("------------------------------------")
    sendMenuMessage('setPlayerList', upload)
end


-- Triggered when the admin authenticates
-- Replaces current playerlist
RegisterNetEvent('txcl:plist:setInitial', function(payload)
    -- print("========== EVENT setInitialPlayerlist")
    -- print(json.encode(payload)) -- [[id, name]]
    -- print("------------------------------------")
    LOCAL_PLAYERLIST = {}
    for _, playerData in pairs(payload) do
        local pids = tostring(playerData[1])
        LOCAL_PLAYERLIST[pids] = {
            name = playerData[2],
            health = 0,
            dist = -1,
            vType = "unknown",
            admin = false
        }
    end
    -- print("------------------------------------")
    -- print(json.encode(LOCAL_PLAYERLIST, {indent = true}))
    -- print("------------------------------------")
    sendReactPlayerlist()
end)


-- Triggered on the return of "getDetailedPlayerlist"
--  > run through inbound playerlist updating existing data
--  > try to get the dist from all players (onesync only)
RegisterNetEvent('txcl:plist:setDetailed', function(players, admins)
    -- print("========== EVENT setDetailedPlayerlist")
    -- print(json.encode(players)) -- [[id, health, vType, xCoord, yCoord, name]]
    -- print("------------------------------------")
    local myID = GetPlayerServerId(PlayerId())
    local myPed = PlayerPedId()
    local myCoords = GetEntityCoords(myPed)

    for _, playerData in pairs(players) do
        local pid = playerData[1]
        local pidStr = tostring(playerData[1])
        local localPlayer = LOCAL_PLAYERLIST[pidStr]
        -- Set inbound data
        if localPlayer == nil then
            debugPrint("Playerlist: received detailed info for player "..pidStr.." not present in local playerlist")
            requirePlayerNames = true
            LOCAL_PLAYERLIST[pidStr] = {
                name = "unknown",
                health = playerData[2],
                vType = vTypeMap[tostring(playerData[3])] or "unknown",
                admin = false
            }
        else
            LOCAL_PLAYERLIST[pidStr].health = playerData[2]
            LOCAL_PLAYERLIST[pidStr].vType = vTypeMap[tostring(playerData[3])] or "unknown"
            -- Set the player name if available - used when the playerJoining (txcl:plist:updatePlayer) was missed
            if playerData[6] then
                LOCAL_PLAYERLIST[pidStr].name = playerData[6]
            end
        end

        --Mark as updated
        LOCAL_PLAYERLIST[pidStr].inLastUpdate = true

        -- Getting distance + health for RedM
        -- NOTE: RedM doesn't save ped health data on server, so need to get locally
        if pid == myID then
            LOCAL_PLAYERLIST[pidStr].dist = 0
            if IS_REDM then
                LOCAL_PLAYERLIST[pidStr].health = GetPedHealthPercent(myPed)
            end
        else
            --calc distance (onesync only, 2d only)
            if playerData[4] == nil or playerData[5] == nil then
                LOCAL_PLAYERLIST[pidStr].dist = -1
            else
                local remoteCoords = vector3(playerData[4], playerData[5], myCoords.z)
                LOCAL_PLAYERLIST[pidStr].dist = floor(#(myCoords - remoteCoords))
            end

            --get health locally
            if IS_REDM then
                local remotePlayer = GetPlayerFromServerId(pid)
                if remotePlayer == -1 then
                    LOCAL_PLAYERLIST[pidStr].health = -1
                else
                    local remotePed = GetPlayerPed(remotePlayer)
                    LOCAL_PLAYERLIST[pidStr].health = GetPedHealthPercent(remotePed)
                end
            end
        end
    end

    --Check if player disconnected and the playerDropped (txcl:plist:updatePlayer) was missed
    for playerID, playerData in pairs(LOCAL_PLAYERLIST) do
        if playerData.inLastUpdate == true then
            playerData.inLastUpdate = false
        else
            debugPrint("Playerlist: did not receive detailed info for player "..playerID.." present in local playerlist")
            LOCAL_PLAYERLIST[playerID] = nil
        end
    end

    -- Mark admins
    for _, adminID in pairs(admins) do
        local id = tostring(adminID)
        if LOCAL_PLAYERLIST[id] ~= nil then
            LOCAL_PLAYERLIST[id].admin = true
        end
    end

    -- print("------------------------------------")
    -- print(json.encode(LOCAL_PLAYERLIST, {indent = true}))
    -- print("------------------------------------")
    sendReactPlayerlist()
end)


-- Triggered on player join/leave
-- add/remove specific id to playerlist
RegisterNetEvent('txcl:plist:updatePlayer', function(id, data)
    local pids = tostring(id)
    if data == false then
        debugPrint("^2txcl:plist:updatePlayer: ^3"..id.."^2 disconnected")
        LOCAL_PLAYERLIST[pids] = nil
    else
        debugPrint("^2txcl:plist:updatePlayer: ^3"..id.."^2 connected")
        LOCAL_PLAYERLIST[pids] = {
            name = data,
            health = 0,
            dist = -1,
            vType = "unknown",
            admin = false
        }
    end
    sendReactPlayerlist()
end)


-- Triggered when the "player" tab opens in the menu, and every 5s after that
RegisterSecureNuiCallback('signalPlayersPageOpen', function(_, cb)
    TriggerServerEvent('txsv:req:plist:getDetailed', requirePlayerNames)
    requirePlayerNames = false
    cb({})
end)


-- DEBUG only
-- RegisterCommand('tnew', function()
--     TriggerServerEvent('txsv:req:plist:getDetailed')
-- end)
-- RegisterCommand('tprint', function()
--     print("------------------------------------")
--     print(json.encode(LOCAL_PLAYERLIST, {indent = true}))
--     print("------------------------------------")
-- end)
