--===============================================================
-- FS25 ANHYDROUS AMMONIA ADDON
-- Clean FS25 + Precision Farming compatible replacement
--===============================================================

AnhydrousAmmoniaAddon = {}

local AA = AnhydrousAmmoniaAddon
AA.MOD_NAME = "FS25_AnhydrousAmmoniaAddon"
AA.SPRAY_TYPE_NAME = "ANHYDROUS"
AA.PF_INJECTED = false
AA.PF_RETRY_OBJECT_ADDED = false
AA.PF_RETRY_TIME = 0
AA.PF_RETRY_COUNT = 0
AA.PF_RETRY_MAX = 240

-- Lower this if gallons/liters drain too quickly.
-- Original was 0.0081. Current tuned rate is 0.0060 for a faster but still controlled NH3 tank drain.
AA.BASE_APPLICATION_RATE = 0.0060
AA.DEBUG_DIAGNOSTICS = true
AA.DIAG_LOGGED_SPRAY = false

local function aaPrint(text)
    print("  INFO [Anhydrous]: " .. tostring(text))
end

local function aaWarn(text)
    print("  WARNING [Anhydrous]: " .. tostring(text))
end

local function aaValueToString(value)
    if value == nil then
        return "nil"
    end

    return tostring(value)
end

local function aaLogManagerField(prefix, object, fieldName)
    if object ~= nil then
        local value = object[fieldName]
        if value ~= nil and type(value) ~= "function" then
            aaPrint(prefix .. "." .. fieldName .. " = " .. aaValueToString(value))
        end
    end
end

local function aaLogSprayTypeEntry(source, entry)
    if type(entry) ~= "table" then
        aaPrint(source .. " = " .. aaValueToString(entry))
        return
    end

    aaPrint(source .. " entry found")

    local fields = {
        "name",
        "index",
        "sprayTypeIndex",
        "fillTypeIndex",
        "fillType",
        "applicationRate",
        "usage",
        "usageRate",
        "litersPerSecond",
        "groundType",
        "sprayType",
        "baseSprayType",
        "isBaseType"
    }

    for _, fieldName in ipairs(fields) do
        if entry[fieldName] ~= nil and type(entry[fieldName]) ~= "function" then
            aaPrint(source .. "." .. fieldName .. " = " .. aaValueToString(entry[fieldName]))
        end
    end
end

local function aaFindSprayTypeEntryByName(sprayName)
    if g_sprayTypeManager == nil or sprayName == nil then
        return nil, nil
    end

    local manager = g_sprayTypeManager
    local upperName = tostring(sprayName):upper()

    local directTables = {
        "nameToSprayType",
        "nameToSprayTypeDesc",
        "sprayTypesByName",
        "sprayTypeByName",
        "sprayTypeNameToDesc"
    }

    for _, tableName in ipairs(directTables) do
        local t = manager[tableName]
        if type(t) == "table" then
            local entry = t[sprayName] or t[upperName]
            if entry ~= nil then
                return entry, tableName
            end
        end
    end

    local indexTables = {
        "nameToIndex",
        "sprayTypeNameToIndex",
        "sprayTypesNameToIndex",
        "nameToSprayTypeIndex"
    }

    for _, tableName in ipairs(indexTables) do
        local t = manager[tableName]
        if type(t) == "table" then
            local index = t[sprayName] or t[upperName]
            if index ~= nil then
                local list = manager.sprayTypes or manager.sprayTypeDescs or manager.indexToSprayType or manager.indexToSprayTypeDesc
                if type(list) == "table" and list[index] ~= nil then
                    return list[index], tableName .. " -> index " .. tostring(index)
                end

                return index, tableName
            end
        end
    end

    local listTables = {
        "sprayTypes",
        "sprayTypeDescs",
        "sprayTypeList",
        "indexToSprayType",
        "indexToSprayTypeDesc"
    }

    for _, tableName in ipairs(listTables) do
        local list = manager[tableName]
        if type(list) == "table" then
            for key, entry in pairs(list) do
                if type(entry) == "table" then
                    local entryName = entry.name or entry.sprayTypeName or entry.fillTypeName
                    if entryName ~= nil and tostring(entryName):upper() == upperName then
                        return entry, tableName .. "[" .. tostring(key) .. "]"
                    end
                end
            end
        end
    end

    return nil, nil
