----------------------------------------------------
-- FA_RidgeMarker.lua
----------------------------------------------------

FA_RidgeMarker = {}

function FA_RidgeMarker.hasRidgeMarker(vehicle)
    return vehicle.spec_ridgeMarker ~= nil
        and vehicle.spec_ridgeMarker.ridgeMarkers ~= nil
        and #vehicle.spec_ridgeMarker.ridgeMarkers > 0
end

-- Sicher pruefen ob ridgeMarkerState gesetzt werden darf.
-- GIANTS' RidgeMarker.lua greift in packetReceived auf liftedAnimTime
-- jedes Markers zu - wenn das nil ist, crasht es.
local function canSetRidgeMarkerState(vehicle)
    if not FA_RidgeMarker.hasRidgeMarker(vehicle) then return false end
    -- Auf dem Server sind Animationen nicht geladen - liftedAnimTime ist nil.
    -- Der Guard ist nur fuer den Client noetig (Crash in packetReceived).
    if not vehicle.isClient then return true end
    for _, rm in ipairs(vehicle.spec_ridgeMarker.ridgeMarkers) do
        if rm.liftedAnimTime == nil then return false end
    end
    return true
end

local function setMarkerAnim(vehicle, animName, down, snap)
    if not vehicle.getAnimationTime or not vehicle.playAnimation then return end

    local curTime = vehicle:getAnimationTime(animName)
    local speed   = down and 1 or -1
    local targetTime = down and 1.0 or 0.0

    -- Status pruefen, falls verfuegbar
    if vehicle.getIsAnimationPlaying then
        local isPlaying = vehicle:getIsAnimationPlaying(animName)
        if not isPlaying then
            -- Schon am Ziel → nichts tun (vermeidet unnoetiges Triggern)
            if down and curTime >= 0.999 then return end
            if not down and curTime <= 0.001 then return end
        end
    end

    if snap then
        -- Marker hart auf Zielposition setzen, ohne Animation.
        -- Erst Animation stoppen falls eine laeuft, dann Zeit setzen.
        if vehicle.stopAnimation then
            vehicle:stopAnimation(animName, true)
        end
        if vehicle.setAnimationTime then
            vehicle:setAnimationTime(animName, targetTime, true)
        end
        return
    end

    -- Von der aktuellen Animationszeit aus in Zielrichtung abspielen.
    -- curTime als Startwert ist wichtig: sonst springt der Marker.
    vehicle:playAnimation(animName, speed, curTime, true)
end

function FA_RidgeMarker.forceState(vehicle, side, snap)
    if not FA_RidgeMarker.hasRidgeMarker(vehicle) then return end
    local rmSpec = vehicle.spec_ridgeMarker

    -- ridgeMarkerState nur setzen wenn alle Marker korrekt initialisiert
    -- sind (liftedAnimTime vorhanden) - sonst crasht GIANTS in packetReceived.
    if canSetRidgeMarkerState(vehicle) then
        local newState
        if side == 0 then newState = 1
        elseif side == 1 then newState = 2
        elseif side == 2 then newState = 3
        elseif side == 3 then newState = 1
        end

        if newState and rmSpec.ridgeMarkerState ~= newState then
            rmSpec.ridgeMarkerState = newState
        end
    end

    -- Animationen nur auf dem Client abspielen
    if not vehicle.isClient then return end

    for i, rm in ipairs(rmSpec.ridgeMarkers) do
        local animName = rm.animName
        if animName and animName ~= "" then
            local isLeft  = animName:lower():find("left")  ~= nil
            local isRight = animName:lower():find("right") ~= nil
            local down = false
            if side == 3 then
                down = true
            elseif side == 1 and isLeft then
                down = true
            elseif side == 2 and isRight then
                down = true
            end
            setMarkerAnim(vehicle, animName, down, snap)
        end
    end
end

----------------------------------------------------
-- Action-Callback des RidgeMarkers direkt überschreiben
-- Das ist der Callback der beim Tastendruck aufgerufen wird
----------------------------------------------------
function FA_RidgeMarker.hookActionCallback(vehicle)
    if not vehicle.isClient then return end
    if not FA_RidgeMarker.hasRidgeMarker(vehicle) then return end

    local rmSpec = vehicle.spec_ridgeMarker
    if not rmSpec or not rmSpec.actionEvents then return end

    for k, ev in pairs(rmSpec.actionEvents) do
        if ev and ev.actionEventId then
            vehicle._faRmOrigCallback = ev.callback
            g_inputBinding:removeActionEvent(ev.actionEventId)
            ev.actionEventId = nil
        end
    end
    vehicle._faRmCallbackHooked = true
end

function FA_RidgeMarker.unhookActionCallback(vehicle)
    if not vehicle.isClient then return end
    if not vehicle._faRmCallbackHooked then return end

    local rmSpec = vehicle.spec_ridgeMarker
    if rmSpec and vehicle.getIsActiveForInput then
        local isActive = vehicle:getIsActiveForInput(false, true)
        if RidgeMarker and RidgeMarker.onRegisterActionEvents then
            RidgeMarker.onRegisterActionEvents(vehicle, isActive, isActive)
        end
    end

    vehicle._faRmCallbackHooked = false
    vehicle._faRmOrigCallback = nil
