#include "../../config/constants.lua"
#include "../../config/events.lua"
#include "../helpers/registry.lua"
#include "../helpers/string.lua"

requester = {
    cache = {},
    time = {},
}

requester_init = function()
    setmetatable(requester, {
        __call = function(self, ...)
            local REQUEST_INFO_TYPES = {
                AI_TRANSFORM        = "AI_TRANSFORM",
                PLAYER_TRANSFORM    = "PLAYER_TRANSFORM",
                CAMERA_TRANSFORM    = "CAMERA_TRANSFORM",
                GLOBAL_VARIABLE     = "GLOBAL_VARIABLE", -- number/string/bool only
                VEHICLE_HEALTH      = "VEHICLE_HEALTH",
            }
            local REQUESTED_INFO = {
                -- AI_TRANSFORM        = function(i) local veh = GetInt("level.players."..i) if veh <= 0 then return "" else return TransformStr(GetVehicleTransform(veh)) end end,
                -- PLAYER_TRANSFORM    = function() return TransformStr(GetPlayerTransform()) end,
                AI_TRANSFORM        = function(i) return TransformStr(cRegistry:GetTransformPlayer(tonumber(i))) end,
                PLAYER_TRANSFORM    = function(with_rot) return TransformStr(cRegistry:GetTransformPlayer("player", with_rot)) end,
                CAMERA_TRANSFORM    = function() return TransformStr(GetCameraTransform()) end,
                VEHICLE_HEALTH      = function(handle) return GetVehicleHealth(tonumber(handle)) end,
            }

            requester_onRequest = function(data)
                local typ, freq, argument, opt_ret = data:unpack_gmatch"[^;]+"
                if not REQUEST_INFO_TYPES[typ] then
                    return
                elseif typ == REQUEST_INFO_TYPES.GLOBAL_VARIABLE then
                    if not argument then argument = freq end

                    TriggerEvent(EVENTS.RESPONSE, typ .. ";" .. _G[argument])
                elseif argument then
                    freq = tonumber(freq)
                    local time = freq ~= -1 and GetTime() or nil
                    local last_time = self.time
                    local cache = self.cache

                    if not time or not last_time[typ]
                    or not last_time[typ][argument] or last_time[typ][argument]+freq <= time then
                        if not cache[typ] then cache[typ] = {} end
                        if not last_time[typ] then last_time[typ] = {} end

                        cache[typ][argument] = REQUESTED_INFO[typ](argument)
                        last_time[typ][argument] = time
                    end
                    TriggerEvent(EVENTS.RESPONSE, typ .. ";" .. cache[typ][argument] .. ";" .. (opt_ret or argument))
                else
                    freq = tonumber(freq)
                    local time = freq ~= -1 and GetTime() or nil
                    local last_time = self.time
                    local cache = self.cache

                    if not time or not last_time[typ]
                    or not last_time[typ] or last_time[typ]+freq <= time then
                        cache[typ] = REQUESTED_INFO[typ]()
                        last_time[typ] = time
                    end
                    TriggerEvent(EVENTS.RESPONSE, typ .. ";" .. cache[typ] .. (opt_ret and ";"..opt_ret or ''))
                end
            end

            RegisterListenerTo(EVENTS.REQUEST, "requester_onRequest")
        end,
    })
end

function requester:Unregister()
    UnregisterListener(EVENTS.REQUEST, "requester_onRequest")
end