end

local function aaLogAnhydrousDiagnostics(context)
    if not AA.DEBUG_DIAGNOSTICS then
        return
    end

    aaPrint("Diagnostic context: " .. tostring(context))
    aaPrint("Target spray type name = " .. tostring(AA.SPRAY_TYPE_NAME))
    aaPrint("Target addon application rate = " .. tostring(AA.BASE_APPLICATION_RATE))

    if g_fillTypeManager ~= nil then
        local names = { "ANHYDROUS", "ANHYDROUSAMMONIA", "AMMONIA", "NH3" }
        for _, name in ipairs(names) do
            local index = nil
            if g_fillTypeManager.getFillTypeIndexByName ~= nil then
                index = g_fillTypeManager:getFillTypeIndexByName(name)
            end

            if index ~= nil and index ~= FillType.UNKNOWN then
                aaPrint("Detected fillType " .. name .. " index = " .. tostring(index))
            end
        end
    else
        aaWarn("Diagnostic: FillTypeManager not ready")
    end

    if g_sprayTypeManager ~= nil then
        aaLogManagerField("SprayTypeManager", g_sprayTypeManager, "loadedMapData")
        aaLogManagerField("SprayTypeManager", g_sprayTypeManager, "numSprayTypes")

        local entry, source = aaFindSprayTypeEntryByName(AA.SPRAY_TYPE_NAME)
        if entry ~= nil then
            aaLogSprayTypeEntry("Existing ANHYDROUS sprayType from " .. tostring(source), entry)
        else
            aaWarn("Diagnostic: No readable ANHYDROUS sprayType entry found in known manager tables")
        end
    else
        aaWarn("Diagnostic: SprayTypeManager not ready")
    end
end

local function getAnhydrousFillType()
    if FillType ~= nil and FillType.ANHYDROUS ~= nil then
        return FillType.ANHYDROUS
    end

    if g_fillTypeManager ~= nil and g_fillTypeManager.getFillTypeIndexByName ~= nil then
        return g_fillTypeManager:getFillTypeIndexByName("ANHYDROUS")
    end

    return nil
end

local function tableHasFillTypeEntry(list, fillTypeIndex)
    if list == nil or fillTypeIndex == nil then
        return false
    end

    for _, entry in ipairs(list) do
        if entry.fillTypeIndex == fillTypeIndex then
            return true
        end
    end

    return false
end

--===============================================================
-- BASE GAME - ADD ANHYDROUS AS SPRAY TYPE
--===============================================================

local tryInjectPrecisionFarming

local function addSprayType(sprayName, appRate, spraytypeName, groundType, baseType)
    if g_sprayTypeManager == nil or g_sprayTypeManager.addSprayType == nil then
        aaWarn("SprayTypeManager not ready")
        return false
    end

    if sprayName == nil or appRate == nil or spraytypeName == nil or groundType == nil or baseType == nil then
        aaWarn("Cannot register spray type because one or more arguments are nil")
        return false
    end

    aaLogAnhydrousDiagnostics("before addSprayType")

    local added = g_sprayTypeManager:addSprayType(sprayName, appRate, spraytypeName, groundType, baseType)

    if added then
        aaPrint("Added spray type " .. sprayName .. " at addon rate " .. tostring(appRate))
    else
        aaWarn("Spray type " .. tostring(sprayName) .. " already exists or could not be added; adopting existing map/mod spray type")
        aaWarn("If drain rate is wrong on this map, the existing map/mod spray type is controlling it unless we patch it later")
    end

    aaLogAnhydrousDiagnostics("after addSprayType")

    return added
end

local function appendSprayTypeManagerLoadMapData(self)
    aaPrint("Registering spray types")
    local added = addSprayType(AA.SPRAY_TYPE_NAME, AA.BASE_APPLICATION_RATE, "FERTILIZER", FieldSprayType.FERTILIZER, true)
    if added then
        aaPrint("ANHYDROUS ownership: addon registered spray type")
    else
        aaPrint("ANHYDROUS ownership: existing map/mod spray type adopted")
    end
    tryInjectPrecisionFarming()
end

if SprayTypeManager ~= nil and SprayTypeManager.loadMapData ~= nil then
    SprayTypeManager.loadMapData = Utils.appendedFunction(SprayTypeManager.loadMapData, appendSprayTypeManagerLoadMapData)
