Module:Building data: Difference between revisions

From Beyond These Stars Official Wiki
Updated with category filtering method in the public interface
m luadoc update only
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
--[[
--[[
Test in Scribunto console with:
Test in Scribunto console with:
=mw.dumpObject(p.get_all_buildings())
=mw.dumpObject(p.get_building("Ore Smelter"))
=mw.dumpObject(p.get_building("Ore Smelter"))
=mw.dumpObject(p.get_name_by_id("OreSmelter"))
=mw.dumpObject(p.get_name_by_id("OreSmelter"))
=mw.dumpObject(p.get_buildings_by_category("Construction"))
=mw.dumpObject(p.get_buildings_by_category("Construction"))
=mw.dumpObject(p.get_building_names_with_tasks_including_resource("Iron"))
]]--
]]--
local p = {}
local p = {}
Line 289: Line 291:
--- Cargo row from querying BuildingTasks; all values are strings at runtime.
--- Cargo row from querying BuildingTasks; all values are strings at runtime.
---@class CargoBuildingTasksRecord
---@class CargoBuildingTasksRecord
---@field page_name string|nil
---@field guid string|nil
---@field BuildingTasks_1_Name string|nil
---@field BuildingTasks_1_Name string|nil
---@field BuildingTasks_1_InitialState string|nil
---@field BuildingTasks_1_InitialState string|nil
Line 434: Line 438:
     WHERE_NAME = "page_name",
     WHERE_NAME = "page_name",
     WHERE_ID = "Name",
     WHERE_ID = "Name",
    WHERE_TASKS_GUID = "BuildingTasks",
     ORDER_BY = "page_name",
     ORDER_BY = "page_name",
     FIELDS_NAME_ONLY = {
     FIELDS_NAME_ONLY = {
Line 718: Line 723:
     -- Commented out fields are not used in BuildingTask
     -- Commented out fields are not used in BuildingTask
     FIELDS = {
     FIELDS = {
      "page_name",
      "guid",
       "BuildingTasks_1_Name",
       "BuildingTasks_1_Name",
       -- "BuildingTasks_1_InitialState",
       -- "BuildingTasks_1_InitialState",
Line 863: Line 870:
   local new_results = {}
   local new_results = {}
   for _, record in ipairs(results) do
   for _, record in ipairs(results) do
     if not p.SKIPPED_BUILDINGS_NAMES[record.page_name] then
     if not p.SKIPPED_BUILDINGS_NAMES[record.Name] then
       table.insert(new_results, record)
       table.insert(new_results, record)
     end
     end
Line 899: Line 906:
     {
     {
       where = filter_field .. '="' .. filter_value .. '"',
       where = filter_field .. '="' .. filter_value .. '"',
      orderBy = QUERIES.BUILDINGS.ORDER_BY,
     })
     })
   if not result or #result == 0 then return {} end
   if not result or #result == 0 then return {} end
Line 933: Line 941:
     {
     {
       where = QUERIES.BUILDINGS.WHERE_ID .. '="' .. building_id .. '"',
       where = QUERIES.BUILDINGS.WHERE_ID .. '="' .. building_id .. '"',
    })
  if not result or #result == 0 then return nil end
  result = skip_unwanted_buildings(result)
  return result[1]
end
--- Queries cargo for the building name only with the given guid.
---@param tasks_guid string the guid of the tasks list to look for in buildings
---@return CargoBuildingRecord|nil
local function query_building_name_only_by_tasks_guid(tasks_guid)
  local cargo = mw.ext.cargo
  if not cargo then return nil end
  local result = cargo.query(
    QUERIES.BUILDINGS.TABLE,
    table.concat(QUERIES.BUILDINGS.FIELDS_NAME_ONLY, ","),
    {
      where = QUERIES.BUILDINGS.WHERE_TASKS_GUID .. '="' .. tasks_guid .. '"',
     })
     })
   if not result or #result == 0 then return nil end
   if not result or #result == 0 then return nil end
Line 943: Line 968:




--#region MARK: Query building tasks
--#region MARK: Query tasks


--- Queries cargo for the building tasks record with the given guid.
--- Queries cargo for the building tasks record with the given guid.
Line 959: Line 984:
   if not result or #result == 0 then return nil end
   if not result or #result == 0 then return nil end
   return result[1]
   return result[1]
end
--- Queries cargo for all building tasks.
---@return CargoBuildingTasksRecord[]
local function query_all_building_tasks()
  local cargo = mw.ext.cargo
  if not cargo then return {} end
  local result = cargo.query(
    QUERIES.TASKS.TABLE,
    table.concat(QUERIES.TASKS.FIELDS, ",")
  )
  if not result or #result == 0 then return {} end
  return result
end
end


Line 965: Line 1,003:




--#region MARK: Local helpers
--#region MARK: Restructuring


--- Restructures the construction resources of a building record from the database into a more usable format.
--- Restructures the construction resources of a building record from the database into a more usable format.
Line 1,026: Line 1,064:


