-- W900 Cistern Context Menu Integration
-- Adds refueling options for cistern trailers with real-time fuel transfer

require "Vehicles/ISUI/ISVehiclePartMenu"
require "Vehicles/ISUI/ISVehicleMenu"
require "Vehicles/TimedActions/ISRefuelFromGasPump"
require "TimedActions/ISRefuelFromW900Cistern"
require "TimedActions/ISFillFuelPumpFromW900Cistern"
require "TimedActions/ISFillW900CisternFromHydrant"
require "TimedActions/ISTakeFluidFromW900Cistern"
require "W900_HydrantWater"
require "W900_CisternParts"

local W900CisternContext = {}
local HYDRANT_SPRITE = "street_decoration_01_12"
local RUBBER_HOSE_TYPE = "RubberHose"
local DRAIN_TARGET_NAME_OVERRIDES = {
    RainCollector_Tarp = "ContextMenu_W900RainCollectorCrateTarp",
    RainCollectorRound_Tarp = "ContextMenu_W900RainCollectorBarrelTarp",
    RainCollectorRound_TarpClosed = "ContextMenu_W900RainCollectorBarrelTarp",
    carpentry_02_120 = "ContextMenu_W900RainCollectorCrateTarp",
    carpentry_02_124 = "ContextMenu_W900RainCollectorBarrelTarp",
    carpentry_02_127 = "ContextMenu_W900RainCollectorBarrelTarp",
}

local function getDrainTargetNameOverride(name)
    local key = name and DRAIN_TARGET_NAME_OVERRIDES[name] or nil
    if not key then
        return nil
    end

    return getText(key)
end

local function isBlacklistedFuelPumpFillTarget(obj)
    if not obj then
        return false
    end

    local candidateNames = {}
    if obj.getObjectName then
        local ok, objectName = pcall(function()
            return obj:getObjectName()
        end)
        if ok and objectName and objectName ~= "" then
            table.insert(candidateNames, objectName)
        end
    end

    if obj.getName then
        local ok, name = pcall(function()
            return obj:getName()
        end)
        if ok and name and name ~= "" then
            table.insert(candidateNames, name)
        end
    end

    local sprite = obj.getSprite and obj:getSprite() or nil
    local spriteName = sprite and sprite:getName() or nil
    if spriteName and spriteName ~= "" then
        table.insert(candidateNames, spriteName)
    end

    for _, candidateName in ipairs(candidateNames) do
        if DRAIN_TARGET_NAME_OVERRIDES[candidateName] then
            return true
        end

        local loweredName = string.lower(candidateName)
        if string.find(loweredName, "raincollector", 1, true)
            or string.find(loweredName, "rain collector", 1, true)
            or string.find(loweredName, "barrel", 1, true) then
            return true
        end
    end

    return false
end

local function isPoweredFuelPump(obj)
    if not obj or obj:getPipedFuelAmount() <= 0 then
        return false
    end

    local square = obj:getSquare()
    return square and ((SandboxVars.AllowExteriorGenerator and square:haveElectricity()) or square:hasGridPower())
end

local function isNamedFuelPump(obj)
    if not obj then
        return false
    end

    if obj.getObjectName then
        local ok, objectName = pcall(function()
            return obj:getObjectName()
        end)
        if ok and (objectName == "FuelPump" or objectName == "Fuel Pump") then
            return true
        end
    end

    if obj.getName then
        local ok, name = pcall(function()
            return obj:getName()
        end)
        if ok and (name == "FuelPump" or name == "Fuel Pump") then
            return true
        end
    end

    local sprite = obj.getSprite and obj:getSprite() or nil
    local spriteName = sprite and sprite:getName() or nil
    return spriteName ~= nil and string.find(spriteName, "location_shop_gas2go_01_", 1, true) == 1
end