end

--===============================================================
-- PRECISION FARMING - FS25 SAFE INTEGRATION
--===============================================================

local function injectPrecisionFarmingFunctions()
    if AA.PF_INJECTED then
        return true
    end

    if g_modIsLoaded == nil or not g_modIsLoaded["FS25_precisionFarming"] then
        return false
    end

    local pf = _G["FS25_precisionFarming"]
    if pf == nil then
        return false
    end

    -- Wait until the important Precision Farming runtime classes are actually available.
    -- Some maps initialize the PF table before all PF classes are ready.
    if pf.NitrogenMap == nil or pf.NitrogenMap.loadFromXML == nil then
        return false
    end

    if pf.ExtendedSprayer == nil or pf.ExtendedSprayer.getCurrentSprayerMode == nil then
        return false
    end

    AA.PF_INJECTED = true
    aaPrint("Injecting ANHYDROUS into Precision Farming")

    ------------------------------------------------------------
    -- NitrogenMap
    ------------------------------------------------------------

    if pf.NitrogenMap ~= nil and pf.NitrogenMap.loadFromXML ~= nil then
        local function loadNitrogenMap(self, xmlFile, key, baseDirectory, configFileName, mapFilename)
            local fillTypeIndex = getAnhydrousFillType()
            if fillTypeIndex == nil then
                aaWarn("Cannot add PF nitrogen values because FillType.ANHYDROUS is missing")
                return
            end

            if self.fertilizerUsage ~= nil and self.fertilizerUsage.nAmounts ~= nil then
                if not tableHasFillTypeEntry(self.fertilizerUsage.nAmounts, fillTypeIndex) then
                    table.insert(self.fertilizerUsage.nAmounts, {
                        fillTypeIndex = fillTypeIndex,
                        amount = 0.82
                    })
                end
            end

            if self.applicationRates ~= nil then
                if not tableHasFillTypeEntry(self.applicationRates, fillTypeIndex) then
                    local amountPerState = self.amountPerState or 1

                    local applicationRate = {
                        fillTypeIndex = fillTypeIndex,
                        autoAdjustToFruit = true,
                        regularRate = 150,
                        ratesBySoilType = {}
                    }

                    table.insert(applicationRate.ratesBySoilType, { soilTypeIndex = 1, rate = 95 / amountPerState })
                    table.insert(applicationRate.ratesBySoilType, { soilTypeIndex = 2, rate = 120 / amountPerState })
                    table.insert(applicationRate.ratesBySoilType, { soilTypeIndex = 3, rate = 150 / amountPerState })
                    table.insert(applicationRate.ratesBySoilType, { soilTypeIndex = 4, rate = 110 / amountPerState })

                    table.insert(self.applicationRates, applicationRate)
                end
            end

            aaPrint("Precision Farming NitrogenMap configured for ANHYDROUS")
        end

        pf.NitrogenMap.loadFromXML = Utils.appendedFunction(pf.NitrogenMap.loadFromXML, loadNitrogenMap)
    else
        aaWarn("PF NitrogenMap hook unavailable")
    end

    ------------------------------------------------------------
    -- ExtendedSprayer mode detection
    ------------------------------------------------------------

    if pf.ExtendedSprayer ~= nil and pf.ExtendedSprayer.getCurrentSprayerMode ~= nil then
        local ExtendedSprayer = pf.ExtendedSprayer

        local function getCurrentSprayerMode(self, superFunc)
            local fillTypeIndex = getAnhydrousFillType()
            if fillTypeIndex == nil then
                return superFunc(self)
            end

            if ExtendedSprayer.getFillTypeSourceVehicle ~= nil then
                local sourceVehicle, fillUnitIndex = ExtendedSprayer.getFillTypeSourceVehicle(self)

                if sourceVehicle ~= nil and fillUnitIndex ~= nil then
                    local currentFillType = nil

                    if sourceVehicle.getFillUnitFillType ~= nil then
                        currentFillType = sourceVehicle:getFillUnitFillType(fillUnitIndex)
                    end

                    if currentFillType == nil and sourceVehicle.getFillUnitLastValidFillType ~= nil then
                        currentFillType = sourceVehicle:getFillUnitLastValidFillType(fillUnitIndex)
                    end

                    if currentFillType == fillTypeIndex then
                        -- FS25 PF ExtendedSprayer mode order matches the vehicle spec flags:
                        -- first = slurry/organic mode, second = liquid fertilizer/N mode.
                        -- NH3 must be treated as liquid fertilizer/nitrogen, not lime/pH.
                        return false, true
                    end
                end
            end

            return superFunc(self)
        end

        ExtendedSprayer.getCurrentSprayerMode = Utils.overwrittenFunction(ExtendedSprayer.getCurrentSprayerMode, getCurrentSprayerMode)
        aaPrint("Precision Farming ExtendedSprayer mode configured")
    else
        aaWarn("PF ExtendedSprayer mode hook unavailable")
    end

    ------------------------------------------------------------
    -- ExtendedSprayer farmland usage statistics
    ------------------------------------------------------------

    if pf.ExtendedSprayer ~= nil and pf.ExtendedSprayer.onEndWorkAreaProcessing ~= nil then
        local function onEndWorkAreaProcessing(self, dt, hasProcessed)
            local fillTypeIndex = getAnhydrousFillType()
            if fillTypeIndex == nil then
                return
            end

            local spec = self.spec_extendedSprayer
            local specSprayer = self.spec_sprayer

            if spec == nil or specSprayer == nil or specSprayer.workAreaParameters == nil then
                return
            end

            if not self.isServer or not specSprayer.workAreaParameters.isActive then
                return
            end

            local fillType = specSprayer.workAreaParameters.sprayFillType
            if fillType ~= fillTypeIndex then
                return
            end

            if self.getIsTurnedOn ~= nil and not self:getIsTurnedOn() then
                return
            end

            local sprayVehicle = specSprayer.workAreaParameters.sprayVehicle
            if sprayVehicle == nil and (self.getIsAIActive == nil or not self:getIsAIActive()) then
                return
            end

            if self.getPFStatisticInfo == nil then
                return
            end

            local farmlandStatistics, _, farmlandId = self:getPFStatisticInfo()
            if farmlandStatistics == nil or farmlandId == nil or farmlandStatistics.updateStatistic == nil then
                return
            end

            local usage = specSprayer.workAreaParameters.usage or 0
            local usageRegular = spec.lastRegularUsage or usage

            farmlandStatistics:updateStatistic(farmlandId, "usedLiquidFertilizer", usage)
            farmlandStatistics:updateStatistic(farmlandId, "usedLiquidFertilizerRegular", usageRegular)
        end

        pf.ExtendedSprayer.onEndWorkAreaProcessing = Utils.appendedFunction(pf.ExtendedSprayer.onEndWorkAreaProcessing, onEndWorkAreaProcessing)
        aaPrint("Precision Farming farmland statistics configured")
    end

    ------------------------------------------------------------
    -- Precision Farming HUD headline correction + construction overlay guard
    ------------------------------------------------------------
    -- Do not change input-help actions and do not change vehicle mode flags here.
    -- Courtland/PF can use the pH/lime headline while the rest of the overlay
    -- is correctly showing nitrogen. This only swaps that headline text while
    -- the active fill type is ANHYDROUS, then restores the original lime text.

    local function objectFlagIsTrue(object, names)
        if object == nil then
            return false
        end

        for _, name in ipairs(names) do
            if object[name] == true then
                return true
            end
        end

        return false
    end

    local function stringLooksLikeConstructionGui(value)
        if value == nil then
            return false
        end

        local name = tostring(value):lower()

        return name:find("construction", 1, true) ~= nil
            or name:find("build", 1, true) ~= nil
            or name:find("placeable", 1, true) ~= nil
            or name:find("landscap", 1, true) ~= nil
    end

    local function isConstructionGuiOpen()
        if g_currentMission ~= nil then
            if objectFlagIsTrue(g_currentMission, {
                "isConstructionModeActive",
                "constructionModeActive",
                "isBuildModeActive",
                "isPlaceablePlacementActive",
                "isPlacementModeActive"
            }) then
                return true
            end

            if objectFlagIsTrue(g_currentMission.construction, {
                "isActive",
                "isOpen",
                "isVisible"
            }) then
                return true
            end

            if objectFlagIsTrue(g_currentMission.constructionScreen, {
                "isActive",
                "isOpen",
                "isVisible"
            }) then
                return true
            end

            if objectFlagIsTrue(g_currentMission.placeableSystem, {
                "isActive",
                "isOpen",
                "isVisible",
                "isPlacing",
                "isPlacementActive"
            }) then
                return true
            end

            -- These are usually only set while actively placing/building.
            if g_currentMission.currentPlaceable ~= nil
                or g_currentMission.currentPlacementPlaceable ~= nil
            then
                return true
            end

            if objectFlagIsTrue(g_currentMission.placeablePlacement, {
                "isActive",
                "isOpen",
                "isVisible",
                "isPlacing",
                "isPlacementActive"
            }) then
                return true
            end

            if objectFlagIsTrue(g_currentMission.placeablePlacementController, {
                "isActive",
                "isOpen",
                "isVisible",
                "isPlacing",
                "isPlacementActive"
            }) then
                return true
            end
        end

        if objectFlagIsTrue(_G["g_constructionScreen"], {
            "isActive",
            "isOpen",
            "isVisible"
        }) then
            return true
        end

        if objectFlagIsTrue(_G["g_constructionManager"], {
            "isActive",
            "isOpen",
            "isVisible",
            "isBuildModeActive"
        }) then
            return true
        end

        if objectFlagIsTrue(_G["g_constructionController"], {
            "isActive",
            "isOpen",
            "isVisible",
            "isBuildModeActive"
        }) then
            return true
        end

        if g_gui ~= nil then
            if stringLooksLikeConstructionGui(g_gui.currentGuiName) then
                return true
            end

            if g_gui.currentGui ~= nil then
                if stringLooksLikeConstructionGui(g_gui.currentGui.name)
                    or stringLooksLikeConstructionGui(g_gui.currentGui.guiName)
                    or stringLooksLikeConstructionGui(g_gui.currentGui.className)
                then
                    return true
                end
            end

            if g_gui.currentGui ~= nil and g_gui.currentGui.target ~= nil then
                local target = g_gui.currentGui.target
                if stringLooksLikeConstructionGui(target.name)
                    or stringLooksLikeConstructionGui(target.guiName)
                    or stringLooksLikeConstructionGui(target.className)
                then
                    return true
                end
            end
        end

        return false
    end

    if pf.ExtendedSprayerHUDExtension ~= nil then
        local HUDExtension = pf.ExtendedSprayerHUDExtension
        local ExtendedSprayer = pf.ExtendedSprayer

        local function isHUDExtensionUsingAnhydrous(hudExtension)
            local fillTypeIndex = getAnhydrousFillType()
            if fillTypeIndex == nil or hudExtension == nil then
                return false
            end

            local vehicle = hudExtension.realVehicle or hudExtension.vehicle
            if vehicle == nil then
                return false
            end

            local sourceVehicle = nil
            local fillUnitIndex = nil

            if hudExtension.getFillTypeSourceVehicle ~= nil then
                local ok, source, index = pcall(function()
                    return hudExtension:getFillTypeSourceVehicle(vehicle)
                end)

                if ok then
                    sourceVehicle = source
                    fillUnitIndex = index
                end
            end

            if sourceVehicle == nil and ExtendedSprayer ~= nil and ExtendedSprayer.getFillTypeSourceVehicle ~= nil then
                local ok, source, index = pcall(function()
                    return ExtendedSprayer.getFillTypeSourceVehicle(vehicle)
                end)

                if ok then
                    sourceVehicle = source
                    fillUnitIndex = index
                end
            end

            if sourceVehicle == nil or fillUnitIndex == nil then
                return false
            end

            local currentFillType = nil

            if sourceVehicle.getFillUnitFillType ~= nil then
                local ok, fillType = pcall(function()
                    return sourceVehicle:getFillUnitFillType(fillUnitIndex)
                end)

                if ok then
                    currentFillType = fillType
                end
            end

            if currentFillType == nil and sourceVehicle.getFillUnitLastValidFillType ~= nil then
                local ok, fillType = pcall(function()
                    return sourceVehicle:getFillUnitLastValidFillType(fillUnitIndex)
                end)

                if ok then
                    currentFillType = fillType
                end
            end

            return currentFillType == fillTypeIndex
        end

        local function updateAnhydrousHUDHeadline(hudExtension)
            if hudExtension == nil or hudExtension.texts == nil then
                return
            end

            local texts = hudExtension.texts

            if texts.headline_ph_lime_ORIGINAL_ANHYDROUS == nil then
                texts.headline_ph_lime_ORIGINAL_ANHYDROUS = texts.headline_ph_lime
            end

            if isHUDExtensionUsingAnhydrous(hudExtension) then
                texts.headline_ph_lime = "Nitrogen - Anhydrous Application"
            elseif texts.headline_ph_lime_ORIGINAL_ANHYDROUS ~= nil then
                texts.headline_ph_lime = texts.headline_ph_lime_ORIGINAL_ANHYDROUS
            end
        end

        if HUDExtension.new ~= nil then
            local function new(self, superFunc, ...)
                local hudExtension = superFunc(self, ...)
                updateAnhydrousHUDHeadline(hudExtension)
                return hudExtension
            end

            HUDExtension.new = Utils.overwrittenFunction(HUDExtension.new, new)
        end

        if HUDExtension.canDraw ~= nil then
            local function canDraw(self, superFunc, ...)
                if isConstructionGuiOpen() then
                    return false
                end

                return superFunc(self, ...)
            end

            HUDExtension.canDraw = Utils.overwrittenFunction(HUDExtension.canDraw, canDraw)
        end

        if HUDExtension.draw ~= nil then
            local function draw(self, superFunc, ...)
                if isConstructionGuiOpen() then
                    return
                end

                updateAnhydrousHUDHeadline(self)
                return superFunc(self, ...)
            end

            HUDExtension.draw = Utils.overwrittenFunction(HUDExtension.draw, draw)
        end

        aaPrint("Precision Farming NH3 HUD headline and construction overlay guard configured")
    else
        aaPrint("Precision Farming construction overlay guard skipped")
    end

    return true