end

-- Manueller Seitenwechsel im auto-Modus (aus dem HUD aufrufen)
function FA_RidgeMarker.toggleSide(vehicle)
    local spec = vehicle["spec_fahrgassenAutomatik"]
    if not spec then return end
    if spec.ridgeMarkerMode ~= "auto" then return end

    if spec._rmForcedSide == 2 then
        spec._rmForcedSide = 1
    else
        spec._rmForcedSide = 2
    end
    spec._rmTotalPassCount = (spec._rmTotalPassCount or 0) + 1
    spec._rmModeChanged = true

    -- Server und andere Clients synchronisieren
    if FA_ToggleRidgeMarkerSideEvent then
        if vehicle.isServer then
            g_server:broadcastEvent(FA_ToggleRidgeMarkerSideEvent:new(vehicle, spec._rmForcedSide, spec._rmTotalPassCount), nil, nil, vehicle)
        else
            local conn = g_client and g_client:getServerConnection()
            if conn then
                conn:sendEvent(FA_ToggleRidgeMarkerSideEvent:new(vehicle, spec._rmForcedSide, spec._rmTotalPassCount))
            end
        end
    end

   -- print(string.format("[FA_RM] Manueller Toggle → side=%d", spec._rmForcedSide))
end

----------------------------------------------------
-- Nach Pass-Wechsel aufrufen
----------------------------------------------------
function FA_RidgeMarker.updateForPass(vehicle)
    local spec = vehicle["spec_fahrgassenAutomatik"]
    if not spec then return end
    if not FA_RidgeMarker.hasRidgeMarker(vehicle) then return end

    -- Gleicher Startup-Delay wie in onUpdate - DLC-Erweiterungen brauchen
    -- ein paar Frames bevor RidgeMarker-Felder sicher angefasst werden koennen.
    -- Eigener Zaehler falls onUpdate (Client) noch nicht gelaufen ist (Server).
    spec._rmServerStartupDelay = (spec._rmServerStartupDelay or 0) + 1
    if (spec._rmStartupDelay or 0) < 10 and spec._rmServerStartupDelay < 10 then
        return
    end

    -- Eingeklappt (mehr als halb gefaltet): nichts tun
    local foldTime = vehicle.spec_foldable and vehicle.spec_foldable.foldAnimTime
    if foldTime ~= nil and foldTime > 0.5 then
        return
    end

    -- Im off-Modus: kompletter Hands-Off, nichts anfassen
    local mode = spec.ridgeMarkerMode or "auto"
    if mode == "off" then
        return
    end

    FA_RidgeMarker.hookActionCallback(vehicle)

    spec._rmTotalPassCount = (spec._rmTotalPassCount or 0) + 1

    local pass    = spec.pass or 1
    local passMax = spec.passMax or spec.N or 2
    local side    = 0

    if mode == "both" then
        side = 3
    elseif mode == "left" then
        side = 1
    elseif mode == "right" then
        side = 2
    elseif mode == "auto" then
        -- Seite direkt aus dem Pass-Index berechnen (nicht aus Zaehler)
        -- damit Doppelaufrufe nicht die Seite verfaelschen.
        side = (pass % 2 == 1) and 2 or 1
    end

    spec._rmForcedSide = side

    if vehicle.isServer then
        -- Server: ridgeMarkerState sofort setzen (WorkArea)
        -- onUpdate laeuft nicht auf dem Server, also muss forceState direkt
        -- aufgerufen werden.
        FA_RidgeMarker.forceState(vehicle, side)
    end

    -- Client: _rmModeChanged setzen damit onUpdate die Animation
    -- korrekt anhand Fold/Lower-Status setzt.
    spec._rmModeChanged = true

  --  print(string.format("[FA_RM] Pass=%d/%d mode=%s → side=%d", pass, passMax, mode, side))
end