local function isFuelPumpFillTarget(obj)
    if not obj
        or not obj.getPipedFuelAmount
        or not obj.setPipedFuelAmount
        or not obj.getSquare
        or obj:getSquare() == nil then
        return false
    end

    if isBlacklistedFuelPumpFillTarget(obj) then
        return false
    end

    if isPoweredFuelPump(obj) then
        return true
    end

    if isNamedFuelPump(obj) then
        return true
    end

    if not obj.getFluidContainer then
        return false
    end

    local ok, fluidContainer = pcall(function()
        return obj:getFluidContainer()
    end)

    return ok
        and fluidContainer ~= nil
        and fluidContainer:canAddFluid(Fluid.Petrol)
end

W900CisternContext.isSplitCisternVehicle = W900CisternParts.isSplitCisternVehicle

W900CisternContext.isValidVehicleGasDestination = W900CisternParts.isValidVehicleGasDestination

-- Store original function
if not W900CisternContext.originalFillPartMenu then
    W900CisternContext.originalFillPartMenu = ISVehicleMenu.FillPartMenu
end

-- Find nearby fuel pump for any type of fuel tank
function W900CisternContext.getNearbyFuelPump(vehicle)
    local part = W900CisternParts.getGasTankPart(vehicle)

    if W900CisternContext.isSplitCisternVehicle(vehicle) then
        if not W900CisternContext.isCisternGasSourcePart(part) then
            return nil
        end
    else
        part = vehicle:getPartById("GasTank")
    end
    
    if not part then return nil end
    
    local areaCenter = vehicle:getAreaCenter(part:getArea())
    if not areaCenter then return nil end
    
    local square = getCell():getGridSquare(areaCenter:getX(), areaCenter:getY(), vehicle:getZ())
    if not square then return nil end
    
    -- Search in a 5x5 grid around the fuel tank
    for dy=-2,2 do
        for dx=-2,2 do
            local square2 = getCell():getGridSquare(square:getX() + dx, square:getY() + dy, square:getZ())
            if square2 and square2:getObjects() then
                for i=0, square2:getObjects():size()-1 do
                    local obj = square2:getObjects():get(i)
                    if isPoweredFuelPump(obj) then
                        return obj
                    end
                end
            end
        end
    end
    
    return nil
end

function W900CisternContext.getNearbyFuelPumpFillTarget(vehicle)
    local part = W900CisternParts.getGasTankPart(vehicle)
    if not W900CisternContext.isCisternGasSourcePart(part) then return nil end

    local nearbyFuelPump = W900CisternContext.getNearbyFuelPump(vehicle)
    if nearbyFuelPump and nearbyFuelPump.setPipedFuelAmount then
        return nearbyFuelPump
    end

    local areaCenter = vehicle:getAreaCenter(part:getArea())
    if not areaCenter then return nil end

    local square = getCell():getGridSquare(areaCenter:getX(), areaCenter:getY(), vehicle:getZ())
    if not square then return nil end

    for dy=-2,2 do
        for dx=-2,2 do
            local square2 = getCell():getGridSquare(square:getX() + dx, square:getY() + dy, square:getZ())
            if square2 and square2:getObjects() then
                for i=0, square2:getObjects():size()-1 do
                    local obj = square2:getObjects():get(i)
                    if isFuelPumpFillTarget(obj) then
                        return obj
                    end
                end
            end
        end
    end

    return nil
end

function W900CisternContext.hasRubberHose(playerObj)
    return playerObj and playerObj:getInventory() and playerObj:getInventory():containsTypeRecurse(RUBBER_HOSE_TYPE)
end

function W900CisternContext.getFluidTypeForPart(part)
    if not part then return nil end
    local contentType = part:getContainerContentType()
    if contentType == "Gasoline" then
        return Fluid.Petrol
    end
    if contentType == "Water" then
        return Fluid.Water
    end
    return nil
end

function W900CisternContext.isHydrantFillTarget(part)
    return W900CisternParts.isHydrantFillTarget(part)
end

function W900CisternContext.isCisternGasSourcePart(part)
    return W900CisternParts.isValidGasSourcePart(part)
end

function W900CisternContext.getHydrantFillLabel(playerObj)
    if W900CisternContext.hasRubberHose(playerObj) then
        return getText("ContextMenu_VehicleFillCisternWaterTank")
    end

    return getText("ContextMenu_VehicleFillCisternWaterTankNeedHose")