end

local function removePFRetryObject()
    if AA.PF_RETRY_OBJECT_ADDED
        and g_currentMission ~= nil
        and g_currentMission.removeUpdateable ~= nil
        and AA.PF_RETRY_OBJECT ~= nil
    then
        g_currentMission:removeUpdateable(AA.PF_RETRY_OBJECT)
    end

    AA.PF_RETRY_OBJECT_ADDED = false
end

AA.PF_RETRY_OBJECT = {
    update = function(self, dt)
        if AA.PF_INJECTED then
            removePFRetryObject()
            return
        end

        AA.PF_RETRY_TIME = AA.PF_RETRY_TIME + (dt or 16)
        if AA.PF_RETRY_TIME < 1000 then
            return
        end

        AA.PF_RETRY_TIME = 0
        AA.PF_RETRY_COUNT = AA.PF_RETRY_COUNT + 1

        if injectPrecisionFarmingFunctions() then
            aaPrint("Precision Farming injected after delayed map startup")
            removePFRetryObject()
            return
        end

        if AA.PF_RETRY_COUNT >= AA.PF_RETRY_MAX then
            aaWarn("Precision Farming injection retry expired; PF runtime was not available")
            removePFRetryObject()
        end
    end,

    delete = function(self)
    end
}

local function registerPFRetryObject()
    if AA.PF_INJECTED or AA.PF_RETRY_OBJECT_ADDED then
        return
    end

    if g_currentMission ~= nil and g_currentMission.addUpdateable ~= nil then
        g_currentMission:addUpdateable(AA.PF_RETRY_OBJECT)
        AA.PF_RETRY_OBJECT_ADDED = true
        AA.PF_RETRY_TIME = 0
        AA.PF_RETRY_COUNT = 0
        aaPrint("Precision Farming delayed injection watcher enabled")
    end
