#include "../helpers/string.lua"
#include "../helpers/entity.lua"
#include "../helpers/utils.lua"
#include "../../config/events.lua"

script_name = GetStringParam("script_name", "")

init_cond   = GetStringParam("init_cond", "")
a_var_fn    = GetStringParam("a_var_fn", "")
a_var_args  = GetStringParam("a_var_args", "")
b_var_op    = GetStringParam("b_var_op", "")
b_var_fn    = GetStringParam("b_var_fn", "")
b_var_args  = GetStringParam("b_var_args", "")
b_cond      = GetStringParam("b_cond", "")
exec_fn     = GetStringParam("exec_fn", "")

function init()
    if a_var_fn == "" or exec_fn == "" then DISABLED = cEntity:EnqueueDeletion() return end
    if init_cond ~= "" then
        RegisterListenerTo(EVENTS.MAIN_FIRST_TICK, "initLogic")
        DISABLED = true
        return
    end
    initLogic()
end

function initLogic()
    if init_cond ~= "" and not loadstring("return " .. init_cond)() then
        UnregisterListener(EVENTS.MAIN_FIRST_TICK, "initLogic")
        DISABLED = cEntity:EnqueueDeletion()
        return
    end

    local a_values = a_var_args:as_map("([^=,]+)=?([^,]*)", nil, OrderedTable())
    for k, v in pairs(a_values) do
        if type(k) == "string" then
            _G[k] = loadstring("return " .. v)()
        end
    end

    if b_var_fn ~= "" and b_var_args ~= "" and b_var_op ~= "" then
        local b_values = b_var_args:as_map("([^=,]+)=?([^,]*)", nil, OrderedTable())
        b_var_args_arr = {}
        for k, v in pairs(b_values) do
            if type(k) == "string" and not _G[k] then
                _G[k] = loadstring("return " .. v)()
            end
            if _G[k] then
                if type(_G[k]) == "table" then
                    b_var_args_arr[#b_var_args_arr+1] = _G[k]
                else
                    b_var_args_arr[#b_var_args_arr+1] = loadstring("return " .. _G[k])()
                end
            else
                b_var_args_arr[#b_var_args_arr+1] = loadstring("return " .. v)()
            end
        end
        local var, fn = b_var_fn:match("([^=]+)=?(.*)")
        if fn == "" then var, fn = nil, var end
        local b_inversed = select(2, fn:find"not ")
        if b_inversed then
            b_var_fn = fn:sub(b_inversed+1)
            b_inversed_logic = true
        end
        if var then
            local b = _G[fn](unpack(b_var_args_arr))
            if b_inversed_logic then b = not b end
            b_var = b
            _G[var] = b
        end
        either = b_var_op:find" or " and true
        b_found = true
    end

    a_var_args_arr = {}
    for k, v in pairs(a_values) do
        if _G[k] then
            a_var_args_arr[#a_var_args_arr+1] = _G[k]
        else
            a_var_args_arr[#a_var_args_arr+1] = v
        end
    end
    local a_inversed = select(2, a_var_fn:find"not ")
    if a_inversed then
        a_var_fn = a_var_fn:sub(a_inversed+1)
        a_inversed_logic = true
    end

    if script_name ~= "" then
        initListeners()
    end
    DISABLED = nil
end

function initListeners()
    RegisterListenerTo(EVENTS.UPDATE_COMPARISON, "UpdateComparison")
end

function handleCommand(str)
    if str == "quickload" then
        if script_name ~= "" then
            initListeners()
        end
    end
end

function update(dt)
    if DISABLED then return end

    local res = _G[a_var_fn](unpack(a_var_args_arr))
    if a_inversed_logic then res = not res end

    if not res and not either then
        return
    elseif b_found then
        local b = b_var or _G[b_var_fn](unpack(b_var_args_arr))
        if b_inversed_logic then b = not b end

        b = b_var_op .. tostring(b) .. b_cond
        res = loadstring("return " .. tostring(res) .. b)()
    end
    if res then
        loadstring(exec_fn)()
        DISABLED = cEntity:EnqueueDeletion()
    end
end

-- works only with numbers right now
function UpdateComparison(data)
    if not data:find(script_name) then return end

    data = (data:gsub(script_name .. ";", ""))
    b_cond = (b_cond:gsub("([%d.]+)", data))
end