end

function W900CisternContext.isVehicleTankItem(item)
    if not item then return false end

    local fullType = item.getFullType and item:getFullType() or nil
    if fullType == "Base.Tank2000_2" or fullType == "Base.Tank2000W_2" then
        return true
    end

    return false
end

function W900CisternContext.getDrainTargetFluidContainer(target)
    local ref = target and target.ref or nil
    if not ref or not ref.getFluidContainer then
        return nil
    end

    local ok, fluidContainer = pcall(function()
        return ref:getFluidContainer()
    end)
    if ok then
        return fluidContainer
    end

    return nil
end

function W900CisternContext.getDrainTargetName(target)
    local ref = target and target.ref or nil
    if not ref then
        return getText("ContextMenu_W900CisternContainer")
    end

    if ref.getName then
        local ok, name = pcall(function()
            return ref:getName()
        end)
        if ok and name and name ~= "" then
            return getDrainTargetNameOverride(name) or name
        end
    end

    if ref.getObjectName then
        local ok, name = pcall(function()
            return ref:getObjectName()
        end)
        if ok and name and name ~= "" then
            return getDrainTargetNameOverride(name) or name
        end
    end

    local sprite = ref.getSprite and ref:getSprite() or nil
    if sprite and sprite:getName() then
        return getDrainTargetNameOverride(sprite:getName()) or sprite:getName()
    end

    return getText("ContextMenu_W900CisternContainer")
end

function W900CisternContext.getDrainTargetIconTexture(target)
    local ref = target and target.ref or nil
    if not ref then
        return nil
    end

    if target.kind == "inventoryItem" and ref.getTex then
        local ok, texture = pcall(function()
            return ref:getTex()
        end)
        if ok and texture then
            return texture
        end
    end

    local sprite = ref.getSprite and ref:getSprite() or nil
    local spriteName = sprite and sprite:getName() or nil
    if spriteName and spriteName ~= "" then
        local texture = getTexture(spriteName)
        if texture and texture.splitIcon then
            return texture:splitIcon()
        end
        return texture
    end

    return nil
end

function W900CisternContext.isCompatibleWorldDrainTarget(obj, fluidType)
    if not obj or not obj.getSquare or not obj:getSquare() then
        return false
    end

    local fluidContainer = W900CisternContext.getDrainTargetFluidContainer({ ref = obj })
    if not fluidContainer or fluidContainer:getFreeCapacity() <= 0 then
        return false
    end

    if fluidContainer:canAddFluid(fluidType) then
        return true
    end

    local amount = fluidContainer.getAmount and fluidContainer:getAmount() or 0
    return amount > 0 and obj.emptyFluid and obj.addFluid
end

function W900CisternContext.getNearbyWorldDrainTargets(vehicle, part, fluidType)
    local targets = {}
    if not vehicle or not part or not fluidType then
        return targets
    end

    local areaCenter = vehicle:getAreaCenter(part:getArea())
    if not areaCenter then
        return targets
    end

    local square = getCell():getGridSquare(areaCenter:getX(), areaCenter:getY(), vehicle:getZ())
    if not square then
        return targets
    end

    for dy = -2, 2 do
        for dx = -2, 2 do
            local nearbySquare = getCell():getGridSquare(square:getX() + dx, square:getY() + dy, square:getZ())
            if nearbySquare and nearbySquare:getObjects() then
                for i = 0, nearbySquare:getObjects():size() - 1 do
                    local obj = nearbySquare:getObjects():get(i)
                    if W900CisternContext.isCompatibleWorldDrainTarget(obj, fluidType) then
                        table.insert(targets, {
                            kind = "worldObject",
                            ref = obj,
                        })
                    end
                end
            end
        end
    end

    return targets
end