end

tryInjectPrecisionFarming = function()
    if not injectPrecisionFarmingFunctions() then
        registerPFRetryObject()
    end
end

local function appendTypeManagerFinalizeTypes(self)
    if self ~= nil and self.rootElementName == "vehicleTypes" then
        tryInjectPrecisionFarming()
    end
end

if TypeManager ~= nil and TypeManager.finalizeTypes ~= nil then
    TypeManager.finalizeTypes = Utils.appendedFunction(TypeManager.finalizeTypes, appendTypeManagerFinalizeTypes)
end

local function appendMissionLoadForPFInjection(self, ...)
    tryInjectPrecisionFarming()
end

if Mission00 ~= nil and Mission00.load ~= nil then
    Mission00.load = Utils.appendedFunction(Mission00.load, appendMissionLoadForPFInjection)
end

if FSBaseMission ~= nil and FSBaseMission.loadMapData ~= nil then
    FSBaseMission.loadMapData = Utils.appendedFunction(FSBaseMission.loadMapData, appendMissionLoadForPFInjection)
end

--===============================================================
-- ALLOW SELECT VEHICLES / IMPLEMENTS TO ACCEPT ONLY ANHYDROUS
--===============================================================

-- IMPORTANT:
-- Do not auto-convert every fillableImplement/fertilizingCultivator.
-- That can break base-game HUD/input-help entries on unrelated tools.
-- Only vehicles listed here are converted to NH3-only fertilizer tanks.
local anhydrousOnlyVehicles = {
    -- Add supported NH3 tanks/implements here.
    -- Every line except the last must end with a comma.
    [g_modsDirectory .. "FS25johnDeerePlanter1775NT/planter1775NT.xml"] = true
}

