Для документации этого модуля может быть создана страница Модуль:Песочница/Pok/doc

local p = {}

---------------------------------------------------------------------
-- Загрузка данных 
---------------------------------------------------------------------
-- Данные для модуля, работающего с содержимым/контейнерами
local itemData          = mw.loadData("Модуль:IanComradeBot/prototypes/fills/Item.json/data")
local tableData         = mw.loadData("Модуль:IanComradeBot/prototypes/table.json/data")
local itemSlotsData     = mw.loadData("Модуль:IanComradeBot/prototypes/ItemSlots.json/data")
local itemStackData     = mw.loadData("Модуль:IanComradeBot/prototypes/fills/stack.json/data")
local chemData          = mw.loadData("Модуль:IanComradeBot/prototypes/fills/chem.json/data")
local chemTranslateData = mw.loadData("Модуль:IanComradeBot/chem prototypes.json/data")

-- Данные для модуля экипировки/должностей
local jobData           = mw.loadData("Модуль:IanComradeBot/job.json/data")
local gearData          = mw.loadData("Модуль:IanComradeBot/startingGear.json/data")
local gearRoleLoadout   = mw.loadData("Модуль:IanComradeBot/roleLoadout.json/data")
local gearloadout       = mw.loadData("Модуль:IanComradeBot/loadout.json/data")
local gearloadoutGroup  = mw.loadData("Модуль:IanComradeBot/loadoutGroup.json/data")

-- Данные для модуля грузов
local cargoData         = mw.loadData("Модуль:IanComradeBot/prototypes/сargo.json/base")

-- Данные для модуля станков (lathe)
local latheData         = mw.loadData("Модуль:IanComradeBot/prototypes/lathe.json/data")
local recipeData        = mw.loadData("Модуль:IanComradeBot/prototypes/lathe/recipes.json/data")
local researchData      = mw.loadData("Модуль:IanComradeBot/prototypes/research.json/data")
local materialData      = mw.loadData("Модуль:IanComradeBot/prototypes/materials.json/data")
local latheChemData     = mw.loadData("Модуль:IanComradeBot/chem prototypes.json/data")

local function reverseFindStorageByItem(itemId, visited)
    visited = visited or {}
    if visited[itemId] then return "" end
    visited[itemId] = true

    local result = {}

    local function searchInEntry(entry)
        if type(entry) == "table" then
            if entry.id == itemId then
                return true
            end
            for _, v in pairs(entry) do
                if type(v) == "table" then
                    if searchInEntry(v) then
                        return true
                    end
                end
            end
        end
        return false
    end

    for tblId, tblEntry in pairs(tableData) do
        if searchInEntry(tblEntry) then
            for storageId, storage in pairs(itemData) do
                if storage.StorageFill and storage.StorageFill.tableId == tblId then
                    table.insert(result, storageId)
                elseif storage.EntityTableContainerFill and storage.EntityTableContainerFill.containers then
                    local cont = storage.EntityTableContainerFill.containers
                    if (cont.entity_storage and cont.entity_storage.tableId == tblId) or
                       (cont.storagebase and cont.storagebase.tableId == tblId) then
                        table.insert(result, storageId)
                    end
                end
            end
        end
    end

    return #result > 0 and table.concat(result, ", ") or ""
end

local function reverseFindJobByItem(itemId)
    local result = {}

    for gearId, gear in pairs(gearData) do
        if gear.equipment then
            for slot, equipId in pairs(gear.equipment) do
                if equipId == itemId then
                    table.insert(result, gearId)
                end
            end
        end
    end

    for roleId, role in pairs(gearRoleLoadout) do
        if role.groups then
            for _, groupId in ipairs(role.groups) do
                local groupData = gearloadoutGroup[groupId]
                if groupData and groupData.loadouts then
                    for _, loadoutId in ipairs(groupData.loadouts) do
                        local loadout = gearloadout[loadoutId]
                        if loadout and loadout.equipment then
                            for slot, equipId in pairs(loadout.equipment) do
                                if equipId == itemId then
                                    table.insert(result, roleId)
                                end
                            end
                        end
                    end
                end
            end
        end
    end

    return #result > 0 and table.concat(result, ", ") or ""
end

local function reverseCargoLookup(field, value)
    for _, entry in ipairs(cargoData) do
        if entry[field] and tostring(entry[field]) == tostring(value) then
            return entry.id
        end
    end
    return nil
end

local function reverseFindLatheByProduct(product)
    for _, lathe in ipairs(latheData) do
        local found = false
        if lathe.Lathe then
            if lathe.Lathe.staticRecipes then
                for _, recipeId in ipairs(lathe.Lathe.staticRecipes) do
                    for _, recipe in ipairs(recipeData) do
                        if recipe.id == recipeId and recipe.result == product then
                            return lathe.id
                        end
                    end
                end
            end
            if lathe.Lathe.dynamicRecipes then
                for _, recipeId in ipairs(lathe.Lathe.dynamicRecipes) do
                    for _, recipe in ipairs(recipeData) do
                        if recipe.id == recipeId and recipe.result == product then
                            return lathe.id
                        end
                    end
                end
            end
        end
        if lathe.EmagLatheRecipes then
            if lathe.EmagLatheRecipes.emagStaticRecipes then
                for _, recipeId in ipairs(lathe.EmagLatheRecipes.emagStaticRecipes) do
                    for _, recipe in ipairs(recipeData) do
                        if recipe.id == recipeId and recipe.result == product then
                            return lathe.id
                        end
                    end
                end
            end
            if lathe.EmagLatheRecipes.emagDynamicRecipes then
                for _, recipeId in ipairs(lathe.EmagLatheRecipes.emagDynamicRecipes) do
                    for _, recipe in ipairs(recipeData) do
                        if recipe.id == recipeId and recipe.result == product then
                            return lathe.id
                        end
                    end
                end
            end
        end
    end
    return nil
end

function p.main(frame)
    local mode = mw.text.trim(frame.args[1] or "")
    local param = mw.text.trim(frame.args[2] or "")
    
    if mode == "" or param == "" then
        return "Ошибка: не указаны необходимые параметры для обратного поиска."
    end

    if mode == "reverseStorage" then
        local storageResult = reverseFindStorageByItem(param)
        if storageResult ~= "" then
            return "Найденные хранилища (itemData), ссылающиеся на таблицу, содержащую предмет " .. param .. ": " .. storageResult
        else
            return "Хранилище не найдено для предмета " .. param
        end
    elseif mode == "reverseJob" then
        local jobResult = reverseFindJobByItem(param)
        if jobResult ~= "" then
            return "Найденные роли/экипировки, использующие предмет " .. param .. ": " .. jobResult
        else
            return "Нет данных для предмета " .. param
        end
    elseif mode == "reverseCargo" then
        -- Здесь предполагается, что param – значение поля product.
        local cargoId = reverseCargoLookup("product", param)
        if cargoId then
            return "Найден груз с ID: " .. cargoId
        else
            return "Груз не найден по значению " .. param
        end
    elseif mode == "reverseLathe" then
        local latheId = reverseFindLatheByProduct(param)
        if latheId then
            return "Найден станок (lathe) с ID: " .. latheId
        else
            return "Станок не найден для продукта " .. param
        end
    else
        return "Ошибка: неизвестный режим обратного поиска: " .. mode
    end
end

return p