require "Vehicles/VehicleDistributions"
require "Items/ProceduralDistributions"

-- Cached item lists (populated once at game start)
local cachedFirearms = {}
local cachedAmmo = {}
local cachedAmmoBoxes = {}
local cachedGunParts = {}
local cachedMilitaryClothing = {}
local itemsCached = false
local warnedInvalidLootDependencies = {}

local function getItemModuleName(fullType)
   if type(fullType) ~= "string" then return nil end
   return fullType:match("^(.-)%.")
end

local function coerceDistributionItemName(itemName)
   if type(itemName) == "string" then
      return itemName
   end
   if itemName == nil then
      return nil
   end
   local ok, stringValue = pcall(tostring, itemName)
   if not ok or stringValue == nil or stringValue == "" then
      return nil
   end
   return stringValue
end

local function normalizeItemType(itemType, defaultModule)
   if type(itemType) ~= "string" or itemType == "" then return nil end
   if itemType:find("%.") or itemType:find(":") then
      return itemType
   end
   if defaultModule and defaultModule ~= "" then
      return defaultModule .. "." .. itemType
   end
   return "Base." .. itemType
end

local function hasScriptItem(itemType)
   local manager = getScriptManager and getScriptManager() or nil
   if not manager or not itemType then return false end
   return manager:FindItem(itemType) ~= nil or manager:getItem(itemType) ~= nil
end

local function getScriptItem(itemType)
   local manager = getScriptManager and getScriptManager() or nil
   local normalizedType = normalizeItemType(itemType)
   if not manager or not normalizedType then return nil end
   return manager:FindItem(normalizedType) or manager:getItem(normalizedType)
end

