-- LogicCenter.lua

-- Ativa ou desativa logs para debug
local ENABLE_LOGICENTER_LOGS = false

-- Função auxiliar para log
local function log(message, ...)
    if ENABLE_LOGICENTER_LOGS then
        print(string.format(message, ...))
    end
end

-- Cria uma tabela estática para armazenar o estado do LogicCenter
LogicCenter = {}
LogicCenter.__index = LogicCenter -- Define o metatable para o funcionamento correto

-- Construtor
function LogicCenter:new()
    if LogicCenter.instance ~= nil then
        return LogicCenter.instance -- Garante que apenas uma instância existe
    end

    local self = setmetatable({}, LogicCenter)
    self.timer = 0 -- Armazena o tempo acumulado
    self.interval = 60000 -- Intervalo em milissegundos (2 minutos)
    self.detectedPallets = {} -- Armazena informações dos paletes detectados
    self.currentValidFillTypes = {} -- Armazena os FillTypes válidos da área atual

    LogicCenter.instance = self
    return self
end

-- Função para buscar um Placeable específico pelo nome
function LogicCenter:findPlaceableByName(targetName)
    local placeables = g_currentMission.placeableSystem.placeables

    if placeables ~= nil then
        for _, placeable in ipairs(placeables) do
            if placeable:getName() == targetName then
                return placeable
            end
        end
    end

    return nil
end

-- Função para verificar se um valor está presente em uma tabela
local function tableContains(tbl, value)
    for _, v in ipairs(tbl) do
        if v == value then
            return true
        end
    end
    return false
end
-- move para LOGI CENTER
function LogicCenter:moveValidPalletsToNode(placeable)
    if not placeable then
        log("LogicCenter: Placeable inválido, não é possível mover os paletes.")
        return
    end

    -- Verifica se o armazenamento é compatível
    if not placeable.getObjectStorageCanStoreObject then
        log("LogicCenter: Placeable não possui suporte para armazenamento de objetos.")
        return
    end

    -- Obtém o nó pelo caminho "0|10|1|1"
    local targetNode = I3DUtil.indexToObject(placeable.rootNode, "0|10|1")
    if targetNode == nil then
        log("LogicCenter: Nó de destino '0|10' não encontrado no LOGI CENTER.")
        return
    end

    log("LogicCenter: Movendo paletes válidos para o nó '0|10|1|1'...")

    local targetX, targetY, targetZ = getWorldTranslation(targetNode)

    for _, pallet in ipairs(self.detectedPallets) do
        if tableContains(self.currentValidFillTypes, pallet.fillType) then
            if pallet.nodeId and pallet.nodeId ~= nil then
                local palletObject = g_currentMission.nodeToObject[pallet.nodeId]

                -- Verifica se há espaço no armazenamento
                local canStore, errorId = placeable:getObjectStorageCanStoreObject(palletObject, true)
                if canStore then
                    -- Usa setWorldTranslation para mover o palete
                    setWorldTranslation(pallet.nodeId, targetX, targetY, targetZ)
                    log(string.format("LogicCenter: Palete '%s' movido para (%.2f, %.2f, %.2f).",pallet.name, targetX, targetY, targetZ))
                else
                    log(string.format("LogicCenter: Não há espaço para armazenar o palete '%s'. Erro: %s",pallet.name, errorId or "Desconhecido"))
                end
            else
                log(string.format("LogicCenter: Palete '%s' possui um nodeId inválido e não pode ser movido.",pallet.name))
            end
        end
    end

    placeable:setObjectStorageObjectInfosDirty()
    log("LogicCenter: Tentativa de mover todos os paletes válidos concluída.")