----------------------------------------------------
-- Jeden Frame aufrufen
----------------------------------------------------
function FA_RidgeMarker.onUpdate(vehicle)
    local spec = vehicle["spec_fahrgassenAutomatik"]
    if not spec then return end
    if not FA_RidgeMarker.hasRidgeMarker(vehicle) then return end

    -- Erste paar Frames nach dem Laden: RidgeMarker NICHT anfassen.
    -- DLC-Erweiterungen (z.B. Sky Agriculture WorkEffects) initialisieren
    -- ihre eigenen RidgeMarker-Felder verzoegert - wenn wir zu frueh
    -- ridgeMarkerState aendern, crasht deren update() mit nil-Arithmetik.
    spec._rmStartupDelay = (spec._rmStartupDelay or 0) + 1
    if spec._rmStartupDelay < 10 then
        return
    end

    -- Wenn die Saemaschine eingeklappt ist: KOMPLETT NICHTS TUN.
    local foldTime = vehicle.spec_foldable and vehicle.spec_foldable.foldAnimTime
    if foldTime ~= nil and foldTime > 0.5 then
        spec._rmWasFolded = true
        return
    end

    -- Nach dem Ausklappen: Zustand zuruecksetzen
    if spec._rmWasFolded then
        spec._rmWasFolded = nil
        spec._rmWasRaised = true
        spec._rmModeChanged = true
    end

    -- _rmForcedSide initialisieren wenn noch nicht gesetzt
    if spec._rmForcedSide == nil then
        local mode = spec.ridgeMarkerMode or "off"
        if mode == "off" then
            spec._rmForcedSide = 0
            return
        elseif mode == "left" then
            spec._rmForcedSide = 1
            FA_RidgeMarker.hookActionCallback(vehicle)
        elseif mode == "right" then
            spec._rmForcedSide = 2
            FA_RidgeMarker.hookActionCallback(vehicle)
        elseif mode == "both" then
            spec._rmForcedSide = 3
            FA_RidgeMarker.hookActionCallback(vehicle)
        elseif mode == "auto" then
            -- Gleiche Berechnung wie updateForPass: pass % 2
            local p = spec.pass or 1
            spec._rmForcedSide = (p % 2 == 1) and 2 or 1
            FA_RidgeMarker.hookActionCallback(vehicle)
        end

        spec._rmWasRaised = true
        FA_RidgeMarker.forceState(vehicle, 0)
    end

    local isLowered = vehicle.getIsImplementChainLowered and vehicle:getIsImplementChainLowered()
                   or vehicle.getIsLowered and vehicle:getIsLowered()
                   or false

    -- Bei Maschinen die Heben/Senken ueber Fold-Animation machen:
    -- Jede Fold-Bewegung (foldTime > 0) = angehoben/in Bewegung.
    -- Nur foldTime == 0 (komplett ausgeklappt) = abgesenkt.
    if foldTime ~= nil and foldTime > 0 then
        isLowered = false
    end

    -- off-Modus: kompletter Hands-Off, nichts anfassen.
    if (spec.ridgeMarkerMode or "off") == "off" then
        if spec._rmModeChanged then
            spec._rmModeChanged = nil
            spec._rmWasRaised = nil
            FA_RidgeMarker.unhookActionCallback(vehicle)
        end
        return
    end

    local mode = spec.ridgeMarkerMode or "off"

    FA_RidgeMarker.hookActionCallback(vehicle)

    -- Modus wurde gewechselt: sofort korrekten Zustand setzen,
    -- abhaengig davon ob die Maschine gerade gesenkt ist.
    if spec._rmModeChanged then
        spec._rmModeChanged = nil
        if isLowered then
            spec._rmWasRaised = false
            FA_RidgeMarker.forceState(vehicle, spec._rmForcedSide)
        else
            spec._rmWasRaised = true
            FA_RidgeMarker.forceState(vehicle, 0)
        end
        return
    end

    -- Angehoben: einmalig einfahren
    if not isLowered then
        if not spec._rmWasRaised then
            spec._rmWasRaised = true
            FA_RidgeMarker.forceState(vehicle, 0)

            -- Im Fahrgassen-Modus "Pause" + RM-Modus "auto":
            -- Bei jedem Anheben die Seite wechseln (kein Pass-Wechsel
            -- der das uebernehmen wuerde).
            if mode == "auto" and spec.mode == "Pause" then
                if spec._rmForcedSide == 2 then
                    spec._rmForcedSide = 1
                else
                    spec._rmForcedSide = 2
                end
                spec._rmTotalPassCount = (spec._rmTotalPassCount or 0) + 1
            end
        end
        return
    end

    -- Abgesenkt: ausfahren
    if spec._rmWasRaised then
        spec._rmWasRaised = false
        FA_RidgeMarker.forceState(vehicle, spec._rmForcedSide)
    end

    -- "beide" jeden Frame erzwingen
    if spec._rmForcedSide == 3 then
        FA_RidgeMarker.forceState(vehicle, 3)
    end
end

----------------------------------------------------
-- Nächsten Modus
----------------------------------------------------
local ridgeMarkerModes = { "auto", "left", "right", "both", "off" }

function FA_RidgeMarker.getNextMode(currentMode)
    for i, m in ipairs(ridgeMarkerModes) do
        if m == currentMode then
            return ridgeMarkerModes[(i % #ridgeMarkerModes) + 1]
        end
    end
    return "auto"
end

----------------------------------------------------
-- Label
----------------------------------------------------
function FA_RidgeMarker.getModeLabel(mode)
    local fallback = { auto="Auto", left="Links", right="Rechts", both="Beide", off="Aus" }
    local labels = {
        auto="fa_rm_auto", left="fa_rm_left", right="fa_rm_right",
        both="fa_rm_both", off="fa_rm_off",
    }
    local key = labels[mode or "auto"] or "fa_rm_auto"
    if g_i18n and g_i18n:hasText(key) then return g_i18n:getText(key) end
    return fallback[mode or "auto"] or "Auto"
end