--- Restructures the inputs or ouputs of a building task
--- Restructures the inputs or ouputs of a building task
---@param record CargoBuildingTasksRecord the building tasks record retrieved for the building
---@param task_record CargoBuildingTasksRecord the building tasks record retrieved for the building
---@param task_num number which task to restructure
---@param task_num number which task to restructure
---@param which_io "Inputs"|"Outputs" the type of tasks to restructure
---@param which_io "Inputs"|"Outputs" the type of tasks to restructure
---@return BuildingTaskIO[]
---@return BuildingTaskIO[]
local function restructure_task_io(record, task_num, which_io)
local function restructure_task_io(task_record, task_num, which_io)
   local task_io = {}
   local task_io = {}
   local max = ((which_io == "Inputs") and p.MAX_BUILDING_TASK_INPUTS) or p.MAX_BUILDING_TASK_OUTPUTS
   local max = ((which_io == "Inputs") and p.MAX_BUILDING_TASK_INPUTS) or p.MAX_BUILDING_TASK_OUTPUTS
   local task_type_prefix = "BuildingTasks_" .. task_num .. "_" .. which_io .. "_%d_"
   local task_type_prefix = "BuildingTasks_" .. task_num .. "_" .. which_io .. "_%d_"
   for i = 1, max do
   for i = 1, max do
     local put_type = record[string.format(task_type_prefix .. "Type", i)]
     local put_type = task_record[string.format(task_type_prefix .. "Type", i)]
     local put_resource = record[string.format(task_type_prefix .. "Resource", i)]
     local put_resource = task_record[string.format(task_type_prefix .. "Resource", i)]
     local put_value = record[string.format(task_type_prefix .. "Value", i)]
     local put_value = task_record[string.format(task_type_prefix .. "Value", i)]
     if put_type or put_resource or put_value then
     if put_type or put_resource or put_value then
       table.insert(task_io, {
       table.insert(task_io, {
Line 1,049: Line 1,087:
end
end


--- Restructures the tasks of a building record from the database into a more usable format.
--- Restructures a task record from the database into a more usable format.
---@param record CargoBuildingRecord
---@param task_record CargoBuildingTasksRecord
---@return BuildingTask[]
---@return BuildingTask[]
local function restructure_tasks(record)
local function restructure_tasks(task_record)
  local tasks_guid = record.BuildingTasks
  if not tasks_guid then return {} end
  local raw_tasks = query_building_tasks(tasks_guid)
  if not raw_tasks then return {}
  end
   local tasks = {}
   local tasks = {}
   for i = 1, p.MAX_BUILDING_TASKS do
   for i = 1, p.MAX_BUILDING_TASKS do
     local task_name = raw_tasks[string.format("BuildingTasks_%d_Name", i)]
     local task_name = task_record[string.format("BuildingTasks_%d_Name", i)]
     local time = tonumber(raw_tasks[string.format("BuildingTasks_%d_Time", i)])
     local time = tonumber(task_record[string.format("BuildingTasks_%d_Time", i)])
     local pollution_slowdown = tonumber(raw_tasks[string.format("BuildingTasks_%d_PollutionSlowdownThreshold", i)])
     local pollution_slowdown = tonumber(task_record[string.format("BuildingTasks_%d_PollutionSlowdownThreshold", i)])
     local outputs = restructure_task_io(raw_tasks, i, "Outputs")
     local outputs = restructure_task_io(task_record, i, "Outputs")
     local inputs = restructure_task_io(raw_tasks, i, "Inputs")
     local inputs = restructure_task_io(task_record, i, "Inputs")
     if task_name then
     if task_name then
       table.insert(tasks, {
       table.insert(tasks, {
Line 1,075: Line 1,108:
     end
     end
   end
   end
  return tasks
end
--- Restructures the tasks of a building record from the database into a more usable format.
---@param building_record CargoBuildingRecord
---@return BuildingTask[]
local function restructure_tasks_in_building(building_record)
  local tasks_guid = building_record.BuildingTasks
  if not tasks_guid then return {} end
  local raw_tasks = query_building_tasks(tasks_guid)
  if not raw_tasks then return {}
  end
  local tasks = restructure_tasks(raw_tasks)
   return tasks
   return tasks
end
end
Line 1,122: Line 1,168:
   building.unlock_values = restructure_unlock_values(record)
   building.unlock_values = restructure_unlock_values(record)
   building.adjacency_bonuses = restructure_adjacency_bonuses(record)
   building.adjacency_bonuses = restructure_adjacency_bonuses(record)
   building.tasks = restructure_tasks(record)
   building.tasks = restructure_tasks_in_building(record)
   return building
   return building
end
--#endregion
--#region MARK: Private helpers
--- Maps the given tasks by the given building guiid.
---@param list_of_tasks_records CargoBuildingTasksRecord[]
---@return table<string, CargoBuildingTasksRecord>
local function map_tasks_by_guid(list_of_tasks_records)
  local map = {}
  for _, tasks_record in ipairs(list_of_tasks_records) do
    local tasks_guid = tasks_record.guid
    if tasks_guid and tasks_guid ~= "" then
      map[tasks_guid] = tasks_record
    end
  end
  return map
end
--- Filters the given tasks by the given resource id.
---@param tasks BuildingTask[]
---@param resource_id string the id of the resource to filter tasks by
---@return BuildingTask[]
local function filter_tasks_by_resource(tasks, resource_id)
  local filtered_tasks = {}
  for _, task in ipairs(tasks) do
    local found = false
    for _, input in ipairs(task.inputs) do
      if input.resource == resource_id then
        table.insert(filtered_tasks, task)
        found = true
        break
      end
    end
    if not found then
      for _, output in ipairs(task.outputs) do
        if output.resource == resource_id then
          table.insert(filtered_tasks, task)
          break
        end
      end
    end
  end
  return filtered_tasks
end
end


Line 1,139: Line 1,232:
---@field MAX_BUILDING_TASK_OUTPUTS number the maximum number of building task outputs
---@field MAX_BUILDING_TASK_OUTPUTS number the maximum number of building task outputs
---@field MAX_BUILDING_TASK_INPUTS number the maximum number of building task inputs
---@field MAX_BUILDING_TASK_INPUTS number the maximum number of building task inputs
---@field FILTERS table filter field names for building queries
---@field get_name_by_id fun(id: string): string|nil looks up a building page name by codename
---@field get_building fun(building_name: string): Building|nil looks up a building by page name
---@field get_buildings_by_category fun(category: string): Building[] gets buildings in a category
---@field get_all_buildings fun(): Building[] gets all buildings
---@field get_all_buildings fun(): Building[] gets all buildings
---@field get_building fun(building_name: string): Building|nil looks up a building by name
---@field get_building_names_with_tasks_including_resource fun(resource_id: string): table<string, BuildingTask[]> building page names to matching tasks


p.MAX_CONSTRUCTION_PAIRS = 6
p.MAX_CONSTRUCTION_PAIRS = 6
Line 1,150: Line 1,247:
p.BUILDING_PORTRAIT_PREFIX = "BuildingPortrait_"
p.BUILDING_PORTRAIT_PREFIX = "BuildingPortrait_"
p.PORTRAITS_MISSING_NAMES = {
p.PORTRAITS_MISSING_NAMES = {
  ["CompostTool"] = true,
   ["CompostingSite"] = true,
   ["CompostingSite"] = true,
   ["Forest_WorldTwo"] = true,
   ["Forest_WorldTwo"] = true,
Line 1,165: Line 1,261:
}
}
p.SKIPPED_BUILDINGS_NAMES = {
p.SKIPPED_BUILDINGS_NAMES = {
  ["CompostTool"] = true,
   ["ConstructionConsumption"] = true,
   ["ConstructionConsumption"] = true,
   ["DemolitionControl"] = true,
   ["DemolitionControl"] = true,
Line 1,182: Line 1,279:
   ["SettlementSpaceshipReload"] = true,
   ["SettlementSpaceshipReload"] = true,
   ["ThornyStems"] = true,
   ["ThornyStems"] = true,
}
p.FILTERS = {
  CATEGORY = FILTER_CATEGORY,
}
}


Line 1,264: Line 1,364:
---@return Building[]
---@return Building[]
function p.get_buildings_by_category(category)
function p.get_buildings_by_category(category)
   local raw_records = query_buildings_by_filter(FILTER_CATEGORY, category)
   local raw_records = query_buildings_by_filter(p.FILTERS.CATEGORY, category)
   if not raw_records then return {} end
   if not raw_records then return {} end
   local new_records = {}
   local new_records = {}
Line 1,285: Line 1,385:
   end
   end
   return new_records
   return new_records
end
--- Fetches all buildings whose work involves the given resource.
---@param resource_id string the id of the resource to fetch buildings for
---@return table<string, BuildingTask[]>
function p.get_building_names_with_tasks_including_resource(resource_id)
  local raw_records = query_all_building_tasks()
  local raw_map_of_tasks = map_tasks_by_guid(raw_records)
  ---@type table<string, BuildingTask[]>
  local map_building_map_of_tasks = {}
  for tasks_guid, tasks_record in pairs(raw_map_of_tasks) do
    local tasks = restructure_tasks(tasks_record)
    local filtered_tasks = filter_tasks_by_resource(tasks, resource_id)
    if filtered_tasks and #filtered_tasks > 0 then
      local building_record = query_building_name_only_by_tasks_guid(tasks_guid)
      if building_record then
        local building_name = building_record.page_name
        if building_name and building_name ~= "" then
          map_building_map_of_tasks[building_name] = filtered_tasks
        end
      end
    end
  end
  return map_building_map_of_tasks
end
end



Latest revision as of 03:33, 10 October 2026

Documentation for this module may be created at Module:Building data/doc

--[[
Test in Scribunto console with:
=mw.dumpObject(p.get_all_buildings())
=mw.dumpObject(p.get_building("Ore Smelter"))
=mw.dumpObject(p.get_name_by_id("OreSmelter"))
=mw.dumpObject(p.get_buildings_by_category("Construction"))
=mw.dumpObject(p.get_building_names_with_tasks_including_resource("Iron"))
]]--
local p = {}



--#region MARK: Cargo types

--- Cargo row from querying Buildings; all values are strings at runtime.
---@class CargoBuildingRecord
---@field page_name string|nil
---@field guid string|nil
---@field Name string|nil
---@field Category string|nil
---@field DisplayNameTerm_en string|nil
---@field DisplayNamePluralTerm_en string|nil
---@field DescriptionTerm_en string|nil
---@field UpgradeTerm string|nil
---@field UpgradeTerm_en string|nil
---@field IconAddress string|nil
---@field PlacementRules_1 string|nil
---@field PlacementRules_2 string|nil
---@field PlacementRules_3 string|nil
---@field PlacementRules_4 string|nil
---@field PlacementRules_5 string|nil
---@field PlacementRules_6 string|nil
---@field AnchorBuildingNames_1 string|nil
---@field AnchorBuildingNames_2 string|nil
---@field ConstructionResources string|nil
---@field ConstructionResources_1_Name string|nil
---@field ConstructionResources_1_Amount string|nil
---@field ConstructionResources_2_Name string|nil
---@field ConstructionResources_2_Amount string|nil
---@field ConstructionResources_3_Name string|nil
---@field ConstructionResources_3_Amount string|nil
---@field ConstructionResources_4_Name string|nil
---@field ConstructionResources_4_Amount string|nil
---@field ConstructionResources_5_Name string|nil
---@field ConstructionResources_5_Amount string|nil
---@field ConstructionResources_6_Name string|nil
---@field ConstructionResources_6_Amount string|nil
---@field SecondaryPrefabAddresses_1 string|nil
---@field SecondaryPrefabAddresses_2 string|nil
---@field RepairResources_1_Name string|nil
---@field RepairResources_1_Amount string|nil
---@field RepairResources_2_Name string|nil
---@field RepairResources_2_Amount string|nil
---@field RepairResources_3_Name string|nil
---@field RepairResources_3_Amount string|nil
---@field RepairResources_4_Name string|nil
---@field RepairResources_4_Amount string|nil
---@field RepairResources_5_Name string|nil
---@field RepairResources_5_Amount string|nil
---@field RepairResources_6_Name string|nil
---@field RepairResources_6_Amount string|nil
---@field ConstructionTime string|nil
---@field ConstructionPeepCount string|nil
---@field UnlockMode string|nil
---@field UnlockValues string|nil
---@field UnlockValues_1 string|nil
---@field UnlockValues_2 string|nil
---@field UnlockValues_3 string|nil
---@field UnlockValues_4 string|nil
---@field RequiredRecords_1 string|nil
---@field UpgradePointsEarned string|nil
---@field LockedInDemo string|nil
---@field FootprintIconAddress string|nil
---@field TechTreeDisplay string|nil
---@field TechTreePrevious string|nil
---@field TechTreeRow string|nil
---@field AdjacencyBonuses string|nil
---@field AdjacencyBonuses_1_GroupName string|nil
---@field AdjacencyBonuses_1_Evaluator string|nil
---@field AdjacencyBonuses_1_EvaluatorThreshold string|nil
---@field AdjacencyBonuses_1_Action string|nil
---@field AdjacencyBonuses_1_ActionNames string|nil
---@field AdjacencyBonuses_1_ActionNames_1 string|nil
---@field AdjacencyBonuses_1_ActionNames_2 string|nil
---@field AdjacencyBonuses_1_ActionNames_3 string|nil
---@field AdjacencyBonuses_1_ActionNames_4 string|nil
---@field AdjacencyBonuses_1_ActionNames_5 string|nil
---@field AdjacencyBonuses_1_EvaluatorValue string|nil
---@field AdjacencyBonuses_1_ActionValue string|nil
---@field AdjacencyBonuses_2_GroupName string|nil
---@field AdjacencyBonuses_2_Evaluator string|nil
---@field AdjacencyBonuses_2_EvaluatorThreshold string|nil
---@field AdjacencyBonuses_2_Action string|nil
---@field AdjacencyBonuses_2_ActionNames string|nil
---@field AdjacencyBonuses_2_ActionNames_1 string|nil
---@field AdjacencyBonuses_2_ActionNames_2 string|nil
---@field AdjacencyBonuses_2_ActionNames_3 string|nil
---@field AdjacencyBonuses_2_ActionNames_4 string|nil
---@field AdjacencyBonuses_2_ActionNames_5 string|nil
---@field AdjacencyBonuses_2_EvaluatorValue string|nil
---@field AdjacencyBonuses_2_ActionValue string|nil
---@field AdjacencyBonuses_3_GroupName string|nil
---@field AdjacencyBonuses_3_Evaluator string|nil
---@field AdjacencyBonuses_3_EvaluatorThreshold string|nil
---@field AdjacencyBonuses_3_Action string|nil
---@field AdjacencyBonuses_3_ActionNames string|nil
---@field AdjacencyBonuses_3_ActionNames_1 string|nil
---@field AdjacencyBonuses_3_ActionNames_2 string|nil
---@field AdjacencyBonuses_3_ActionNames_3 string|nil
---@field AdjacencyBonuses_3_ActionNames_4 string|nil
---@field AdjacencyBonuses_3_EvaluatorValue string|nil
---@field AdjacencyBonuses_3_ActionValue string|nil
---@field AdjacencyBonuses_4_GroupName string|nil
---@field AdjacencyBonuses_4_Evaluator string|nil
---@field AdjacencyBonuses_4_EvaluatorThreshold string|nil
---@field AdjacencyBonuses_4_Action string|nil
---@field AdjacencyBonuses_4_ActionNames string|nil
---@field AdjacencyBonuses_4_EvaluatorValue string|nil
---@field AdjacencyBonuses_4_ActionValue string|nil
---@field OperationRules string|nil
---@field OperationRules_1 string|nil
---@field OperationRules_2 string|nil
---@field OperationRules_3 string|nil
---@field OperationRules_4 string|nil
---@field OperationRules_5 string|nil
---@field OperationRules_6 string|nil
---@field OperationRules_7 string|nil
---@field OperationRules_8 string|nil
---@field OperationRules_9 string|nil
---@field OperationRules_10 string|nil
---@field OperationRules_11 string|nil
---@field OperationRules_12 string|nil
---@field OperationRules_13 string|nil
---@field MaxPeeps string|nil
---@field PeepExhaustionRemoved string|nil
---@field PeepAgeAdded string|nil
---@field PeepHappinessAdded string|nil
---@field PeepHappinessCost string|nil
---@field PollutionOutputMode string|nil
---@field SourceOfOxygenRange string|nil
---@field Resources string|nil
---@field Resources_1_Name string|nil
---@field Resources_1_Maximum string|nil
---@field Resources_1_StorageMode string|nil
---@field Resources_1_StartFull string|nil
---@field Resources_1_FetchInRange string|nil
---@field Resources_1_CanBeShared string|nil
---@field Resources_1_CycleThoughResourceSources string|nil
---@field Resources_1_GatheringMode string|nil
---@field Resources_1_DistributionMode string|nil
---@field Resources_1_DeliverInRange string|nil
---@field Resources_1_VehicleFetchsAndDelivers string|nil
---@field Resources_2_Name string|nil
---@field Resources_2_Maximum string|nil
---@field Resources_2_StorageMode string|nil
---@field Resources_2_StartFull string|nil
---@field Resources_2_FetchInRange string|nil
---@field Resources_2_CanBeShared string|nil
---@field Resources_2_CycleThoughResourceSources string|nil
---@field Resources_2_GatheringMode string|nil
---@field Resources_2_DistributionMode string|nil
---@field Resources_2_DeliverInRange string|nil
---@field Resources_2_VehicleFetchsAndDelivers string|nil
---@field Resources_3_Name string|nil
---@field Resources_3_Maximum string|nil
---@field Resources_3_StorageMode string|nil
---@field Resources_3_StartFull string|nil
---@field Resources_3_FetchInRange string|nil
---@field Resources_3_CanBeShared string|nil
---@field Resources_3_CycleThoughResourceSources string|nil
---@field Resources_3_GatheringMode string|nil
---@field Resources_3_DistributionMode string|nil
---@field Resources_3_DeliverInRange string|nil
---@field Resources_3_VehicleFetchsAndDelivers string|nil
---@field Resources_4_Name string|nil
---@field Resources_4_Maximum string|nil
---@field Resources_4_StorageMode string|nil
---@field Resources_4_StartFull string|nil
---@field Resources_4_FetchInRange string|nil
---@field Resources_4_CanBeShared string|nil
---@field Resources_4_CycleThoughResourceSources string|nil
---@field Resources_4_GatheringMode string|nil
---@field Resources_4_DistributionMode string|nil
---@field Resources_4_DeliverInRange string|nil
---@field Resources_4_VehicleFetchsAndDelivers string|nil
---@field Resources_5_Name string|nil
---@field Resources_5_Maximum string|nil
---@field Resources_5_StorageMode string|nil
---@field Resources_5_StartFull string|nil
---@field Resources_5_FetchInRange string|nil
---@field Resources_5_CanBeShared string|nil
---@field Resources_5_CycleThoughResourceSources string|nil
---@field Resources_5_GatheringMode string|nil
---@field Resources_5_DistributionMode string|nil
---@field Resources_5_DeliverInRange string|nil
---@field Resources_5_VehicleFetchsAndDelivers string|nil
---@field Resources_6_Name string|nil
---@field Resources_6_Maximum string|nil
---@field Resources_6_StorageMode string|nil
---@field Resources_6_StartFull string|nil
---@field Resources_6_FetchInRange string|nil
---@field Resources_6_CanBeShared string|nil
---@field Resources_6_CycleThoughResourceSources string|nil
---@field Resources_6_GatheringMode string|nil
---@field Resources_6_DistributionMode string|nil
---@field Resources_6_DeliverInRange string|nil
---@field Resources_6_VehicleFetchsAndDelivers string|nil
---@field Resources_7_Name string|nil
---@field Resources_7_Maximum string|nil
---@field Resources_7_StorageMode string|nil
---@field Resources_7_StartFull string|nil
---@field Resources_7_FetchInRange string|nil
---@field Resources_7_CanBeShared string|nil
---@field Resources_7_CycleThoughResourceSources string|nil
---@field Resources_7_GatheringMode string|nil
---@field Resources_7_DistributionMode string|nil
---@field Resources_7_DeliverInRange string|nil
---@field Resources_7_VehicleFetchsAndDelivers string|nil
---@field Resources_8_Name string|nil
---@field Resources_8_Maximum string|nil
---@field Resources_8_StorageMode string|nil
---@field Resources_8_StartFull string|nil
---@field Resources_8_FetchInRange string|nil
---@field Resources_8_CanBeShared string|nil
---@field Resources_8_CycleThoughResourceSources string|nil
---@field Resources_8_GatheringMode string|nil
---@field Resources_8_DistributionMode string|nil
---@field Resources_8_DeliverInRange string|nil
---@field Resources_8_VehicleFetchsAndDelivers string|nil
---@field Resources_9_Name string|nil
---@field Resources_9_Maximum string|nil
---@field Resources_9_StorageMode string|nil
---@field Resources_9_StartFull string|nil
---@field Resources_9_FetchInRange string|nil
---@field Resources_9_CanBeShared string|nil
---@field Resources_9_CycleThoughResourceSources string|nil
---@field Resources_9_GatheringMode string|nil
---@field Resources_9_DistributionMode string|nil
---@field Resources_9_DeliverInRange string|nil
---@field Resources_9_VehicleFetchsAndDelivers string|nil
---@field ResourceGroups string|nil
---@field ResourceGroups_1_Type string|nil
---@field ResourceGroups_1_Maximum string|nil
---@field ResourceGroups_1_GatheringMode string|nil
---@field ResourceGroups_1_DistributionMode string|nil
---@field ResourceGroups_1_StartFullResource string|nil
---@field ResourceGroups_2_Type string|nil
---@field ResourceGroups_2_Maximum string|nil
---@field ResourceGroups_2_GatheringMode string|nil
---@field ResourceGroups_2_DistributionMode string|nil
---@field ResourceGroups_2_StartFullResource string|nil
---@field DefinedResourceLists string|nil
---@field DefinedResourceLists_2_Name string|nil
---@field DefinedResourceLists_2_Maximum string|nil
---@field DefinedResourceLists_2_StorageMode string|nil
---@field DefinedResourceLists_2_StartFull string|nil
---@field DefinedResourceLists_2_FetchInRange string|nil
---@field DefinedResourceLists_2_CanBeShared string|nil
---@field DefinedResourceLists_2_CycleThoughResourceSources string|nil
---@field DefinedResourceLists_2_GatheringMode string|nil
---@field DefinedResourceLists_2_DistributionMode string|nil
---@field DefinedResourceLists_2_DeliverInRange string|nil
---@field DefinedResourceLists_2_VehicleFetchsAndDelivers string|nil
---@field DefaultFetchMode string|nil
---@field DefaultDeliveryMode string|nil
---@field FetchTime string|nil
---@field DeliveryTime string|nil
---@field TotalStorageMaximum string|nil
---@field MaxSeedSlots string|nil
---@field BuildingTasks string|nil
---@field PlayerSelectableTasks_1 string|nil
---@field PlayerSelectableTasks_2 string|nil
---@field PlayerSelectableTasks_3 string|nil
---@field SourceDefinition string|nil
---@field Hotkey string|nil
---@field ConstructionMustReplace string|nil
---@field AutoUnlock string|nil
---@field TechTreeListPreviousExit string|nil
---@field TechTreeListEntry string|nil
---@field TechTreeLineVerticalOffset string|nil
---@field PowerRange string|nil
---@field PeepEnergyAdded string|nil
---@field PeepEnergyCost string|nil

-- FIELDS that fit the pattern but were proven to not exist: 
--   BuildingTasks_4_Outputs_2_*
--   BuildingTasks_4_Inputs_2_*
--   BuildingTasks_5_Outputs_2_*
--   BuildingTasks_5_Inputs_2_*
-- Commented out fields are not used in BuildingTask
--- Cargo row from querying BuildingTasks; all values are strings at runtime.
---@class CargoBuildingTasksRecord
---@field page_name string|nil
---@field guid string|nil
---@field BuildingTasks_1_Name string|nil
---@field BuildingTasks_1_InitialState string|nil
---@field BuildingTasks_1_Time string|nil
---@field BuildingTasks_1_MinimumTimeDelta string|nil
---@field BuildingTasks_1_Outputs_1_Type string|nil
---@field BuildingTasks_1_Outputs_1_Resource string|nil
---@field BuildingTasks_1_Outputs_1_Value string|nil
---@field BuildingTasks_1_Outputs_2_Type string|nil
---@field BuildingTasks_1_Outputs_2_Resource string|nil
---@field BuildingTasks_1_Outputs_2_Value string|nil
---@field BuildingTasks_1_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_1_Inputs_1_Type string|nil
---@field BuildingTasks_1_Inputs_1_Resource string|nil
---@field BuildingTasks_1_Inputs_1_Value string|nil
---@field BuildingTasks_1_Inputs_2_Type string|nil
---@field BuildingTasks_1_Inputs_2_Resource string|nil
---@field BuildingTasks_1_Inputs_2_Value string|nil
---@field BuildingTasks_1_Inputs_3_Type string|nil
---@field BuildingTasks_1_Inputs_3_Resource string|nil
---@field BuildingTasks_1_Inputs_3_Value string|nil
---@field BuildingTasks_1_Inputs_4_Type string|nil
---@field BuildingTasks_1_Inputs_4_Resource string|nil
---@field BuildingTasks_1_Inputs_4_Value string|nil
---@field BuildingTasks_1_DescriptionTerm_en string|nil
---@field BuildingTasks_2_Name string|nil
---@field BuildingTasks_2_InitialState string|nil
---@field BuildingTasks_2_Time string|nil
---@field BuildingTasks_2_MinimumTimeDelta string|nil
---@field BuildingTasks_2_Outputs_1_Type string|nil
---@field BuildingTasks_2_Outputs_1_Resource string|nil
---@field BuildingTasks_2_Outputs_1_Value string|nil
---@field BuildingTasks_2_Outputs_2_Type string|nil
---@field BuildingTasks_2_Outputs_2_Resource string|nil
---@field BuildingTasks_2_Outputs_2_Value string|nil
---@field BuildingTasks_2_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_2_Inputs_1_Type string|nil
---@field BuildingTasks_2_Inputs_1_Resource string|nil
---@field BuildingTasks_2_Inputs_1_Value string|nil
---@field BuildingTasks_2_Inputs_2_Type string|nil
---@field BuildingTasks_2_Inputs_2_Resource string|nil
---@field BuildingTasks_2_Inputs_2_Value string|nil
---@field BuildingTasks_2_Inputs_3_Type string|nil
---@field BuildingTasks_2_Inputs_3_Resource string|nil
---@field BuildingTasks_2_Inputs_3_Value string|nil
---@field BuildingTasks_3_Name string|nil
---@field BuildingTasks_3_InitialState string|nil
---@field BuildingTasks_3_Time string|nil
---@field BuildingTasks_3_MinimumTimeDelta string|nil
---@field BuildingTasks_3_Outputs_1_Type string|nil
---@field BuildingTasks_3_Outputs_1_Resource string|nil
---@field BuildingTasks_3_Outputs_1_Value string|nil
---@field BuildingTasks_3_Outputs_2_Type string|nil
---@field BuildingTasks_3_Outputs_2_Resource string|nil
---@field BuildingTasks_3_Outputs_2_Value string|nil
---@field BuildingTasks_3_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_3_Inputs_1_Type string|nil
---@field BuildingTasks_3_Inputs_1_Resource string|nil
---@field BuildingTasks_3_Inputs_1_Value string|nil
---@field BuildingTasks_3_Inputs_2_Type string|nil
---@field BuildingTasks_3_Inputs_2_Resource string|nil
---@field BuildingTasks_3_Inputs_2_Value string|nil
---@field BuildingTasks_4_Name string|nil
---@field BuildingTasks_4_InitialState string|nil
---@field BuildingTasks_4_Time string|nil
---@field BuildingTasks_4_MinimumTimeDelta string|nil
---@field BuildingTasks_4_Outputs_1_Type string|nil
---@field BuildingTasks_4_Outputs_1_Resource string|nil
---@field BuildingTasks_4_Outputs_1_Value string|nil
---@field BuildingTasks_4_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_4_Inputs_1_Type string|nil
---@field BuildingTasks_4_Inputs_1_Resource string|nil
---@field BuildingTasks_4_Inputs_1_Value string|nil
---@field BuildingTasks_5_Name string|nil
---@field BuildingTasks_5_InitialState string|nil
---@field BuildingTasks_5_Time string|nil
---@field BuildingTasks_5_MinimumTimeDelta string|nil
---@field BuildingTasks_5_Outputs_1_Type string|nil
---@field BuildingTasks_5_Outputs_1_Resource string|nil
---@field BuildingTasks_5_Outputs_1_Value string|nil
---@field BuildingTasks_5_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_5_Inputs_1_Type string|nil
---@field BuildingTasks_5_Inputs_1_Resource string|nil
---@field BuildingTasks_5_Inputs_1_Value string|nil
---@field BuildingTasks_6_Name string|nil
---@field BuildingTasks_6_InitialState string|nil
---@field BuildingTasks_6_Time string|nil
---@field BuildingTasks_6_MinimumTimeDelta string|nil
---@field BuildingTasks_6_Outputs_1_Type string|nil
---@field BuildingTasks_6_Outputs_1_Resource string|nil
---@field BuildingTasks_6_Outputs_1_Value string|nil
---@field BuildingTasks_6_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_6_Inputs_1_Type string|nil
---@field BuildingTasks_6_Inputs_1_Resource string|nil
---@field BuildingTasks_6_Inputs_1_Value string|nil
---@field BuildingTasks_6_Inputs_2_Type string|nil
---@field BuildingTasks_6_Inputs_2_Resource string|nil
---@field BuildingTasks_6_Inputs_2_Value string|nil
---@field BuildingTasks_7_Name string|nil
---@field BuildingTasks_7_InitialState string|nil
---@field BuildingTasks_7_Time string|nil
---@field BuildingTasks_7_MinimumTimeDelta string|nil
---@field BuildingTasks_7_Outputs_1_Type string|nil
---@field BuildingTasks_7_Outputs_1_Resource string|nil
---@field BuildingTasks_7_Outputs_1_Value string|nil
---@field BuildingTasks_7_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_7_Inputs_1_Type string|nil
---@field BuildingTasks_7_Inputs_1_Resource string|nil
---@field BuildingTasks_7_Inputs_1_Value string|nil
---@field BuildingTasks_8_Name string|nil
---@field BuildingTasks_8_InitialState string|nil
---@field BuildingTasks_8_Time string|nil
---@field BuildingTasks_8_MinimumTimeDelta string|nil
---@field BuildingTasks_8_Outputs_1_Type string|nil
---@field BuildingTasks_8_Outputs_1_Resource string|nil
---@field BuildingTasks_8_Outputs_1_Value string|nil
---@field BuildingTasks_8_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_8_Inputs_1_Type string|nil
---@field BuildingTasks_8_Inputs_1_Resource string|nil
---@field BuildingTasks_8_Inputs_1_Value string|nil
---@field BuildingTasks_9_Name string|nil
---@field BuildingTasks_9_InitialState string|nil
---@field BuildingTasks_9_Time string|nil
---@field BuildingTasks_9_MinimumTimeDelta string|nil
---@field BuildingTasks_9_Outputs_1_Type string|nil
---@field BuildingTasks_9_Outputs_1_Resource string|nil
---@field BuildingTasks_9_Outputs_1_Value string|nil
---@field BuildingTasks_9_PollutionSlowdownThreshold string|nil
---@field BuildingTasks_9_Inputs_1_Type string|nil
---@field BuildingTasks_9_Inputs_1_Resource string|nil
---@field BuildingTasks_9_Inputs_1_Value string|nil

--#endregion



--#region MARK: Cargo consts

local FILTER_CATEGORY = "Category"
---@alias VALID_FILTER_FIELDS "Category"

local QUERIES = {
  BUILDINGS = {
    TABLE = "Buildings",
    WHERE_NAME = "page_name",
    WHERE_ID = "Name",
    WHERE_TASKS_GUID = "BuildingTasks",
    ORDER_BY = "page_name",
    FIELDS_NAME_ONLY = {
      "page_name",
    },
    FIELDS_FULL = {
      "page_name",
      "guid",
      "Name",
      FILTER_CATEGORY,
      "DisplayNameTerm_en",
      "DisplayNamePluralTerm_en",
      "DescriptionTerm_en",
      -- "UpgradeTerm",
      -- "UpgradeTerm_en",
      "IconAddress",
      -- "PlacementRules_1",
      -- "PlacementRules_2",
      -- "PlacementRules_3",
      -- "PlacementRules_4",
      -- "PlacementRules_5",
      -- "PlacementRules_6",
      -- "AnchorBuildingNames_1",
      -- "AnchorBuildingNames_2",
      -- "ConstructionResources",
      "ConstructionResources_1_Name",
      "ConstructionResources_1_Amount",
      "ConstructionResources_2_Name",
      "ConstructionResources_2_Amount",
      "ConstructionResources_3_Name",
      "ConstructionResources_3_Amount",
      "ConstructionResources_4_Name",
      "ConstructionResources_4_Amount",
      "ConstructionResources_5_Name",
      "ConstructionResources_5_Amount",
      "ConstructionResources_6_Name",
      "ConstructionResources_6_Amount",
      -- "SecondaryPrefabAddresses_1",
      -- "SecondaryPrefabAddresses_2",
      -- "RepairResources_1_Name",
      -- "RepairResources_1_Amount",
      -- "RepairResources_2_Name",
      -- "RepairResources_2_Amount",
      -- "RepairResources_3_Name",
      -- "RepairResources_3_Amount",
      -- "RepairResources_4_Name",
      -- "RepairResources_4_Amount",
      -- "RepairResources_5_Name",
      -- "RepairResources_5_Amount",
      -- "RepairResources_6_Name",
      -- "RepairResources_6_Amount",
      "ConstructionTime",
      -- "ConstructionPeepCount",
      "UnlockMode",
      "UnlockValues",
      "UnlockValues_1",
      "UnlockValues_2",
      "UnlockValues_3",
      "UnlockValues_4",
      -- "RequiredRecords_1",
      -- "UpgradePointsEarned",
      "LockedInDemo",
      "FootprintIconAddress",
      -- "TechTreeDisplay",
      "TechTreePrevious",
      -- "TechTreeRow",
      -- "AdjacencyBonuses",
      "AdjacencyBonuses_1_GroupName",
      "AdjacencyBonuses_1_Evaluator",
      "AdjacencyBonuses_1_EvaluatorThreshold",
      "AdjacencyBonuses_1_Action",
      -- "AdjacencyBonuses_1_ActionNames",
      -- "AdjacencyBonuses_1_ActionNames_1",
      -- "AdjacencyBonuses_1_ActionNames_2",
      -- "AdjacencyBonuses_1_ActionNames_3",
      -- "AdjacencyBonuses_1_ActionNames_4",
      -- "AdjacencyBonuses_1_ActionNames_5",
      "AdjacencyBonuses_1_EvaluatorValue",
      "AdjacencyBonuses_1_ActionValue",
      "AdjacencyBonuses_2_GroupName",
      "AdjacencyBonuses_2_Evaluator",
      "AdjacencyBonuses_2_EvaluatorThreshold",
      "AdjacencyBonuses_2_Action",
      -- "AdjacencyBonuses_2_ActionNames",
      -- "AdjacencyBonuses_2_ActionNames_1",
      -- "AdjacencyBonuses_2_ActionNames_2",
      -- "AdjacencyBonuses_2_ActionNames_3",
      -- "AdjacencyBonuses_2_ActionNames_4",
      -- "AdjacencyBonuses_2_ActionNames_5",
      "AdjacencyBonuses_2_EvaluatorValue",
      "AdjacencyBonuses_2_ActionValue",
      "AdjacencyBonuses_3_GroupName",
      "AdjacencyBonuses_3_Evaluator",
      "AdjacencyBonuses_3_EvaluatorThreshold",
      "AdjacencyBonuses_3_Action",
      -- "AdjacencyBonuses_3_ActionNames",
      -- "AdjacencyBonuses_3_ActionNames_1",
      -- "AdjacencyBonuses_3_ActionNames_2",
      -- "AdjacencyBonuses_3_ActionNames_3",
      -- "AdjacencyBonuses_3_ActionNames_4",
      "AdjacencyBonuses_3_EvaluatorValue",
      "AdjacencyBonuses_3_ActionValue",
      "AdjacencyBonuses_4_GroupName",
      "AdjacencyBonuses_4_Evaluator",
      "AdjacencyBonuses_4_EvaluatorThreshold",
      "AdjacencyBonuses_4_Action",
      -- "AdjacencyBonuses_4_ActionNames",
      "AdjacencyBonuses_4_EvaluatorValue",
      "AdjacencyBonuses_4_ActionValue",
      -- "OperationRules",
      -- "OperationRules_1",
      -- "OperationRules_2",
      -- "OperationRules_3",
      -- "OperationRules_4",
      -- "OperationRules_5",
      -- "OperationRules_6",
      -- "OperationRules_7",
      -- "OperationRules_8",
      -- "OperationRules_9",
      -- "OperationRules_10",
      -- "OperationRules_11",
      -- "OperationRules_12",
      -- "OperationRules_13",
      "MaxPeeps",
      "PeepExhaustionRemoved",
      "PeepAgeAdded",
      "PeepHappinessAdded",
      "PeepHappinessCost",
      "PollutionOutputMode",
      "SourceOfOxygenRange",
      -- "Resources",
      -- "Resources_1_Name",
      -- "Resources_1_Maximum",
      -- "Resources_1_StorageMode",
      -- "Resources_1_StartFull",
      -- "Resources_1_FetchInRange",
      -- "Resources_1_CanBeShared",
      -- "Resources_1_CycleThoughResourceSources",
      -- "Resources_1_GatheringMode",
      -- "Resources_1_DistributionMode",
      -- "Resources_1_DeliverInRange",
      -- "Resources_1_VehicleFetchsAndDelivers",
      -- "Resources_2_Name",
      -- "Resources_2_Maximum",
      -- "Resources_2_StorageMode",
      -- "Resources_2_StartFull",
      -- "Resources_2_FetchInRange",
      -- "Resources_2_CanBeShared",
      -- "Resources_2_CycleThoughResourceSources",
      -- "Resources_2_GatheringMode",
      -- "Resources_2_DistributionMode",
      -- "Resources_2_DeliverInRange",
      -- "Resources_2_VehicleFetchsAndDelivers",
      -- "Resources_3_Name",
      -- "Resources_3_Maximum",
      -- "Resources_3_StorageMode",
      -- "Resources_3_StartFull",
      -- "Resources_3_FetchInRange",
      -- "Resources_3_CanBeShared",
      -- "Resources_3_CycleThoughResourceSources",
      -- "Resources_3_GatheringMode",
      -- "Resources_3_DistributionMode",
      -- "Resources_3_DeliverInRange",
      -- "Resources_3_VehicleFetchsAndDelivers",
      -- "Resources_4_Name",
      -- "Resources_4_Maximum",
      -- "Resources_4_StorageMode",
      -- "Resources_4_StartFull",
      -- "Resources_4_FetchInRange",
      -- "Resources_4_CanBeShared",
      -- "Resources_4_CycleThoughResourceSources",
      -- "Resources_4_GatheringMode",
      -- "Resources_4_DistributionMode",
      -- "Resources_4_DeliverInRange",
      -- "Resources_4_VehicleFetchsAndDelivers",
      -- "Resources_5_Name",
      -- "Resources_5_Maximum",
      -- "Resources_5_StorageMode",
      -- "Resources_5_StartFull",
      -- "Resources_5_FetchInRange",
      -- "Resources_5_CanBeShared",
      -- "Resources_5_CycleThoughResourceSources",
      -- "Resources_5_GatheringMode",
      -- "Resources_5_DistributionMode",
      -- "Resources_5_DeliverInRange",
      -- "Resources_5_VehicleFetchsAndDelivers",
      -- "Resources_6_Name",
      -- "Resources_6_Maximum",
      -- "Resources_6_StorageMode",
      -- "Resources_6_StartFull",
      -- "Resources_6_FetchInRange",
      -- "Resources_6_CanBeShared",
      -- "Resources_6_CycleThoughResourceSources",
      -- "Resources_6_GatheringMode",
      -- "Resources_6_DistributionMode",
      -- "Resources_6_DeliverInRange",
      -- "Resources_6_VehicleFetchsAndDelivers",
      -- "Resources_7_Name",
      -- "Resources_7_Maximum",
      -- "Resources_7_StorageMode",
      -- "Resources_7_StartFull",
      -- "Resources_7_FetchInRange",
      -- "Resources_7_CanBeShared",
      -- "Resources_7_CycleThoughResourceSources",
      -- "Resources_7_GatheringMode",
      -- "Resources_7_DistributionMode",
      -- "Resources_7_DeliverInRange",
      -- "Resources_7_VehicleFetchsAndDelivers",
      -- "Resources_8_Name",
      -- "Resources_8_Maximum",
      -- "Resources_8_StorageMode",
      -- "Resources_8_StartFull",
      -- "Resources_8_FetchInRange",
      -- "Resources_8_CanBeShared",
      -- "Resources_8_CycleThoughResourceSources",
      -- "Resources_8_GatheringMode",
      -- "Resources_8_DistributionMode",
      -- "Resources_8_DeliverInRange",
      -- "Resources_8_VehicleFetchsAndDelivers",
      -- "Resources_9_Name",
      -- "Resources_9_Maximum",
      -- "Resources_9_StorageMode",
      -- "Resources_9_StartFull",
      -- "Resources_9_FetchInRange",
      -- "Resources_9_CanBeShared",
      -- "Resources_9_CycleThoughResourceSources",
      -- "Resources_9_GatheringMode",
      -- "Resources_9_DistributionMode",
      -- "Resources_9_DeliverInRange",
      -- "Resources_9_VehicleFetchsAndDelivers",
      -- "ResourceGroups",
      -- "ResourceGroups_1_Type",
      -- "ResourceGroups_1_Maximum",
      -- "ResourceGroups_1_GatheringMode",
      -- "ResourceGroups_1_DistributionMode",
      -- "ResourceGroups_1_StartFullResource",
      -- "ResourceGroups_2_Type",
      -- "ResourceGroups_2_Maximum",
      -- "ResourceGroups_2_GatheringMode",
      -- "ResourceGroups_2_DistributionMode",
      -- "ResourceGroups_2_StartFullResource",
      -- "DefinedResourceLists",
      -- "DefinedResourceLists_2_Name",
      -- "DefinedResourceLists_2_Maximum",
      -- "DefinedResourceLists_2_StorageMode",
      -- "DefinedResourceLists_2_StartFull",
      -- "DefinedResourceLists_2_FetchInRange",
      -- "DefinedResourceLists_2_CanBeShared",
      -- "DefinedResourceLists_2_CycleThoughResourceSources",
      -- "DefinedResourceLists_2_GatheringMode",
      -- "DefinedResourceLists_2_DistributionMode",
      -- "DefinedResourceLists_2_DeliverInRange",
      -- "DefinedResourceLists_2_VehicleFetchsAndDelivers",
      -- "DefaultFetchMode",
      -- "DefaultDeliveryMode",
      "FetchTime",
      "DeliveryTime",
      "TotalStorageMaximum",
      -- "MaxSeedSlots",
      "BuildingTasks",
      -- "PlayerSelectableTasks_1",
      -- "PlayerSelectableTasks_2",
      -- "PlayerSelectableTasks_3",
      -- "SourceDefinition",
      -- "Hotkey",
      -- "ConstructionMustReplace",
      -- "AutoUnlock",
      -- "TechTreeListPreviousExit",
      -- "TechTreeListEntry",
      -- "TechTreeLineVerticalOffset",
      "PowerRange",
      "PeepEnergyAdded",
      "PeepEnergyCost",
    },
  },
  TASKS = {
    TABLE = "BuildingTasks",
    WHERE_GUID = "guid",
    -- FIELDS that fit the pattern but are not declared in the DB table definition: 
    --   BuildingTasks_4_Outputs_2_*
    --   BuildingTasks_4_Inputs_2_*
    --   BuildingTasks_5_Outputs_2_*
    --   BuildingTasks_5_Inputs_2_*
    -- Commented out fields are not used in BuildingTask
    FIELDS = {
      "page_name",
      "guid",
      "BuildingTasks_1_Name",
      -- "BuildingTasks_1_InitialState",
      "BuildingTasks_1_Time",
      -- "BuildingTasks_1_MinimumTimeDelta",
      "BuildingTasks_1_Outputs_1_Type",
      "BuildingTasks_1_Outputs_1_Resource",
      "BuildingTasks_1_Outputs_1_Value",
      "BuildingTasks_1_Outputs_2_Type",
      "BuildingTasks_1_Outputs_2_Resource",
      "BuildingTasks_1_Outputs_2_Value",
      "BuildingTasks_1_Inputs_1_Type",
      "BuildingTasks_1_Inputs_1_Resource",
      "BuildingTasks_1_Inputs_1_Value",
      "BuildingTasks_1_Inputs_2_Type",
      "BuildingTasks_1_Inputs_2_Resource",
      "BuildingTasks_1_Inputs_2_Value",
      "BuildingTasks_1_Inputs_3_Type",
      "BuildingTasks_1_Inputs_3_Resource",
      "BuildingTasks_1_Inputs_3_Value",
      "BuildingTasks_1_Inputs_4_Type",
      "BuildingTasks_1_Inputs_4_Resource",
      "BuildingTasks_1_Inputs_4_Value",
      "BuildingTasks_1_PollutionSlowdownThreshold",
      "BuildingTasks_2_Name",
      -- "BuildingTasks_2_InitialState",
      "BuildingTasks_2_Time",
      -- "BuildingTasks_2_MinimumTimeDelta",
      "BuildingTasks_2_Outputs_1_Type",
      "BuildingTasks_2_Outputs_1_Resource",
      "BuildingTasks_2_Outputs_1_Value",
      "BuildingTasks_2_Outputs_2_Type",
      "BuildingTasks_2_Outputs_2_Resource",
      "BuildingTasks_2_Outputs_2_Value",
      "BuildingTasks_2_PollutionSlowdownThreshold",
      "BuildingTasks_2_Inputs_1_Type",
      "BuildingTasks_2_Inputs_1_Resource",
      "BuildingTasks_2_Inputs_1_Value",
      "BuildingTasks_2_Inputs_2_Type",
      "BuildingTasks_2_Inputs_2_Resource",
      "BuildingTasks_2_Inputs_2_Value",
      "BuildingTasks_2_Inputs_3_Type",
      "BuildingTasks_2_Inputs_3_Resource",
      "BuildingTasks_2_Inputs_3_Value",
      "BuildingTasks_3_Name",
      -- "BuildingTasks_3_InitialState",
      "BuildingTasks_3_Time",
      -- "BuildingTasks_3_MinimumTimeDelta",
      "BuildingTasks_3_Outputs_1_Type",
      "BuildingTasks_3_Outputs_1_Resource",
      "BuildingTasks_3_Outputs_1_Value",
      "BuildingTasks_3_Outputs_2_Type",
      "BuildingTasks_3_Outputs_2_Resource",
      "BuildingTasks_3_Outputs_2_Value",
      "BuildingTasks_3_PollutionSlowdownThreshold",
      "BuildingTasks_3_Inputs_1_Type",
      "BuildingTasks_3_Inputs_1_Resource",
      "BuildingTasks_3_Inputs_1_Value",
      "BuildingTasks_3_Inputs_2_Type",
      "BuildingTasks_3_Inputs_2_Resource",
      "BuildingTasks_3_Inputs_2_Value",
      "BuildingTasks_4_Name",
      -- "BuildingTasks_4_InitialState",
      "BuildingTasks_4_Time",
      -- "BuildingTasks_4_MinimumTimeDelta",
      "BuildingTasks_4_Outputs_1_Type",
      "BuildingTasks_4_Outputs_1_Resource",
      "BuildingTasks_4_Outputs_1_Value",
      "BuildingTasks_4_PollutionSlowdownThreshold",
      "BuildingTasks_4_Inputs_1_Type",
      "BuildingTasks_4_Inputs_1_Resource",
      "BuildingTasks_4_Inputs_1_Value",
      "BuildingTasks_5_Name",
      -- "BuildingTasks_5_InitialState",
      "BuildingTasks_5_Time",
      -- "BuildingTasks_5_MinimumTimeDelta",
      "BuildingTasks_5_Outputs_1_Type",
      "BuildingTasks_5_Outputs_1_Resource",
      "BuildingTasks_5_Outputs_1_Value",
      "BuildingTasks_5_PollutionSlowdownThreshold",
      "BuildingTasks_5_Inputs_1_Type",
      "BuildingTasks_5_Inputs_1_Resource",
      "BuildingTasks_5_Inputs_1_Value",
      "BuildingTasks_6_Name",
      -- "BuildingTasks_6_InitialState",
      "BuildingTasks_6_Time",
      -- "BuildingTasks_6_MinimumTimeDelta",
      "BuildingTasks_6_Outputs_1_Type",
      "BuildingTasks_6_Outputs_1_Resource",
      "BuildingTasks_6_Outputs_1_Value",
      "BuildingTasks_6_PollutionSlowdownThreshold",
      "BuildingTasks_6_Inputs_1_Type",
      "BuildingTasks_6_Inputs_1_Resource",
      "BuildingTasks_6_Inputs_1_Value",
      "BuildingTasks_6_Inputs_2_Type",
      "BuildingTasks_6_Inputs_2_Resource",
      "BuildingTasks_6_Inputs_2_Value",
      "BuildingTasks_7_Name",
      -- "BuildingTasks_7_InitialState",
      "BuildingTasks_7_Time",
      -- "BuildingTasks_7_MinimumTimeDelta",
      "BuildingTasks_7_Outputs_1_Type",
      "BuildingTasks_7_Outputs_1_Resource",
      "BuildingTasks_7_Outputs_1_Value",
      "BuildingTasks_7_PollutionSlowdownThreshold",
      "BuildingTasks_7_Inputs_1_Type",
      "BuildingTasks_7_Inputs_1_Resource",
      "BuildingTasks_7_Inputs_1_Value",
      "BuildingTasks_8_Name",
      -- "BuildingTasks_8_InitialState",
      "BuildingTasks_8_Time",
      -- "BuildingTasks_8_MinimumTimeDelta",
      "BuildingTasks_8_Outputs_1_Type",
      "BuildingTasks_8_Outputs_1_Resource",
      "BuildingTasks_8_Outputs_1_Value",
      "BuildingTasks_8_PollutionSlowdownThreshold",
      "BuildingTasks_8_Inputs_1_Type",
      "BuildingTasks_8_Inputs_1_Resource",
      "BuildingTasks_8_Inputs_1_Value",
      "BuildingTasks_9_Name",
      -- "BuildingTasks_9_InitialState",
      "BuildingTasks_9_Time",
      -- "BuildingTasks_9_MinimumTimeDelta",
      "BuildingTasks_9_Outputs_1_Type",
      "BuildingTasks_9_Outputs_1_Resource",
      "BuildingTasks_9_Outputs_1_Value",
      "BuildingTasks_9_PollutionSlowdownThreshold",
      "BuildingTasks_9_Inputs_1_Type",
      "BuildingTasks_9_Inputs_1_Resource",
      "BuildingTasks_9_Inputs_1_Value",
    }
  }
}

--#endregion



--#region MARK: Query buildings

--- Skips unwanted buildings from a query result.
---@param results CargoBuildingRecord[]
---@return CargoBuildingRecord[]
local function skip_unwanted_buildings(results)
  local new_results = {}
  for _, record in ipairs(results) do
    if not p.SKIPPED_BUILDINGS_NAMES[record.Name] then
      table.insert(new_results, record)
    end
  end
  return new_results
end

--- Queries cargo for all building records.
---@return CargoBuildingRecord[]
local function query_all_buildings()
  local cargo = mw.ext.cargo
  if not cargo then return {} end
  local result = cargo.query(
    QUERIES.BUILDINGS.TABLE,
    table.concat(QUERIES.BUILDINGS.FIELDS_FULL, ","), 
    {
      limit = 150,
      orderBy = QUERIES.BUILDINGS.ORDER_BY,
    })
  if not result or #result == 0 then return {} end
  result = skip_unwanted_buildings(result)
  return result
end

--- Queries cargo for building records by the given filter.
---@param filter_field VALID_FILTER_FIELDS
---@param filter_value string
---@return CargoBuildingRecord[]
local function query_buildings_by_filter(filter_field, filter_value)
  local cargo = mw.ext.cargo
  if not cargo then return {} end
  local result = cargo.query(
    QUERIES.BUILDINGS.TABLE,
    table.concat(QUERIES.BUILDINGS.FIELDS_FULL, ","), 
    {
      where = filter_field .. '="' .. filter_value .. '"',
      orderBy = QUERIES.BUILDINGS.ORDER_BY,
    })
  if not result or #result == 0 then return {} end
  result = skip_unwanted_buildings(result)
  return result
end

--- Queries cargo for the building record with the given name.
---@param building_name string the name of the building to fetch
---@return CargoBuildingRecord|nil
local function query_building(building_name)
  local cargo = mw.ext.cargo
  if not cargo then return nil end
  local result = cargo.query(
    QUERIES.BUILDINGS.TABLE,
    table.concat(QUERIES.BUILDINGS.FIELDS_FULL, ","), 
    {
      where = QUERIES.BUILDINGS.WHERE_NAME .. '="' .. building_name .. '"',
    })
  if not result or #result == 0 then return nil end
  result = skip_unwanted_buildings(result)
  return result[1]
end

--- Queries cargo for the building name only with the given id.
---@param building_id string the id of the building to fetch
---@return CargoBuildingRecord|nil
local function query_building_name_only(building_id)
  local cargo = mw.ext.cargo
  if not cargo then return nil end
  local result = cargo.query(
    QUERIES.BUILDINGS.TABLE,
    table.concat(QUERIES.BUILDINGS.FIELDS_NAME_ONLY, ","), 
    {
      where = QUERIES.BUILDINGS.WHERE_ID .. '="' .. building_id .. '"',
    })
  if not result or #result == 0 then return nil end
  result = skip_unwanted_buildings(result)
  return result[1]
end

--- Queries cargo for the building name only with the given guid.
---@param tasks_guid string the guid of the tasks list to look for in buildings
---@return CargoBuildingRecord|nil
local function query_building_name_only_by_tasks_guid(tasks_guid)
  local cargo = mw.ext.cargo
  if not cargo then return nil end
  local result = cargo.query(
    QUERIES.BUILDINGS.TABLE,
    table.concat(QUERIES.BUILDINGS.FIELDS_NAME_ONLY, ","), 
    {
      where = QUERIES.BUILDINGS.WHERE_TASKS_GUID .. '="' .. tasks_guid .. '"',
    })
  if not result or #result == 0 then return nil end
  result = skip_unwanted_buildings(result)
  return result[1]
end

--#endregion



--#region MARK: Query tasks

--- Queries cargo for the building tasks record with the given guid.
---@param building_tasks_guid string the guid of the building tasks to fetch
---@return CargoBuildingTasksRecord|nil
local function query_building_tasks(building_tasks_guid)
  local cargo = mw.ext.cargo
  if not cargo then return nil end
  local result = cargo.query(
    QUERIES.TASKS.TABLE,
    table.concat(QUERIES.TASKS.FIELDS, ","), 
    {
      where = QUERIES.TASKS.WHERE_GUID .. '="' .. building_tasks_guid .. '"',
    })
  if not result or #result == 0 then return nil end
  return result[1]
end

--- Queries cargo for all building tasks.
---@return CargoBuildingTasksRecord[]
local function query_all_building_tasks()
  local cargo = mw.ext.cargo
  if not cargo then return {} end
  local result = cargo.query(
    QUERIES.TASKS.TABLE,
    table.concat(QUERIES.TASKS.FIELDS, ",")
  )
  if not result or #result == 0 then return {} end
  return result
end

--#endregion



--#region MARK: Restructuring

--- Restructures the construction resources of a building record from the database into a more usable format.
---@param record CargoBuildingRecord
---@return ConstructionPair[]
local function restructure_construction_resources(record)
  local construction_resources = {}
  for i = 1, p.MAX_CONSTRUCTION_PAIRS do
    local construction_resource = record[string.format("ConstructionResources_%d_Name", i)]
    local construction_amount = record[string.format("ConstructionResources_%d_Amount", i)]
    if construction_resource and construction_amount then
      table.insert(construction_resources, {
        name = construction_resource,
        amount = tonumber(construction_amount),
      })
    end
  end
  return construction_resources
end

--- Restructures the unlock values of a building record from the database into a more usable format.
---@param record CargoBuildingRecord
---@return string[]
local function restructure_unlock_values(record)
  local unlock_values = {}
  for i = 1, p.MAX_UNLOCK_VALUES do
    local unlock_value = record[string.format("UnlockValues_%d", i)]
    if unlock_value then
      table.insert(unlock_values, unlock_value)
    end
  end
  return unlock_values
end

--- Restructures the adjacency bonuses of a building record from the database into a more usable format.
---@param record CargoBuildingRecord
---@return AdjacencyBonus[]
local function restructure_adjacency_bonuses(record)
  local adjacency_bonuses = {}
  for i = 1, p.MAX_ADJACENCY_BONUSES do
    local group_name = record[string.format("AdjacencyBonuses_%d_GroupName", i)]
    local evaluator_type = record[string.format("AdjacencyBonuses_%d_Evaluator", i)]
    local evaluator_threshold = record[string.format("AdjacencyBonuses_%d_EvaluatorThreshold", i)]
    local evaluator_value = record[string.format("AdjacencyBonuses_%d_EvaluatorValue", i)]
    local action = record[string.format("AdjacencyBonuses_%d_Action", i)]
    local action_value = record[string.format("AdjacencyBonuses_%d_ActionValue", i)]
    if group_name and evaluator_type and evaluator_threshold and evaluator_value and action and action_value then
      table.insert(adjacency_bonuses, {
        bonus_name = group_name,
        evaluator_type = evaluator_type,
        evaluator_threshold = tonumber(evaluator_threshold),
        evaluator_value = evaluator_value,
        action = action,
        action_value = tonumber(action_value),
      })
    end
  end
  return adjacency_bonuses
end

--- Restructures the inputs or ouputs of a building task
---@param task_record CargoBuildingTasksRecord the building tasks record retrieved for the building
---@param task_num number which task to restructure
---@param which_io "Inputs"|"Outputs" the type of tasks to restructure
---@return BuildingTaskIO[]
local function restructure_task_io(task_record, task_num, which_io)
  local task_io = {}
  local max = ((which_io == "Inputs") and p.MAX_BUILDING_TASK_INPUTS) or p.MAX_BUILDING_TASK_OUTPUTS
  local task_type_prefix = "BuildingTasks_" .. task_num .. "_" .. which_io .. "_%d_"
  for i = 1, max do
    local put_type = task_record[string.format(task_type_prefix .. "Type", i)]
    local put_resource = task_record[string.format(task_type_prefix .. "Resource", i)]
    local put_value = task_record[string.format(task_type_prefix .. "Value", i)]
    if put_type or put_resource or put_value then
      table.insert(task_io, {
        type = put_type,
        resource = put_resource,
        value = put_value,
      })
    end
  end
  return task_io
end

--- Restructures a task record from the database into a more usable format.
---@param task_record CargoBuildingTasksRecord
---@return BuildingTask[]
local function restructure_tasks(task_record)
  local tasks = {}
  for i = 1, p.MAX_BUILDING_TASKS do
    local task_name = task_record[string.format("BuildingTasks_%d_Name", i)]
    local time = tonumber(task_record[string.format("BuildingTasks_%d_Time", i)])
    local pollution_slowdown = tonumber(task_record[string.format("BuildingTasks_%d_PollutionSlowdownThreshold", i)])
    local outputs = restructure_task_io(task_record, i, "Outputs")
    local inputs = restructure_task_io(task_record, i, "Inputs")
    if task_name then
      table.insert(tasks, {
        task_name = task_name,
        time = time,
        outputs = outputs,
        inputs = inputs,
        pollution_slowdown_threshold = pollution_slowdown,
      })
    end
  end
  return tasks
end

--- Restructures the tasks of a building record from the database into a more usable format.
---@param building_record CargoBuildingRecord
---@return BuildingTask[]
local function restructure_tasks_in_building(building_record)
  local tasks_guid = building_record.BuildingTasks
  if not tasks_guid then return {} end
  local raw_tasks = query_building_tasks(tasks_guid)
  if not raw_tasks then return {}
   end
  local tasks = restructure_tasks(raw_tasks)
  return tasks
end

--- Restructures a flat building record from the database into a more usable format.
---@param record CargoBuildingRecord
---@return Building|nil
local function restructure_building_record(record)
  local portrait_icon_filename = nil
  if not p.PORTRAITS_MISSING_NAMES[record.Name] then
    portrait_icon_filename = p.BUILDING_PORTRAIT_PREFIX .. record.Name
  end
  local building = {
    name = record.page_name,
    category = record.Category,
    display_name = record.DisplayNameTerm_en or record.page_name,
    display_name_plural = record.DisplayNamePluralTerm_en,
    description = record.DescriptionTerm_en,
    icon = record.IconAddress,
    portrait_icon = portrait_icon_filename,
    construction_resources = {},
    construction_time = tonumber(record.ConstructionTime),
    unlock_mode = record.UnlockMode,
    unlock_values = {},
    is_in_demo = record.LockedInDemo,
    footprint_icon = record.FootprintIconAddress,
    tech_tree_previous = record.TechTreePrevious,
    adjacency_bonuses = {},
    max_peeps = tonumber(record.MaxPeeps),
    peep_exhaustion_removed = tonumber(record.PeepExhaustionRemoved),
    peep_age_added = tonumber(record.PeepAgeAdded),
    peep_happiness_added = tonumber(record.PeepHappinessAdded),
    peep_happiness_cost = tonumber(record.PeepHappinessCost),
    peep_energy_added = tonumber(record.PeepEnergyAdded),
    peep_energy_cost = tonumber(record.PeepEnergyCost),
    pollution_output_mode = record.PollutionOutputMode,
    oxygen_source_range = tonumber(record.SourceOfOxygenRange),
    fetch_mode = record.DefaultFetchMode,
    delivery_mode = record.DefaultDeliveryMode,
    fetch_time = tonumber(record.FetchTime),
    delivery_time = tonumber(record.DeliveryTime),
    storage_max = tonumber(record.TotalStorageMaximum),
    power_range = tonumber(record.PowerRange),
    tasks = {},
  }
  building.construction_resources = restructure_construction_resources(record)
  building.unlock_values = restructure_unlock_values(record)
  building.adjacency_bonuses = restructure_adjacency_bonuses(record)
  building.tasks = restructure_tasks_in_building(record)
  return building
end

--#endregion



--#region MARK: Private helpers

--- Maps the given tasks by the given building guiid.
---@param list_of_tasks_records CargoBuildingTasksRecord[]
---@return table<string, CargoBuildingTasksRecord>
local function map_tasks_by_guid(list_of_tasks_records)
  local map = {}
  for _, tasks_record in ipairs(list_of_tasks_records) do
    local tasks_guid = tasks_record.guid
    if tasks_guid and tasks_guid ~= "" then
      map[tasks_guid] = tasks_record
    end
  end
  return map
end

--- Filters the given tasks by the given resource id.
---@param tasks BuildingTask[]
---@param resource_id string the id of the resource to filter tasks by
---@return BuildingTask[]
local function filter_tasks_by_resource(tasks, resource_id)
  local filtered_tasks = {}
  for _, task in ipairs(tasks) do
    local found = false
    for _, input in ipairs(task.inputs) do
      if input.resource == resource_id then
        table.insert(filtered_tasks, task)
        found = true
        break
      end
    end
    if not found then
      for _, output in ipairs(task.outputs) do
        if output.resource == resource_id then
          table.insert(filtered_tasks, task)
          break
        end
      end
    end
  end
  return filtered_tasks
end

--#endregion



--#region MARK: Public interface

---@class BuildingDataModule
---@field MAX_CONSTRUCTION_PAIRS number the maximum number of construction pairs
---@field MAX_UNLOCK_VALUES number the maximum number of unlock values
---@field MAX_ADJACENCY_BONUSES number the maximum number of adjacency bonuses
---@field MAX_BUILDING_TASKS number the maximum number of building tasks
---@field MAX_BUILDING_TASK_OUTPUTS number the maximum number of building task outputs
---@field MAX_BUILDING_TASK_INPUTS number the maximum number of building task inputs
---@field FILTERS table filter field names for building queries
---@field get_name_by_id fun(id: string): string|nil looks up a building page name by codename
---@field get_building fun(building_name: string): Building|nil looks up a building by page name
---@field get_buildings_by_category fun(category: string): Building[] gets buildings in a category
---@field get_all_buildings fun(): Building[] gets all buildings
---@field get_building_names_with_tasks_including_resource fun(resource_id: string): table<string, BuildingTask[]> building page names to matching tasks

p.MAX_CONSTRUCTION_PAIRS = 6
p.MAX_UNLOCK_VALUES = 4
p.MAX_ADJACENCY_BONUSES = 4
p.MAX_BUILDING_TASKS = 9
p.MAX_BUILDING_TASK_OUTPUTS = 2
p.MAX_BUILDING_TASK_INPUTS = 4
p.BUILDING_PORTRAIT_PREFIX = "BuildingPortrait_"
p.PORTRAITS_MISSING_NAMES = {
  ["CompostingSite"] = true,
  ["Forest_WorldTwo"] = true,
  ["HomeSpaceshipLanded"] = true,
  ["Mill"] = true,
  ["WhaleTranslatorRuin"] = true,
  ["OxygenGenerator"] = true,
  ["Rock_WorldThree"] = true,
  ["Ruin_WorldTwo"] = true,
  ["SettlementSpaceshipLanded"] = true,
  ["SettlementSpaceshipLauncher"] = true,
  ["SteelBridge"] = true,
  ["StorageExtension"] = true,
}
p.SKIPPED_BUILDINGS_NAMES = {
  ["CompostTool"] = true,
  ["ConstructionConsumption"] = true,
  ["DemolitionControl"] = true,
  ["Drone_Repair"] = true,
  ["ForestPlantingTool"] = true,
  ["CreateMineableArea"] = true,
  ["MiningTile"] = true,
  ["MoveBuildingControl"] = true,
  ["PauseControl"] = true,
  ["PeepConsumption"] = true,
  ["PriorityControl"] = true,
  ["LandFillingSite"] = true,
  ["RampConstruction"] = true,
  ["RepairControl"] = true,
  ["ResourceCache"] = true,
  ["RoadConstruction"] = true,
  ["SettlementSpaceshipReload"] = true,
  ["ThornyStems"] = true,
}
p.FILTERS = {
  CATEGORY = FILTER_CATEGORY,
}

---@class ConstructionPair
---@field name string the name of the construction resource
---@field amount number the amount of the construction resource

---@class AdjacencyBonus
---@field bonus_name string|nil the codename for the bonus group
---@field evaluator_type string|nil the type of evaluator that triggers the bonus
---@field evaluator_threshold number|nil the threshold value for the evaluator
---@field evaluator_value string|nil the codename for what condition evaluated for the trigger
---@field action string|nil the action to take when the bonus is triggered
---@field action_value number|nil the value to apply for the action

---@class BuildingTaskIO
---@field type string|nil the type of input/output
---@field resource string|nil the codename for the resource
---@field value string|nil the value of the input/output

---@class BuildingTask
---@field task_name string|nil the name of the task
---@field time number|nil the time it takes to complete the task
---@field outputs BuildingTaskIO[]|nil the outputs of the task
---@field inputs BuildingTaskIO[]|nil the inputs of the task
---@field pollution_slowdown_threshold number|nil the threshold at which pollution slows down the task

---@class Building
---@field name string|nil the in-game codename for the building
---@field category string|nil the category of the building
---@field display_name string|nil the display name of the building
---@field display_name_plural string|nil the plural display name of the building
---@field description string|nil the description of the building
---@field icon string|nil the flat icon asset name for this building
---@field portrait_icon string|nil the pre-rendered portrait icon asset name for this building
---@field construction_resources ConstructionPair[]|nil the construction resources of the building
---@field construction_time number|nil the time it takes to construct the building
---@field unlock_mode string|nil the requirement for unlocking the building
---@field unlock_values string[]|nil the values required for unlocking the building
---@field is_in_demo boolean whether the building is locked in the demo
---@field footprint_icon string|nil the icon filename for the building's footprint
---@field tech_tree_previous string|nil the previous building in the tech tree
---@field adjacency_bonuses AdjacencyBonus[]|nil the adjacency bonuses of the building
---@field max_peeps number|nil the maximum number of peeps that can be assigned to the building
---@field peep_exhaustion_removed number|nil the amount of exhaustion removed per peep per second
---@field peep_age_added number|nil the amount of age added per peep per second
---@field peep_happiness_added number|nil the amount of happiness added per peep per second
---@field peep_happiness_cost number|nil the cost of happiness per peep per second
---@field peep_energy_added number|nil the amount of energy added per peep per second
---@field peep_energy_cost number|nil the cost of energy per peep per second
---@field pollution_output_mode string|nil the level of pollution output from the building
---@field oxygen_source_range number|nil the range of the oxygen source for the building
---@field fetch_mode string|nil the mode for fetching resources from the building
---@field delivery_mode string|nil the mode for delivering resources to the building
---@field fetch_time number|nil the time it takes to fetch resources from the building
---@field delivery_time number|nil the time it takes to deliver resources to the building
---@field storage_max number|nil the maximum amount of storage for the building
---@field power_range number|nil the range of the power source for the building
---@field tasks BuildingTask[]|nil the tasks the building can work on

--- Fetches a building's page name by its id.
---@param id string the id of the building to fetch
---@return string|nil the page name of the building
function p.get_name_by_id(id)
  local raw_record = query_building_name_only(id)
  if not raw_record then return nil end
  return raw_record.page_name or nil
end

--- Fetches a building record from the database.
---@param building_name string the in-game name of the building to fetch
---@return Building|nil
function p.get_building(building_name)
  local raw_record = query_building(building_name)
  if not raw_record then return nil end
  local record = restructure_building_record(raw_record)
  return record
end

--- Fetches building records for the given category.
---@param category string
---@return Building[]
function p.get_buildings_by_category(category)
  local raw_records = query_buildings_by_filter(p.FILTERS.CATEGORY, category)
  if not raw_records then return {} end
  local new_records = {}
  for _, raw_record in ipairs(raw_records) do
    local record = restructure_building_record(raw_record)
    table.insert(new_records, record)
  end
  return new_records
end

--- Fetches all building records from the database.
---@return Building[]
function p.get_all_buildings()
  local raw_records = query_all_buildings()
  if not raw_records then return {} end
  local new_records = {}
  for _, raw_record in ipairs(raw_records) do
    local record = restructure_building_record(raw_record)
    table.insert(new_records, record)
  end
  return new_records
end

--- Fetches all buildings whose work involves the given resource.
---@param resource_id string the id of the resource to fetch buildings for
---@return table<string, BuildingTask[]>
function p.get_building_names_with_tasks_including_resource(resource_id)
  local raw_records = query_all_building_tasks()
  local raw_map_of_tasks = map_tasks_by_guid(raw_records)
  ---@type table<string, BuildingTask[]>
  local map_building_map_of_tasks = {}
  for tasks_guid, tasks_record in pairs(raw_map_of_tasks) do
    local tasks = restructure_tasks(tasks_record)
    local filtered_tasks = filter_tasks_by_resource(tasks, resource_id)
    if filtered_tasks and #filtered_tasks > 0 then
      local building_record = query_building_name_only_by_tasks_guid(tasks_guid)
      if building_record then
        local building_name = building_record.page_name
        if building_name and building_name ~= "" then
          map_building_map_of_tasks[building_name] = filtered_tasks
        end
      end
    end
  end
  return map_building_map_of_tasks
end

---@cast p BuildingDataModule
return p

--#endregion