function W900CisternContext.getCompatibleDrainContainers(playerObj, part, fluidType)
    local playerInv = playerObj:getInventory()
    local compatible = playerInv:getAllEvalRecurse(function(item)
        if W900CisternContext.isVehicleTankItem(item) then
            return false
        end
        if not item:getFluidContainer() then
            return false
        end
        if item:getFluidContainer():getFreeCapacity() <= 0 then
            return false
        end
        return item:getFluidContainer():canAddFluid(fluidType)
    end)

    local allContainers = {}
    for i=0, compatible:size() - 1 do
        table.insert(allContainers, {
            kind = "inventoryItem",
            ref = compatible:get(i),
        })
    end

    local worldTargets = W900CisternContext.getNearbyWorldDrainTargets(part and part:getVehicle() or nil, part, fluidType)
    for _, target in ipairs(worldTargets) do
        table.insert(allContainers, target)
    end

    table.sort(allContainers, function(a, b)
        return string.lower(W900CisternContext.getDrainTargetName(a)) < string.lower(W900CisternContext.getDrainTargetName(b))
    end)

    local allContainerTypes = {}
    local allContainersOfType = {}
    local previousContainer = nil
    for _, container in pairs(allContainers) do
        if previousContainer ~= nil and W900CisternContext.getDrainTargetName(container) ~= W900CisternContext.getDrainTargetName(previousContainer) then
            table.insert(allContainerTypes, allContainersOfType)
            allContainersOfType = {}
        end
        table.insert(allContainersOfType, container)
        previousContainer = container
    end
    if #allContainersOfType > 0 then
        table.insert(allContainerTypes, allContainersOfType)
    end

    return allContainers, allContainerTypes
end

function W900CisternContext.getDrainContainersByKind(allContainers, kind)
    local filtered = {}
    if not allContainers or not kind then
        return filtered
    end

    for _, container in ipairs(allContainers) do
        if container.kind == kind then
            table.insert(filtered, container)
        end
    end

    return filtered
end

function W900CisternContext.getFluidAmountText(fluidContainer)
    if not fluidContainer then
        return "0 / 0"
    end

    local amount = math.floor(fluidContainer:getAmount() * 1000) / 1000
    local capacity = math.floor(fluidContainer:getCapacity() * 1000) / 1000
    return string.format("%s / %s", amount, capacity)
end

function W900CisternContext.getDrainSliceLabel(part)
    if W900CisternContext.getFluidTypeForPart(part) == Fluid.Water then
        return getText("ContextMenu_DrainW900Cistern")
    end

    return getText("ContextMenu_VehicleSiphonGas")
end

function W900CisternContext.getDrainSliceTexture(part)
    if W900CisternContext.getFluidTypeForPart(part) == Fluid.Water then
        return getTexture("media/ui/vehicles/vehicle_water_hose.png")
    end

    return getTexture("media/ui/vehicles/gas_siphon.png")
end

function W900CisternContext.onDrainFluidRadial(playerObj, part)
    local fluidType = W900CisternContext.getFluidTypeForPart(part)
    if not fluidType then return end

    local allContainers = select(1, W900CisternContext.getCompatibleDrainContainers(playerObj, part, fluidType))
    local inventoryContainers = W900CisternContext.getDrainContainersByKind(allContainers, "inventoryItem")
    local fluidContainer = inventoryContainers[1]
    if not fluidContainer then return end

    W900CisternContext.onDrainFluid(nil, part, inventoryContainers, fluidContainer, playerObj:getPlayerNum())
end