local function getKnownFertilizerFillTypes()
    local fillTypes = {}

    if FillType ~= nil then
        if FillType.LIQUIDFERTILIZER ~= nil then
            table.insert(fillTypes, FillType.LIQUIDFERTILIZER)
        end
        if FillType.LIQUIDMANURE ~= nil then
            table.insert(fillTypes, FillType.LIQUIDMANURE)
        end
        if FillType.DIGESTATE ~= nil then
            table.insert(fillTypes, FillType.DIGESTATE)
        end
        if FillType.FERTILIZER ~= nil then
            table.insert(fillTypes, FillType.FERTILIZER)
        end
    end

    return fillTypes
end

local function fillUnitSupportsFillType(fillUnit, fillTypeIndex)
    if fillUnit == nil or fillUnit.supportedFillTypes == nil or fillTypeIndex == nil then
        return false
    end

    return fillUnit.supportedFillTypes[fillTypeIndex] == true
end

local function fillUnitSupportsKnownFertilizer(fillUnit)
    if fillUnit == nil or fillUnit.supportedFillTypes == nil then
        return false
    end

    for _, fillTypeIndex in ipairs(getKnownFertilizerFillTypes()) do
        if fillUnitSupportsFillType(fillUnit, fillTypeIndex) then
            return true
        end
    end

    return false
