---
-- LiftableAxleSteeringBlock
--
-- @author      nilBrain
-- @date        2026-04-05
--
-- Copyright (C) nilBrain | Philipp Jaeger, Confidential, All Rights Reserved.

LiftableAxleSteeringBlock = {}
LiftableAxleSteeringBlock.BLOCK_SMOOTH_SPEED = 0.002

local modName = g_currentModName
LiftableAxleSteeringBlock.SPEC_NAME = modName .. ".liftableAxleSteeringBlock"
LiftableAxleSteeringBlock.SPEC_TABLE_NAME = "spec_" .. modName .. ".liftableAxleSteeringBlock"

---Called while initializing the specialization
function LiftableAxleSteeringBlock.initSpecialization()
    local schema = Vehicle.xmlSchema
    schema:setXMLSpecializationType("LiftableAxleSteeringBlock")
    schema:register(XMLValueType.BOOL, "vehicle.wheels.wheelConfigurations.wheelConfiguration(?).wheels.wheel(?).steeringAxle#blockOnLift", "Block steering when lift axle is raised", false)
    schema:setXMLSpecializationType()
end

---Register all functions from the specialization that can be called on vehicle level
-- @param table vehicleType vehicle type
function LiftableAxleSteeringBlock.registerFunctions(vehicleType)
    SpecializationUtil.registerFunction(vehicleType, "isSteeringBlockedByLiftAxle", LiftableAxleSteeringBlock.isSteeringBlockedByLiftAxle)
end

---Register all function overwritings
-- @param table vehicleType vehicle type
function LiftableAxleSteeringBlock.registerOverwrittenFunctions(vehicleType)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadWheelsFromXML", LiftableAxleSteeringBlock.loadWheelsFromXML)
end

---Register all events that should be called for this specialization
-- @param table vehicleType vehicle type
function LiftableAxleSteeringBlock.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", LiftableAxleSteeringBlock)
    SpecializationUtil.registerEventListener(vehicleType, "onUpdate", LiftableAxleSteeringBlock)
end

---Checks if all prerequisite specializations are loaded
-- @param table specializations specializations
-- @return boolean hasPrerequisite true if all prerequisite specializations are loaded
function LiftableAxleSteeringBlock.prerequisitesPresent(specializations)
    local hasPrerequisite = SpecializationUtil.hasSpecialization(LiftableAxle, specializations)
    return hasPrerequisite
end

---Overwritten loadWheelsFromXML — captures original steering range per wheel
-- @param function superFunc original function
-- @param XMLFile xmlFile xml file
-- @param string key xml key
-- @param integer wheelConfigurationId wheel configuration id
function LiftableAxleSteeringBlock:loadWheelsFromXML(superFunc, xmlFile, key, wheelConfigurationId)
    superFunc(self, xmlFile, key, wheelConfigurationId)

    local spec = self[LiftableAxleSteeringBlock.SPEC_TABLE_NAME]
    local specWheels = self.spec_wheels

    spec.wheelBlockList = {}

    for wheelIndex = 1, #specWheels.wheels do
        local wheel = specWheels.wheels[wheelIndex]
        if wheel ~= nil and wheel.steering ~= nil then
            local blockOnLift = xmlFile:getBool(string.format("%s.wheels.wheel(%d).steeringAxle#blockOnLift", key, wheelIndex - 1), false)
            wheel.steering.blockOnLift = blockOnLift
            wheel.steering.blockOnLiftOriginalRotMin = wheel.steering.steeringAxleRotMin
            wheel.steering.blockOnLiftOriginalRotMax = wheel.steering.steeringAxleRotMax
            wheel.steering.blockOnLiftBlend = 0

            if blockOnLift then
                table.insert(spec.wheelBlockList, wheel)
            end
        end
    end

    if #spec.wheelBlockList == 0 then
        for wheelIndex = 1, #specWheels.wheels do
            local wheel = specWheels.wheels[wheelIndex]
            if wheel ~= nil and wheel.steering ~= nil and wheel.steering.steeringAxleScale ~= nil and wheel.steering.steeringAxleScale > 0 then
                wheel.steering.blockOnLift = true
                table.insert(spec.wheelBlockList, wheel)
            end
        end
    end
end

---Called on post load
-- @param table savegame savegame
function LiftableAxleSteeringBlock:onPostLoad(savegame)
    local spec = self[LiftableAxleSteeringBlock.SPEC_TABLE_NAME]

    if self.spec_liftableAxle.animationName == nil then
        SpecializationUtil.removeEventListener(self, "onUpdate", LiftableAxleSteeringBlock)
        return
    end

    spec.wheelBlockList = spec.wheelBlockList or {}
end

---Called on update
-- @param float dt time since last call in ms
function LiftableAxleSteeringBlock:onUpdate(dt)
    local spec = self[LiftableAxleSteeringBlock.SPEC_TABLE_NAME]

    if #spec.wheelBlockList == 0 then
        return
    end

    local blocked = self:isSteeringBlockedByLiftAxle()
    local targetBlend = blocked and 1 or 0
    local blendStep = math.min(dt * LiftableAxleSteeringBlock.BLOCK_SMOOTH_SPEED, 1)

    for _, wheel in ipairs(spec.wheelBlockList) do
        if wheel.steering ~= nil then
            wheel.steering.blockOnLiftBlend = MathUtil.lerp(wheel.steering.blockOnLiftBlend, targetBlend, blendStep)
            local alpha = 1 - wheel.steering.blockOnLiftBlend
            wheel.steering.steeringAxleRotMin = wheel.steering.blockOnLiftOriginalRotMin * alpha
            wheel.steering.steeringAxleRotMax = wheel.steering.blockOnLiftOriginalRotMax * alpha
        end
    end
end

---Returns whether the lift axle is blocking steering
-- @return boolean blocked true if axle is raised
function LiftableAxleSteeringBlock:isSteeringBlockedByLiftAxle()
    local blocked = self.spec_liftableAxle.state == false
    return blocked
end