function W900CisternContext.onDrainFluid(worldobjects, part, fluidContainerList, fluidContainer, player)
    local playerObj = getSpecificPlayer(player)
    if not W900CisternContext.hasRubberHose(playerObj) then return end
    if playerObj:getVehicle() then
        ISVehicleMenu.onExit(playerObj)
    end
    if not fluidContainer and fluidContainerList and #fluidContainerList > 1 then
        fluidContainer = table.remove(fluidContainerList, 1)
    end
    ISTimedActionQueue.add(ISPathFindAction:pathToVehicleArea(playerObj, part:getVehicle(), part:getArea()))
    if fluidContainer and part:getContainerContentAmount() > 0 then
        local actionTarget = fluidContainer
        local actionTargetList = fluidContainerList
        if fluidContainer.kind == "inventoryItem" then
            ISVehiclePartMenu.toPlayerInventory(playerObj, fluidContainer.ref)
            ISInventoryPaneContextMenu.equipWeapon(fluidContainer.ref, false, false, playerObj:getPlayerNum())
            actionTarget = fluidContainer.ref
            if actionTargetList then
                actionTargetList = {}
                for _, target in ipairs(fluidContainerList) do
                    if target.kind == "inventoryItem" then
                        table.insert(actionTargetList, target.ref)
                    else
                        table.insert(actionTargetList, target)
                    end
                end
            end
        end
        ISTimedActionQueue.add(ISTakeFluidFromW900Cistern:new(playerObj, part, actionTarget, actionTargetList, W900CisternContext.getFluidTypeForPart(part)))
    end
end

