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

pEventListener = GetStringParam("event_listener", "")
pVoxelsToDestroy = GetIntParam("voxels_to_destroy", 275)
pCheckAll = GetBoolParam("check_all_shapes", true)

calls, numCalls = {}, 3
for i = 1, numCalls do
    calls["call"..i] = GetStringParam("call_function"..i, "")
    calls["call"..i.."delay"] = GetFloatParam("call_delay"..i, 0.0)
end

function init()
    local script = GetScriptId()
    shapes = FindShapes()
    shapes.voxels, shapes.voxels_to_destroy, shapes.broken = {}, {}, { count = 0 }
    for i=#shapes,1,-1 do
        local shape = shapes[i]
        local body = GetShapeBody(shape)
        for j = 1, numCalls do
            if calls["call"..j]:find"__HANDLE__" and HasTag(body, "parent_prop") then
                SetTag(body, "parent_prop", tostring(script))
            end
        end
        if HasTag(shape, "ignore_break") then
            table.remove(shapes, i)
        else
            shapes.voxels_to_destroy[i] = tonumber(GetTagValue(shape, 'voxels_to_destroy'))
        end
    end
    for i = 1, numCalls do
        calls["call"..i] = calls["call"..i]:gsub('__HANDLE__', script)
    end
    for i = 1, #shapes do shapes.voxels[i] = GetShapeVoxelCount(shapes[i]) end
    completed = false
    forced = false
    maxdelay = nil

    if pEventListener ~= "" then
        RegisterListenerTo(EVENTS.UPDATE_STATE, "UpdateState")
    end
end

function update(dt)
    if completed then
        if maxdelay then
            maxdelay = maxdelay - dt
            for i = 1, numCalls do
                local call = calls["call"..i]
                if call ~= "" then
                    local delay = calls["call"..i.."delay"]
                    calls["call"..i.."delay"] = delay - dt
                    if delay <= dt then
                        TriggerEvent(EVENTS.CALL_FUNCTION, call)
                        calls["call"..i] = ""
                    end
                end
            end
            if maxdelay <= 0 then
                maxdelay = nil
                cEntity:EnqueueDeletion()
            end
        end
        return
    end

    for i = 1, #shapes do repeat
        if shapes.broken[i] then break end

        local shape = shapes[i]
        local voxels_to_destroy = shapes.voxels_to_destroy[i]
        local voxdiff = shapes.voxels[i] - GetShapeVoxelCount(shape)

        -- shape tag has more priority than script param
        if voxdiff > (voxels_to_destroy or pVoxelsToDestroy) then
            shapes.broken[i] = true
            shapes.broken.count = shapes.broken.count + 1

            if not HasTag(shape, 'call') then break end
            TriggerEvent(EVENTS.CALL_FUNCTION, GetTagValue(shape, 'call'))
        end
    until true end

    if forced or (not pCheckAll and shapes.broken.count>0) or #shapes.broken == #shapes then
        local nodelays = true
        maxdelay = 0
        for i = 1, numCalls do
            local call = calls["call"..i]
            if call ~= "" then
                local delay = calls["call"..i.."delay"]
                if delay > 0 then
                    maxdelay = math.max(maxdelay, delay)
                    nodelays = false
                else
                    TriggerEvent(EVENTS.CALL_FUNCTION, call)
                end
            end
        end
        if nodelays then
            cEntity:EnqueueDeletion()
        end
        completed = true
    end
end

function UpdateState(data)
    if data ~= pEventListener then return end

    forced = true
end