local function warnInvalidFirearmDependency(weaponType, dependencyKind, dependencyType)
   local key = tostring(weaponType) .. "|" .. tostring(dependencyKind) .. "|" .. tostring(dependencyType)
   if warnedInvalidLootDependencies[key] then return end
   warnedInvalidLootDependencies[key] = true
   --print(("rSemiTruck: Skipping firearm in military loot, unresolved " .. tostring(dependencyKind) .. " for " .. tostring(weaponType) .. ": " .. tostring(dependencyType))
end

local function isFirearmSafeForLoot(scriptItem)
   if not scriptItem then return false end

   local fullType = scriptItem:getFullName()
   local moduleName = scriptItem.getModuleName and scriptItem:getModuleName() or getItemModuleName(fullType)
   local magazineType = scriptItem.getMagazineType and normalizeItemType(scriptItem:getMagazineType(), moduleName) or nil
   if magazineType and not hasScriptItem(magazineType) then
      warnInvalidFirearmDependency(fullType, "MagazineType", magazineType)
      return false
   end

   local ammoBoxType = scriptItem.getAmmoBox and normalizeItemType(scriptItem:getAmmoBox(), moduleName) or nil
   if ammoBoxType and not hasScriptItem(ammoBoxType) then
      warnInvalidFirearmDependency(fullType, "AmmoBox", ammoBoxType)
      return false
   end

   return true
end

local function isDistributionItemSafe(itemName)
   local scriptItem = getScriptItem(itemName)
   if not scriptItem then return false end
   if scriptItem:hasTag(ItemTag.FIREARM) then
      return isFirearmSafeForLoot(scriptItem)
   end
   return true
end

-- Build cached item lists once
local function cacheModdedItems()
   if itemsCached then return end
   
  ----print(("rSemiTruck: Building modded item cache...")
   local allItems = getAllItems()
   if not allItems then return end
   
   for i = 0, allItems:size() - 1 do
      local item = allItems:get(i)
      if item then
            local isCandidate = false
            local targetList = nil
            -- Determine if this item is a candidate and which list it belongs to
            if item:hasTag(ItemTag.FIREARM) then
               if isFirearmSafeForLoot(item) then
                  isCandidate = true
                  targetList = cachedFirearms
               end
            elseif item.getDisplayCategory and item:getDisplayCategory() == "Ammo" then
               isCandidate = true
               targetList = cachedAmmo
            elseif item.getDisplayCategory and item:getDisplayCategory() == "WeaponPart" then
               isCandidate = true
               targetList = cachedGunParts
            elseif item.getDisplayName and item.getClothingItem then
               local displayName = item:getDisplayName()
               if displayName then
                  local displayLower = displayName:lower()
                  local clothingItem = item:getClothingItem()
                  if clothingItem and (displayLower:find("army") or displayLower:find("military") or
                      displayLower:find("camo") or displayLower:find("tactical") or displayLower:find("vest") or
                      displayLower:find("combat") or displayLower:find("ghillie")) then
                     isCandidate = true
                     targetList = cachedMilitaryClothing
                  end
               end
            end
         local fullType = item:getFullName()  -- e.g. "Base.AssaultRifle" -- required by AddItem
         if fullType then
            if isCandidate and targetList then
               table.insert(targetList, fullType)
               -- Also track ammo boxes separately (for cab spawning)
               if targetList == cachedAmmo and fullType:lower():find("box") then
                  table.insert(cachedAmmoBoxes, fullType)
               end
            end
         end
      end
   end
   
   itemsCached = true
  ----print(("rSemiTruck: Cached " .. #cachedFirearms .. " firearms, " .. #cachedAmmo .. " ammo types, " .. #cachedMilitaryClothing .. " clothing items")
end

-- Helper function to dynamically add modded military items when filling vehicle containers
local function onFillMilitaryVehicle(roomName, containerType, container)
   local enabledmilitaryloot = true -- Set to false to disable dynamic loot injection (cache is still built and distributions initialized)
   if not enabledmilitaryloot then return end
   -- instanceof guards against non-standard Java containers (e.g. ItemPickerJava$ItemPickerContainer)
   if not container or not instanceof(container, "ItemContainer") then return end
   local part = container:getVehiclePart()
   if not part then return end
   local vehicle = part:getVehicle()
   if not vehicle then return end
   local script = vehicle:getScript()
   if not script then return end
   local scriptName = script:getName()
   if not (scriptName and (scriptName:find("SemiTruckBox_mil") or scriptName:find("SemiTrailerVan_mil"))) then
      return
   end
   -- Skip item-containers that live inside the vehicle (bags, cases, etc. — they have underscores in their type name)
   if not containerType or containerType:find("_") then return end
   -- Skip engine, seat, and glovebox containers
   local ct = containerType:lower()
   if ct:find("engine") or ct:find("seat") or ct:find("glovebox") or ct:find("trunktoolbox") then return end

   -- Ensure cache is built
   if not itemsCached then
      cacheModdedItems()
   end
   
   --print(("rSemiTruck: Filling dynamic military cargo: " .. scriptName .. " / " .. containerType)
   
   local itemsAdded = 0
   
   -- Add firearms: randomly pick 1-5 from cached list (no iteration!)
   if #cachedFirearms > 0 then
      local numFirearms = ZombRand(1, 6) -- 1 to 5
      numFirearms = math.min(numFirearms, #cachedFirearms) -- Don't exceed available
      
      for i = 1, numFirearms do
         local randomIndex = ZombRand(1, #cachedFirearms + 1)
         local ok = pcall(function() container:AddItem(cachedFirearms[randomIndex]) end)
         if ok then itemsAdded = itemsAdded + 1 end
      end
     ----print(("rSemiTruck: Added " .. numFirearms .. " firearms")
   end
   
   -- Add ammunition: randomly pick 10-25 boxes from cached list
   if #cachedAmmo > 0 then
      local numAmmo = ZombRand(10, 25) -- 10 to 25 boxes
      numAmmo = math.min(numAmmo, #cachedAmmo) -- Don't exceed available
      for i = 1, numAmmo do
         local randomIndex = ZombRand(1, #cachedAmmo + 1)
         --local quantity = ZombRand(1, 4) -- 1-3 per type
         local quantity = 2
         local ok = pcall(function() container:AddItems(cachedAmmo[randomIndex], quantity) end)
         if ok then itemsAdded = itemsAdded + 1 end
      end
     ----print(("rSemiTruck: Added " .. numAmmo .. " ammo types")
   end
   
   -- Add gun parts: randomly pick 2-8 from cached list
   if #cachedGunParts > 0 then
      local numParts = ZombRand(2, 8) -- 2 to 8 
      numParts = math.min(numParts, #cachedGunParts)
      
      for i = 1, numParts do
         local randomIndex = ZombRand(1, #cachedGunParts + 1)
         local ok = pcall(function() container:AddItem(cachedGunParts[randomIndex]) end)
         if ok then itemsAdded = itemsAdded + 1 end
      end
     ----print(("rSemiTruck: Added " .. numParts .. " gun parts")
   end
  
  ----print(("rSemiTruck: Total modded items added: " .. itemsAdded)
end

-- Helper function to copy items from ProceduralDistributions to vehicle distribution
local function mergeProceduralIntoVehicle(procDistNames, baseRolls)
   local mergedItems = {}
   
   -- Safety check for ProceduralDistributions
   if not ProceduralDistributions or not ProceduralDistributions.list then
     ----print(("rSemiTruck: ERROR - ProceduralDistributions.list not available yet")
      return {
         rolls = baseRolls,
         items = {},
         junk = { rolls = 1, items = {} }
      }
   end
   
   for _, distName in ipairs(procDistNames) do
      local procDist = ProceduralDistributions.list[distName]
      if procDist and procDist.items then
         for i = 1, #procDist.items, 2 do
            local itemName = coerceDistributionItemName(procDist.items[i])
            local itemChance = procDist.items[i + 1]
            if itemName and itemChance then
               if isDistributionItemSafe(itemName) then
                  table.insert(mergedItems, itemName)
                  table.insert(mergedItems, itemChance)
               elseif itemName:find("%.") then
                  warnInvalidFirearmDependency(itemName, "DistributionItem", itemName)
               end
            end
         end
      end
   end
   
  ----print(("rSemiTruck: Merged " .. (#mergedItems / 2) .. " items from procedural distributions")
   
   return {
      rolls = baseRolls,
      items = mergedItems,
      junk = {
         rolls = 1,
         items = {}
      }
   }
end

-- Army ProceduralDistributions to merge (for vanilla items)
local armyProcDistributions = {
   "ArmyStorageGuns",
   "ArmyStorageAmmunition",
   --"ArmyStorageOutfit",
   "ArmyStorageMedical",
   "ArmyStorageElectronics",
   "ArmySurplusBackpacks",
   "ArmySurplusTools",
   "ArmySurplusMisc",
}
local armyProcDistributionsSmall = {
   "ArmyStorageOutfit",
   "ArmySurplusBackpacks",
   "ArmySurplusTools",
}


-- Initialize distributions
local function initMilitaryDistributions()
  ----print(("=== rSemiTruck: Initializing military distributions (POST-MERGE) ===")
   
   -- Safety check for required APIs
   if not VehicleDistributions then
      ----print(("rSemiTruck: ERROR - VehicleDistributions not available")
      return
   end
   
   if not ProceduralDistributions or not ProceduralDistributions.list then
      ----print(("rSemiTruck: ERROR - ProceduralDistributions not available")
      return
   end
   
   -- Get the distribution table
   local distributionTable = VehicleDistributions[1]
   
   -- Define vehicle inventory tables
   
   -- Military truck uses custom military distribution
   VehicleDistributions.SemiTruckInventory_mil = {
      TruckBed = nil;  -- Will be set below
      TrunkLeft = nil;  -- Will be set below
      SeatMiddleLeft = VehicleDistributions.ArmyLightSeatRear;
   }
   
   -- Military box truck uses custom military distribution
   VehicleDistributions.SemiTruckBoxInventory_mil = {
      TruckBed = nil;  -- Will be set below
      TruckBedOpen = nil;  -- Will be set below
      TrailerTrunk = nil;  -- Will be set below
   }   -- Military trailer van uses custom military distribution
   VehicleDistributions.TrailerVanInventory_mil = {
      TruckBed = nil;  -- Will be set below
      TrunkToolbox = nil;  -- Will be set below
   }
   
   -- Merge vanilla military items
   VehicleDistributions.MilitaryTruckBed = mergeProceduralIntoVehicle(armyProcDistributions, 0.25)
      VehicleDistributions.MilitaryTruckBedSmall = mergeProceduralIntoVehicle(armyProcDistributionsSmall, 0.75)
   
   -- Set up vehicle distributions
   VehicleDistributions.SemiTruckInventory_mil.TruckBed = VehicleDistributions.MilitaryTruckBedSmall
   VehicleDistributions.SemiTruckInventory_mil.TrunkLeft = VehicleDistributions.MilitaryTruckBedSmall
   
   VehicleDistributions.SemiTruckBoxInventory_mil.TruckBed = VehicleDistributions.MilitaryTruckBed
   
   VehicleDistributions.TrailerVanInventory_mil.TruckBed = VehicleDistributions.MilitaryTruckBed
   VehicleDistributions.TrailerVanInventory_mil.TrunkToolbox = VehicleDistributions.MilitaryTruckBedSmall
   
   -- Register military vehicles in distribution table
   distributionTable["SemiTruck_mil"] = { Normal = VehicleDistributions.SemiTruckInventory_mil; }
   distributionTable["SemiTruckBox_mil"] = { Normal = VehicleDistributions.SemiTruckBoxInventory_mil; }
   distributionTable["SemiTrailerVan_mil"] = { Normal = VehicleDistributions.TrailerVanInventory_mil; }
   
end

-- Loot injection for SemiTruck_mil cab (limited storage: 2 weapons + their mags + ammo)
local function onFillSemiTruckMilCab(roomName, containerType, container)
   if not container or not instanceof(container, "ItemContainer") then return end
   local part = container:getVehiclePart()
   if not part then return end
   local vehicle = part:getVehicle()
   if not vehicle then return end
   local script = vehicle:getScript()
   if not script then return end
   local scriptName = script:getName()
   -- Only SemiTruck_mil, explicitly not the box variant
   if not (scriptName and scriptName:find("SemiTruck_mil") and not scriptName:find("Box")) then
      return
   end
   if containerType then
      local ct = containerType:lower()
      if ct:find("engine") or ct:find("seat") or ct:find("microwave") or ct:find("fridge") then return end
   end

   if not itemsCached then cacheModdedItems() end
   if #cachedFirearms == 0 then return end

   --print(("rSemiTruck: Filling SemiTruck_mil cab: " .. scriptName .. " / " .. (containerType or "?"))

   for i = 1, 2 do
      local randomIndex = ZombRand(1, #cachedFirearms + 1)
      local weaponType = cachedFirearms[randomIndex]
      local weapon = nil
      local ok = pcall(function() weapon = container:AddItem(weaponType) end)
      if ok and weapon then
         -- Add 1-3 magazines if the weapon uses them
         local magType = nil
         pcall(function() magType = weapon:getMagazineType() end)
         local normalizedMagType = normalizeItemType(magType, getItemModuleName(weaponType))
         if normalizedMagType and hasScriptItem(normalizedMagType) then
            local magCount = ZombRand(1, 4)  -- 1-3 magazines
            for j = 1, magCount do
               pcall(function() container:AddItem(normalizedMagType) end)
            end
         elseif normalizedMagType then
            warnInvalidFirearmDependency(weaponType, "MagazineType", normalizedMagType)
         end
         -- Add 1-5 ammo boxes
         if #cachedAmmoBoxes > 0 then
            local boxCount = ZombRand(1, 6)
            for j = 1, boxCount do
               local boxIndex = ZombRand(1, #cachedAmmoBoxes + 1)
               pcall(function() container:AddItem(cachedAmmoBoxes[boxIndex]) end)
            end
         end
      end
   end

   -- Add 3-6 gun parts
   if #cachedGunParts > 0 then
      local numParts = ZombRand(3, 7)
      for i = 1, numParts do
         local randomIndex = ZombRand(1, #cachedGunParts + 1)
         pcall(function() container:AddItem(cachedGunParts[randomIndex]) end)
      end
   end
end

-- Register events (these are always available at server Lua load time)
Events.OnDistributionMerge.Add(initMilitaryDistributions)
Events.OnFillContainer.Add(onFillSemiTruckMilCab)
Events.OnFillContainer.Add(onFillMilitaryVehicle)