function W900CisternContext.addDrainMenu(context, part, playerObj)
    local fluidType = W900CisternContext.getFluidTypeForPart(part)
    if not fluidType then return end
    if not W900CisternParts.isInstalledPart(part) then return end
    if part:getContainerContentAmount() <= 0 then return end
    if not W900CisternContext.hasRubberHose(playerObj) then return end

    local allContainers, allContainerTypes = W900CisternContext.getCompatibleDrainContainers(playerObj, part, fluidType)
    if #allContainers == 0 then return end

    local drainOption = context:addOption(getText("ContextMenu_DrainW900Cistern"), playerObj, nil)
    local containerMenu = ISContextMenu:getNew(context)
    context:addSubMenu(drainOption, containerMenu)

    for _, containerType in pairs(allContainerTypes) do
        local destItem = containerType[1]
        local label = W900CisternContext.getDrainTargetName(destItem)
        local iconTexture = W900CisternContext.getDrainTargetIconTexture(destItem)
        if #containerType > 1 then
            local containerOption = containerMenu:addOption(label .. " (" .. #containerType .. ")", playerObj, nil)
            containerOption.iconTexture = iconTexture
            local containerTypeMenu = ISContextMenu:getNew(containerMenu)
            containerMenu:addSubMenu(containerOption, containerTypeMenu)
            local fillOneOption = containerTypeMenu:addOption(getText("ContextMenu_FillOne"), playerObj, W900CisternContext.onDrainFluid, part, nil, destItem, playerObj:getPlayerNum())
            fillOneOption.iconTexture = iconTexture
        else
            local option = containerMenu:addOption(label, playerObj, W900CisternContext.onDrainFluid, part, nil, destItem, playerObj:getPlayerNum())
            option.iconTexture = iconTexture
            local t = ISWorldObjectContextMenu.addToolTip()
            t.maxLineWidth = 512
            t.description = getText("ContextMenu_FuelCapacity") .. W900CisternContext.getFluidAmountText(W900CisternContext.getDrainTargetFluidContainer(destItem))
            option.toolTip = t
        end
    end
end

function W900CisternContext.addDrainSlice(slice, part, playerObj)
    local fluidType = W900CisternContext.getFluidTypeForPart(part)
    if not fluidType then return end
    if not W900CisternParts.isInstalledPart(part) then return end
    if part:getContainerContentAmount() <= 0 then return end

    local allContainers = select(1, W900CisternContext.getCompatibleDrainContainers(playerObj, part, fluidType))
    local inventoryContainers = W900CisternContext.getDrainContainersByKind(allContainers, "inventoryItem")
    if #inventoryContainers == 0 then
        return
    end

    if not W900CisternContext.hasRubberHose(playerObj) then
        slice:addSlice(getText("ContextMenu_VehicleNeedHose"), getTexture("Item_Petrol"))
        return
    end

    slice:addSlice(
        W900CisternContext.getDrainSliceLabel(part),
        W900CisternContext.getDrainSliceTexture(part),
        W900CisternContext.onDrainFluidRadial,
        playerObj,
        part
    )
end

function W900CisternContext.getNearbyHydrant(vehicle, part)
    if not W900CisternContext.isHydrantFillTarget(part) then return nil end
    if not part then return nil end

    local areaCenter = vehicle:getAreaCenter(part:getArea())
    if not areaCenter then return nil end

    local square = getCell():getGridSquare(areaCenter:getX(), areaCenter:getY(), vehicle:getZ())
    if not square then return nil end

    for dy=-2,2 do
        for dx=-2,2 do
            local square2 = getCell():getGridSquare(square:getX() + dx, square:getY() + dy, square:getZ())
            if square2 and square2:getObjects() then
                for i=0, square2:getObjects():size()-1 do
                    local obj = square2:getObjects():get(i)
                    local sprite = obj:getSprite()
                    if sprite and sprite:getName() == HYDRANT_SPRITE and W900HydrantWater.canUseHydrant(obj) then
                        return obj
                    end
                end
            end
        end
    end

    return nil
end

-- Find nearby W900 Cistern tanker
function W900CisternContext.findNearbyCisternTanker(playerObj, playerVehicle)
    local radius = 2
    local cell = playerObj:getCell()
    local vehicleList = cell:getVehicles()
    
    ----print(("W900: Searching for nearby cistern tanker, total vehicles: " .. vehicleList:size())
    
    for index=0, vehicleList:size()-1 do
        local vehicle = vehicleList:get(index)
        if vehicle ~= playerVehicle and W900CisternContext.isSplitCisternVehicle(vehicle) then
            local cisternPart = W900CisternParts.getGasTankPart(vehicle)
            if W900CisternContext.isCisternGasSourcePart(cisternPart) then
                ----print(("W900: Found 2000TankG, fuel amount: " .. cisternPart:getContainerContentAmount())
                local availableFuel = cisternPart and cisternPart:getContainerContentAmount() or 0

                if availableFuel > 0 then
                    local sourceArea = cisternPart and cisternPart.getArea and cisternPart:getArea() or nil
                    local areaCenter = sourceArea and vehicle:getAreaCenter(sourceArea) or nil
                    local sourceX = areaCenter and areaCenter:getX() or vehicle:getX()
                    local sourceY = areaCenter and areaCenter:getY() or vehicle:getY()
                    local playerX = math.abs(sourceX - playerObj:getX())
                    local playerY = math.abs(sourceY - playerObj:getY())
                    local distance = math.sqrt(playerX * playerX + playerY * playerY)
                    
                    ----print(("W900: Distance to cistern: " .. distance .. " (radius: " .. radius .. ")")
                    
                    if distance <= radius then
                        ----print(("W900: Cistern is in range!")
                        return cisternPart
                    end
                end
            end
        end
    end
    
    ----print(("W900: No cistern tanker found in range")
    return nil
end

-- Handle refueling from gas pump (5x faster)
function W900CisternContext.onPumpGasoline(playerObj, part)
    if playerObj:getVehicle() then
        ISVehicleMenu.onExit(playerObj)
    end
    
    local fuelStation = W900CisternContext.getNearbyFuelPump(part:getVehicle())
    if fuelStation then
        local square = fuelStation:getSquare()
        if square then
            local action = ISPathFindAction:pathToVehicleArea(playerObj, part:getVehicle(), part:getArea())
            action:setOnFail(ISVehiclePartMenu.onPumpGasolinePathFail, playerObj)
            ISTimedActionQueue.add(action)
            
            -- Create refuel action and make it 5x faster
            local refuelAction = ISRefuelFromGasPump:new(playerObj, part, fuelStation)
            refuelAction.maxTime = refuelAction.maxTime / 5  -- 5x faster
            ISTimedActionQueue.add(refuelAction)
        end
    end
end

-- Handle refueling from cistern tanker (normal speed)
function W900CisternContext.onPumpFromCistern(playerObj, part, sourcePart)
    if not W900CisternContext.isValidVehicleGasDestination(part) then
        return
    end

    if not W900CisternContext.isCisternGasSourcePart(sourcePart) then
        return
    end

    if playerObj:getVehicle() then
        ISVehicleMenu.onExit(playerObj)
    end
    
    local action = ISPathFindAction:pathToVehicleArea(playerObj, part:getVehicle(), part:getArea())
    action:setOnFail(ISVehiclePartMenu.onPumpGasolinePathFail, playerObj)
    ISTimedActionQueue.add(action)
    ISTimedActionQueue.add(ISRefuelFromW900Cistern:new(playerObj, part, sourcePart))
end

function W900CisternContext.onFillFuelPumpFromCistern(playerObj, sourcePart, fuelPump)
    if not W900CisternContext.isCisternGasSourcePart(sourcePart) then
        return
    end

    if not isFuelPumpFillTarget(fuelPump) then
        return
    end

    if playerObj:getVehicle() then
        ISVehicleMenu.onExit(playerObj)
    end

    local action = ISPathFindAction:pathToVehicleArea(playerObj, sourcePart:getVehicle(), sourcePart:getArea())
    action:setOnFail(ISVehiclePartMenu.onPumpGasolinePathFail, playerObj)
    ISTimedActionQueue.add(action)
    ISTimedActionQueue.add(ISFillFuelPumpFromW900Cistern:new(playerObj, sourcePart, fuelPump))
end

function W900CisternContext.onFillFromHydrant(playerObj, part, hydrant)
    if not W900CisternContext.isHydrantFillTarget(part) then return end
    if not W900CisternContext.hasRubberHose(playerObj) then return end
    if playerObj:getVehicle() then
        ISVehicleMenu.onExit(playerObj)
    end

    local action = ISPathFindAction:pathToVehicleArea(playerObj, part:getVehicle(), part:getArea())
    action:setOnFail(ISVehiclePartMenu.onPumpGasolinePathFail, playerObj)
    ISTimedActionQueue.add(action)

    local fillAction = ISFillW900CisternFromHydrant:new(playerObj, part, hydrant, HYDRANT_SPRITE, RUBBER_HOSE_TYPE)
    fillAction.maxTime = fillAction.maxTime / 5
    ISTimedActionQueue.add(fillAction)
end

-- Override FillPartMenu to add cistern refuel options
function ISVehicleMenu.FillPartMenu(playerIndex, context, slice, vehicle)
    ----print(("W900: FillPartMenu called for vehicle")
    
    local playerObj = getSpecificPlayer(playerIndex)
    local isSplitCistern = W900CisternContext.isSplitCisternVehicle(vehicle)

    -- Skip vanilla fuel handling on split cisterns so the inherited hidden GasTank
    -- cannot offer reversed vehicle-to-trailer refuel actions.
    if not isSplitCistern then
        W900CisternContext.originalFillPartMenu(playerIndex, context, slice, vehicle)
    end

    for i=1, vehicle:getPartCount() do
        local drainPart = vehicle:getPartByIndex(i-1)
        if W900CisternContext.isCisternGasSourcePart(drainPart) or W900CisternContext.isHydrantFillTarget(drainPart) then
            if context then
                W900CisternContext.addDrainMenu(context, drainPart, playerObj)
            end
            if slice then
                W900CisternContext.addDrainSlice(slice, drainPart, playerObj)
            end
        end
    end
    
    ----print(("W900: Checking vehicle parts, total: " .. vehicle:getPartCount())
    
    -- Now add our custom options
    for i=1, vehicle:getPartCount() do
        local part = vehicle:getPartByIndex(i-1)
        ----print(("W900: Checking part: " .. part:getId() .. ", isContainer: " .. tostring(part:isContainer()))
        
        -- For W900 Cistern (2000TankG) - Add refueling from pump
        if W900CisternContext.isCisternGasSourcePart(part) then
            ----print(("W900: Found 2000TankG, amount: " .. part:getContainerContentAmount() .. " / " .. part:getContainerCapacity())
            
            if part:getContainerContentAmount() < part:getContainerCapacity() then
                ----print(("W900: Tank not full, checking for pump")
                -- Check if near a fuel pump
                local fuelPump = W900CisternContext.getNearbyFuelPump(vehicle)
                if fuelPump then
                    ----print(("W900: Found fuel pump, adding refuel option to " .. (slice and "slice" or "context"))
                    if slice then
                        slice:addSlice(
                            getText("ContextMenu_VehicleFillCisternTank"),
                            getTexture("media/ui/vehicles/vehicle_gas_hose.png"),
                            W900CisternContext.onPumpGasoline,
                            playerObj,
                            part
                        )
                    else
                        context:addOption(
                            getText("ContextMenu_VehicleFillCisternTank"),
                            playerObj,
                            W900CisternContext.onPumpGasoline,
                            part
                        )
                    end
                else
                    ----print(("W900: No fuel pump found nearby")
                end
            end

            if part:getContainerContentAmount() > 0 then
                local fuelPumpTarget = W900CisternContext.getNearbyFuelPumpFillTarget(vehicle)
                if fuelPumpTarget then
                    if slice then
                        slice:addSlice(
                            getText("ContextMenu_FillFuelPumpFromW900Cistern"),
                            getTexture("media/textures/Icon_FuelPumpModded.png"),
                            W900CisternContext.onFillFuelPumpFromCistern,
                            playerObj,
                            part,
                            fuelPumpTarget
                        )
                    else
                        context:addOption(
                            getText("ContextMenu_FillFuelPumpFromW900Cistern"),
                            playerObj,
                            W900CisternContext.onFillFuelPumpFromCistern,
                            part,
                            fuelPumpTarget
                        )
                    end
                end
            end
        end

        if W900CisternContext.isHydrantFillTarget(part) then
            if part:getContainerContentAmount() < part:getContainerCapacity() then
                local hydrant = W900CisternContext.getNearbyHydrant(vehicle, part)
                if hydrant then
                    local hydrantLabel = W900CisternContext.getHydrantFillLabel(playerObj)
                    if slice then
                        slice:addSlice(
                            hydrantLabel,
                            getTexture("media/ui/vehicles/vehicle_water_hose.png"),
                            W900CisternContext.hasRubberHose(playerObj) and W900CisternContext.onFillFromHydrant or function() end,
                            playerObj,
                            part,
                            hydrant
                        )
                    else
                        local option = nil
                        if W900CisternContext.hasRubberHose(playerObj) then
                            option = context:addOption(
                                hydrantLabel,
                                playerObj,
                                W900CisternContext.onFillFromHydrant,
                                part,
                                hydrant
                            )
                        else
                            option = context:addOption(hydrantLabel, nil, nil)
                            option.notAvailable = true
                        end
                    end
                end
            end
        end
        
        -- For regular vehicles (GasTank) - Add option to refuel from nearby W900 Cistern
        if W900CisternContext.isValidVehicleGasDestination(part) then
            ----print(("W900: Found GasTank, amount: " .. part:getContainerContentAmount() .. " / " .. part:getContainerCapacity())
            
            if part:getContainerContentAmount() < part:getContainerCapacity() then
                ----print(("W900: GasTank not full, checking for cistern")
                -- Check if there's a W900 Cistern nearby
                local cisternSource = W900CisternContext.findNearbyCisternTanker(playerObj, vehicle)
                if cisternSource then
                    ----print(("W900: Found cistern, adding refuel option to " .. (slice and "slice" or "context"))
                    if slice then
                        slice:addSlice(
                            getText("ContextMenu_RefuelFromW900Cistern"),
                            getTexture("media/ui/vehicles/vehicle_gas_hose.png"),
                            W900CisternContext.onPumpFromCistern,
                            playerObj,
                            part,
                            cisternSource
                        )
                    else
                        context:addOption(
                            getText("ContextMenu_RefuelFromW900Cistern"),
                            playerObj,
                            W900CisternContext.onPumpFromCistern,
                            part,
                            cisternSource
                        )
                    end
                else
                    ----print(("W900: No cistern found nearby")
                end
            end
        end
    end
    
    ----print(("W900: FillPartMenu finished")
end

----print(("W900: Cistern context menu integration loaded")

return W900CisternContext