end
-- Função para mover paletes válidos para LOGI TRANSFER
function LogicCenter:moveValidPalletsToTransfer(placeable)
    log("====================================================================")
    if not placeable then
        log("LogicCenter: Placeable inválido, não é possível mover os paletes.")
        return
    end

    -- Obtém o nó pelo caminho "0|10|1"
    local targetNode = I3DUtil.indexToObject(placeable.rootNode, "0|10|1")
    if targetNode == nil then
        log("LogicCenter: Nó de destino '0|10|1' não encontrado no LOGI TRANSFER.")
        return
    end

    log("LogicCenter: Movendo paletes válidos para LOGI TRANSFER...")

    local targetX, targetY, targetZ = getWorldTranslation(targetNode)

    for _, pallet in ipairs(self.detectedPallets) do
        log(string.format("LogicCenter: Verificando palete '%s' com FillType '%s'.",pallet.name or "Desconhecido", tostring(pallet.fillType)))

        if self.currentValidFillTypes[pallet.fillType] then
            if pallet.nodeId and pallet.nodeId ~= nil then
                local palletObject = g_currentMission.nodeToObject[pallet.nodeId]

                if palletObject then
                    log("LogicCenter: Palete localizado no mundo. Verificando armazenamento...")

                    local canStore, errorId

                    -- Verifica SellingStation do ProductionPoint
                    if placeable.spec_productionPoint
                        and placeable.spec_productionPoint.productionPoint
                        and placeable.spec_productionPoint.productionPoint.unloadingStation then

                        log("LogicCenter: Usando SellingStation do ProductionPoint para verificar armazenamento.")
                        canStore = placeable.spec_productionPoint.productionPoint.unloadingStation:getIsFillTypeSupported(pallet.fillType)
                        errorId = canStore and nil or "FillType não suportado"
                    else
                        log("LogicCenter: Nenhum método de armazenamento detectado para LOGI TRANSFER.")
                        canStore = false
                    end

                    -- Resultado da Verificação
                    log(string.format("LogicCenter: Resultado da verificação - CanStore: %s, ErrorID: %s",tostring(canStore), tostring(errorId or "Nenhum")))

                    if canStore then
                        setWorldTranslation(pallet.nodeId, targetX, targetY, targetZ)
                        log(string.format("LogicCenter: Palete '%s' movido para (%.2f, %.2f, %.2f).",pallet.name, targetX, targetY, targetZ))
                    else
                        log(string.format("LogicCenter: Não há espaço para armazenar o palete '%s'. Erro: %s",pallet.name, errorId or "Desconhecido"))
                    end
                else
                    log(string.format("LogicCenter: Não foi possível localizar o objeto do palete '%s'.",pallet.name))
                end
            else
                log(string.format("LogicCenter: Palete '%s' possui um nodeId inválido e não pode ser movido.",pallet.name))
            end
        else
            log(string.format("LogicCenter: FillType '%s' não é válido para este palete.",tostring(pallet.fillType)
            ))
        end
    end

    log("LogicCenter: Tentativa de mover todos os paletes válidos para LOGI TRANSFER concluída.")
    log("--------------------------------------------------------------------------")
end


-- Callback para detectar paletes (apenas paletes cheios)
function LogicCenter:onFindPalletCallback(node)
    local object = g_currentMission.nodeToObject[node]
    if object and object.isa and object:isa(Vehicle) and object.isPallet then
        local fillLevel = object:getFillUnitFillLevel(1) or 0
        local capacity = object:getFillUnitCapacity(1) or 0

        -- Verifica se o palete está completamente cheio
        if fillLevel > 0 and fillLevel >= capacity then
            table.insert(self.detectedPallets, {
                nodeId = node,
                id = object.id or "N/A",
                name = object:getName() or "Desconhecido",
                fillType = object:getFillUnitFillType(1) or "Desconhecido",
                fillLevel = fillLevel,
                capacity = capacity
            })
        end
    end
    return true