end

local function setFillUnitAnhydrousOnly(fillUnit, anhydrousFillTypeIndex)
    if fillUnit == nil or fillUnit.supportedFillTypes == nil or anhydrousFillTypeIndex == nil then
        return false
    end

    -- Remove only fertilizer/manure fill types. Do NOT wipe the whole supportedFillTypes
    -- table because some FS25 HUD/input-help logic expects unrelated fill-unit metadata
    -- to remain valid.
    for _, fillTypeIndex in ipairs(getKnownFertilizerFillTypes()) do
        if fillTypeIndex ~= anhydrousFillTypeIndex then
            fillUnit.supportedFillTypes[fillTypeIndex] = nil
        end
    end

    fillUnit.supportedFillTypes[anhydrousFillTypeIndex] = true
    return true
end

local function appendLoadFillUnit(self, savegame)
    local anhydrousFillTypeIndex = getAnhydrousFillType()
    if anhydrousFillTypeIndex == nil then
        return
    end

    if self == nil or self.spec_fillUnit == nil or self.spec_fillUnit.fillUnits == nil then
        return
    end

    if self.configFileName == nil or anhydrousOnlyVehicles[self.configFileName] ~= true then
        return
    end

    local changedCount = 0

    for _, fillUnit in ipairs(self.spec_fillUnit.fillUnits) do
        -- Convert only fill units that already accepted fertilizer/manure.
        -- Seed, fuel, DEF, water, and other non-fertilizer units are left alone.
        if fillUnitSupportsKnownFertilizer(fillUnit) then
            if setFillUnitAnhydrousOnly(fillUnit, anhydrousFillTypeIndex) then
                changedCount = changedCount + 1
            end
        end
    end

    if changedCount > 0 then
        aaPrint("Configured " .. tostring(self.configFileName) .. " fertilizer fill unit(s) to accept ANHYDROUS only")
    end
end

if FillUnit ~= nil and FillUnit.onLoad ~= nil then
    FillUnit.onLoad = Utils.appendedFunction(FillUnit.onLoad, appendLoadFillUnit)
end