end
-- Função principal para verificar paletes e áreas
function LogicCenter:checkAndDrawClearAreas()
    local playerFarmId = g_currentMission:getFarmId()
    if not playerFarmId then
        log("LogicCenter: Erro - ID da fazenda do jogador não encontrado.")
        return
    end

    log("LogicCenter: Verificando paletes nas ClearAreas dos placeables do jogador...")

    local validStaticFillTypes = {
        [FillType.EGG] = true,
        [FillType.WOOL] = true,
        [FillType.GOATMILK] = true,
        [FillType.HONEY] = true
    }

    local validPlaceableTypes = {
        sheepHusbandry = true,
        chickenHusbandry = true,
        beehivePalletSpawner = true
    }

    local targetPlaceableName = ""

    for _, placeable in ipairs(g_currentMission.placeableSystem.placeables) do
        if placeable:getOwnerFarmId() == playerFarmId then
            log(string.format("LogicCenter: Verificando placeable '%s' do tipo '%s'.", placeable:getName() or "Desconhecido", placeable.typeName))

            local validFillTypes = {}

            -- Se for um ponto de produção
            if placeable.spec_productionPoint then
                local productionPoint = placeable.spec_productionPoint.productionPoint
                if productionPoint and productionPoint.outputFillTypeIds then
                    for fillType, _ in pairs(productionPoint.outputFillTypeIds) do
                        table.insert(validFillTypes, fillType)
                    end
                end
                targetPlaceableName = "LOGI CENTER"
                log("LogicCenter: Placeable identificado como ponto de produção. ValidFillTypes carregados.")

            -- Se for um husbandry ou spawner válido
            elseif validPlaceableTypes[placeable.typeName] then
                validFillTypes = validStaticFillTypes
                targetPlaceableName = "LOGI TRANSFER"
                log("LogicCenter: Placeable identificado como husbandry ou spawner. Usando validStaticFillTypes.")

            -- Caso não se encaixe em nenhuma categoria
            else
                log("LogicCenter: Tipo de placeable não suportado. Pulando...")
                targetPlaceableName = ""
            end

            -- Verifica ClearAreas apenas se targetPlaceableName não estiver vazio
            if targetPlaceableName ~= "" and placeable.spec_clearAreas then
                for i, clearArea in ipairs(placeable.spec_clearAreas.areas) do
                    local startX, startY, startZ = getWorldTranslation(clearArea.start)
                    local widthX, widthY, widthZ = getWorldTranslation(clearArea.width)
                    local heightX, heightY, heightZ = getWorldTranslation(clearArea.height)

                    -- Calcula o quarto ponto
                    local fourthX = widthX + (heightX - startX)
                    local fourthY = math.max(startY, widthY, heightY) + 3
                    local fourthZ = widthZ + (heightZ - startZ)

                    -- Calcula o centro da área
                    local centerX = (startX + widthX + heightX + fourthX) / 4
                    local centerY = (startY + widthY + heightY + fourthY) / 4
                    local centerZ = (startZ + widthZ + heightZ + fourthZ) / 4

                    local sizeX = math.sqrt((widthX - startX)^2 + (widthZ - startZ)^2)
                    local sizeZ = math.sqrt((heightX - startX)^2 + (heightZ - startZ)^2)
                    local sizeY = 3
                    local rotationY = math.atan2(widthZ - startZ, widthX - startX)

                    self.currentValidFillTypes = validFillTypes
                    self:checkPalletsInArea(centerX, centerY, centerZ, sizeX, sizeY, sizeZ, rotationY)

                    local targetPlaceable = self:findPlaceableByName(targetPlaceableName)
                    if targetPlaceable ~= nil then
                        if targetPlaceableName == "LOGI CENTER" then
                            self:moveValidPalletsToNode(targetPlaceable)
                        elseif targetPlaceableName == "LOGI TRANSFER" then
                            self:moveValidPalletsToTransfer(targetPlaceable)
                        end
                        self.detectedPallets = {} -- Limpa os paletes detectados após o movimento
                        self.currentValidFillTypes = {}
                    end
                end
            else
                log("LogicCenter: Placeable não possui áreas ClearAreas ou não é um tipo válido. Pulando...")
            end
        end
    end

    log("LogicCenter: Verificação de paletes concluída.")
end

-- verifica paletes na area
function LogicCenter:checkPalletsInArea(x, y, z, width, height, depth, rotationY)
    overlapBox(
        x, y, z,
        0, rotationY, 0,
        width / 2, height / 2, depth / 2,
        "onFindPalletCallback", self,
        CollisionFlag.VEHICLE + CollisionFlag.DYNAMIC_OBJECT
    )
end


-- Função de atualização chamada automaticamente pelo sistema
function LogicCenter:update(dt)
    self.timer = self.timer + dt

    if self.timer >= self.interval then
        self.timer = 0 -- Reseta o timer

        local placeable = self:findPlaceableByName("LOGI CENTER")
        local placeable2 = self:findPlaceableByName("LOGI TRANSFER")

          if placeable ~= nil or placeable2 ~= nil then
            log("LogicCenter: LOGI CENTER / TRANSFER detectado! Iniciando verificação de paletes...")
            self:checkAndDrawClearAreas()
        else
            log("LogicCenter: LOGI CENTER não encontrado. Aguardando próxima verificação...")
        end
    end
end

-- Adiciona ao evento onStartMission
Mission00.onStartMission = Utils.appendedFunction(Mission00.onStartMission, function()
    log("LogicCenter: Inicializando...")
    LogicCenter:new()

    if LogicCenter.instance ~= nil then
        g_currentMission:addUpdateable(LogicCenter.instance)
        log("LogicCenter: Registrado para verificação periódica.")
    end
end)