-- HelicopterMode.lua – FINAL FIX: No Jump Back, Smooth Braking
-- Frissítve: Ágica kérésére - VISSZAUGRÁS JAVÍTVA
-- 1. Fék: Mostantól, ha nyomod az S-t, a motorerő (heli_currentForward) gyorsabban csökken, mint ahogy a gép lassul.
--    Így amikor elengeded a gombot, nem marad "beragadva" gáz, és nem ugrik vissza a sebesség.
-- 2. 20 km/h alatti rángatózás továbbra is tiltva.
-- 3. Minden más beállítás változatlan.

HelicopterMode = {}

function HelicopterMode.prerequisitesPresent(specializations)
    return true
end

function HelicopterMode.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onLoad", HelicopterMode)
    SpecializationUtil.registerEventListener(vehicleType, "onUpdate", HelicopterMode)
    SpecializationUtil.registerEventListener(vehicleType, "onDraw", HelicopterMode)
    SpecializationUtil.registerEventListener(vehicleType, "onReadStream", HelicopterMode)
    SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", HelicopterMode)
end

function HelicopterMode:onLoad(savegame)
    self.heli_isFlying = false
    self.heli_hasLifted = false

    local function gfloat(key, default)
        local v = nil
        if self.xmlFile ~= nil then
            if self.xmlFile.getFloat ~= nil then
                v = self.xmlFile:getFloat(key)
            elseif self.xmlFile.getValue ~= nil then
                v = self.xmlFile:getValue(key)
            else
                local handle = nil
                if type(self.xmlFile) == "number" then handle = self.xmlFile
                elseif type(self.xmlFile) == "table" and self.xmlFile.handle ~= nil then handle = self.xmlFile.handle end
                if handle ~= nil then v = getXMLFloat(handle, key) end
            end
        end
        if v == nil then return default end
        return v
    end

    local spec = {}
    -- === FIZIKAI PARAMÉTEREK ===
    spec.liftForce        = gfloat("vehicle.helicopterMode#liftForce", 80)
    spec.gravityForce     = gfloat("vehicle.helicopterMode#gravityForce", -5)
    
    spec.forwardForce     = gfloat("vehicle.helicopterMode#forwardForce", 6000)
    spec.forceBackwardMax = 3000 
    
    spec.hoverForce       = gfloat("vehicle.helicopterMode#hoverForce", 24)
    spec.accelerationRate = gfloat("vehicle.helicopterMode#accelerationRate", 4.0)
    spec.yawTorque        = gfloat("vehicle.helicopterMode#yawTorque", 25)
    spec.linearDamping    = gfloat("vehicle.helicopterMode#linearDamping", 0.33)
    spec.angularDamping   = gfloat("vehicle.helicopterMode#angularDamping", 5.0)
    spec.gyroStrength     = 100.0

    spec.minSprayHeight = gfloat("vehicle.helicopterMode#minSprayHeight", 3)
    spec.maxSprayHeight = gfloat("vehicle.helicopterMode#maxSprayHeight", 13)

    spec.accelBoost           = gfloat("vehicle.helicopterMode#accelBoost", 4.5)
    spec.accelBoostUntilKmh   = gfloat("vehicle.helicopterMode#accelBoostUntilKmh", 80)

    -- A régi bonyolult fékparaméterekre már nincs szükség, de a biztonság kedvéért bent hagyom őket,
    -- hogy az XML olvasás ne törjön el, ha valaki használja.
    spec.landingAssistAlt       = gfloat("vehicle.helicopterMode#landingAssistAlt", 10.0)
    spec.landingBrakeBonus      = gfloat("vehicle.helicopterMode#landingBrakeBonus", 1.2)
    spec.airbrakeBaseGain       = gfloat("vehicle.helicopterMode#airbrakeBaseGain", 1.1)
    spec.airbrakeExtraDamping   = gfloat("vehicle.helicopterMode#airbrakeExtraDamping", 0.15)
    spec.brakeTargetTimeFrom120 = gfloat("vehicle.helicopterMode#brakeTargetTimeFrom120", 7.5)
    spec.brakeRefStartKmh       = gfloat("vehicle.helicopterMode#brakeRefStartKmh", 120.0)

    -- === VIZUÁLIS PARAMÉTEREK ===
    spec.maxBankAngle = math.rad(28)
    spec.maxPitchAngle = math.rad(20)
    spec.autoPitchAngle = math.rad(7)
    spec.autoPitchMaxSpeed = 30
    spec.bankSpeed    = 1.5
    spec.minBankHeight = 2.0
    
    -- === ANIMÁCIÓS PARAMÉTEREK ===
    spec.animSpeed = 5.0

    spec.dirtyFlag = self:getNextDirtyFlag()

    self.spec_helicopterMode = spec

    self.setHelicopterInput = HelicopterMode.setHelicopterInput
    self.setSprayerState    = HelicopterMode.setSprayerState

    self.heli_inputW = false; self.heli_inputS = false
    self.heli_inputA = false; self.heli_inputD = false
    self.heli_inputLMB = false; self.heli_inputRMB = false

    self.lastInputW = false; self.lastInputS = false
    self.lastInputA = false; self.lastInputD = false
    self.lastInputLMB = false; self.lastInputRMB = false

    self.showLowSpeedWarning = false
    self.heli_currentForward = 0
    -- A fékidőzítőkre már nincs szükség a simplified logikában

    self.heli_currentVisualRoll = 0
    self.heli_currentVisualPitch = 0
    
    local visualNode = I3DUtil.indexToObject(self.components[1].node, "0")
    if visualNode ~= nil then
        self.heli_visualNode = visualNode
    else
        print("HelicopterMode HIBA: Nem talalhato a '0' node (Main Visual)!")
    end

    self.animNodeLeftWing = I3DUtil.indexToObject(self.components[1].node, "0|10|0")
    self.curRotLeftWing = 0

    self.animNodeRightWing = I3DUtil.indexToObject(self.components[1].node, "0|10|1")
    self.curRotRightWing = 0

    self.animNodeRudder = I3DUtil.indexToObject(self.components[1].node, "0|10|30")
    self.curRotRudder = 0

    self.animNodeElevator = I3DUtil.indexToObject(self.components[1].node, "0|10|19")
    self.curRotElevator = 0

    local workAreaNode = I3DUtil.indexToObject(self.components[1].node, "0|4|0|0|0")
    if workAreaNode ~= nil then
        self.workAreaNode = workAreaNode
        setTranslation(self.workAreaNode, 4000, 0, 0)
    end
end

function HelicopterMode:onReadStream(streamId, connection)
    self.heli_inputW = streamReadBool(streamId)
    self.heli_inputS = streamReadBool(streamId)
    self.heli_inputA = streamReadBool(streamId)
    self.heli_inputD = streamReadBool(streamId)
    self.heli_inputLMB = streamReadBool(streamId)
    self.heli_inputRMB = streamReadBool(streamId)
    self.heli_currentForward = streamReadFloat32(streamId)
end

function HelicopterMode:onWriteStream(streamId, connection)
    streamWriteBool(streamId, self.heli_inputW or false)
    streamWriteBool(streamId, self.heli_inputS or false)
    streamWriteBool(streamId, self.heli_inputA or false)
    streamWriteBool(streamId, self.heli_inputD or false)
    streamWriteBool(streamId, self.heli_inputLMB or false)
    streamWriteBool(streamId, self.heli_inputRMB or false)
    streamWriteFloat32(streamId, self.heli_currentForward or 0)
end

function HelicopterMode.setHelicopterInput(self, w, s, a, d, lmb, rmb)
    local changed = (self.heli_inputW ~= w) or (self.heli_inputS ~= s) or
                    (self.heli_inputA ~= a) or (self.heli_inputD ~= d) or
                    (self.heli_inputLMB ~= lmb) or (self.heli_inputRMB ~= rmb)

    self.heli_inputW = w; self.heli_inputS = s
    self.heli_inputA = a; self.heli_inputD = d
    self.heli_inputLMB = lmb; self.heli_inputRMB = rmb
    
    if changed and self.isServer then
        self:raiseDirtyFlags(self.spec_helicopterMode.dirtyFlag)
    end
end

function HelicopterMode.setSprayerState(self, state)
    if self.workAreaNode ~= nil then
        if state then setTranslation(self.workAreaNode, 0, 0, 0)
        else setTranslation(self.workAreaNode, 4000, 0, 0) end
    end
end

local function clamp(x, a, b) if x < a then return a elseif x > b then return b else return x end end
local function sign(x) if x > 0 then return 1 elseif x < 0 then return -1 else return 0 end end
local function lerp(a, b, t) return a + (b - a) * t end

function HelicopterMode:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
    -- INPUT KEZELÉS
    if self:getIsControlled() then
        if self.isClient and self:getIsActiveForInput(true) then
            local w = Input.isKeyPressed(Input.KEY_w)
            local s = Input.isKeyPressed(Input.KEY_s)
            local a = Input.isKeyPressed(Input.KEY_a)
            local d = Input.isKeyPressed(Input.KEY_d)
            local lmb = Input.isMouseButtonPressed(Input.MOUSE_BUTTON_LEFT)
            local rmb = Input.isMouseButtonPressed(Input.MOUSE_BUTTON_RIGHT)

            if self.lastInputW ~= w or self.lastInputS ~= s or self.lastInputA ~= a or self.lastInputD ~= d
                or self.lastInputLMB ~= lmb or self.lastInputRMB ~= rmb then

                self.lastInputW = w; self.lastInputS = s
                self.lastInputA = a; self.lastInputD = d
                self.lastInputLMB = lmb; self.lastInputRMB = rmb

                self:setHelicopterInput(w, s, a, d, lmb, rmb)
                g_client:getServerConnection():sendEvent(HelicopterInputEvent.new(self, w, s, a, d, lmb, rmb))
            end
        end
    end

    local px, py, pz = getWorldTranslation(self.components[1].node)
    local groundY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, px, 0, pz)
    local altAboveGround = math.max(0, py - groundY)
    self.altAboveGround = altAboveGround

    local sprayState = altAboveGround > self.spec_helicopterMode.minSprayHeight
                    and altAboveGround <= self.spec_helicopterMode.maxSprayHeight
    self:setSprayerState(sprayState)

    -- === FIZIKA ===
    local comp = self.components[1].node
    local spec = self.spec_helicopterMode
    local speed = self:getLastSpeed() * 3.6
    local dtSec = dt / 1000

    -- 1. Emelőerő
    local dynamicHoverForce = 0
    if speed < 269 then
        local ratio = speed / 269.0
        dynamicHoverForce = lerp(-30, 3, ratio)
    elseif speed < 395 then
        local ratio = (speed - 269.0) / (395.0 - 269.0)
        dynamicHoverForce = lerp(3, 40, ratio)
    else
        dynamicHoverForce = 40
    end

    local upForce = 0
    self.showLowSpeedWarning = false
    
    if self.heli_inputRMB then
        upForce = spec.gravityForce 
    elseif self.heli_inputLMB then
        if speed < 287 then
            self.showLowSpeedWarning = true
            upForce = dynamicHoverForce 
        else
            upForce = math.max(dynamicHoverForce + 10, spec.liftForce)
            self.heli_hasLifted = true
        end
    elseif self.heli_hasLifted then
        if self.altAboveGround < 3.0 and speed < 141 then
            upForce = -5.0 
        else
            upForce = dynamicHoverForce
        end
    else
        upForce = dynamicHoverForce 
    end
    
    self.heli_isFlying = (upForce > 0)

    -- 2. Előre/Hátra vezérlés
    local baseAccel = spec.accelerationRate
    local accel = baseAccel
    if speed < (spec.accelBoostUntilKmh or 80) and self.heli_inputW then
        accel = baseAccel * (spec.accelBoost or 4.5)
    end
    local acceleration = accel * dt / 16.666

    if self.heli_inputW then
        -- Előre gyorsítás
        self.heli_currentForward = math.min(spec.forwardForce, self.heli_currentForward + acceleration)
    
    elseif self.heli_inputS then
        -- FÉK vagy TOLATÁS
        if self.heli_currentForward > 0.1 then
            -- JAVÍTÁS: EGYSZERŰSÍTETT, MEGBÍZHATÓ FÉKRENDSZER
            -- Ez kiveszi a "matekot", és csak simán, de erősen veszi el a motorerőt.
            -- Így nem marad "töltés" a rendszerben, ami visszarántaná a gépet.
            
            local brakePower = 0
            if speed > 20 then
                 -- Nagy sebességnél: Erőteljes lassítás (kb 30%-át veszi el a max erőnek másodpercenként)
                 -- Ez elég gyors ahhoz, hogy ne ragadjon be a gáz, de elég finom, hogy ne rántson.
                 brakePower = spec.forwardForce * 0.4 * dtSec 
            else
                 -- Kis sebességnél (20 alatt): Még gyorsabb ürítés a teljes megálláshoz
                 brakePower = spec.forwardForce * 0.8 * dtSec
            end
            
            self.heli_currentForward = math.max(0, self.heli_currentForward - brakePower)
            
        else
            -- TOLATÁS
            if speed < 22 then
                self.heli_currentForward = math.max(-spec.forceBackwardMax, self.heli_currentForward - (acceleration * 4.0))
            else
                self.heli_currentForward = math.max(-spec.forceBackwardMax, self.heli_currentForward)
            end
        end
    else
        -- Kigurulás (amikor nem nyomsz semmit)
        if self.heli_currentForward > 0 then self.heli_currentForward = math.max(0, self.heli_currentForward - acceleration)
        elseif self.heli_currentForward < 0 then self.heli_currentForward = math.min(0, self.heli_currentForward + acceleration) end
    end

    -- === FIZIKA ALKALMAZÁSA (CSAK SZERVER!) ===
    if self.isServer then
        local dx, _, dz = localDirectionToWorld(comp, 1, 0, 0)
        local sinDir = dx / 15; local cosDir = dz / -15
        local xForce = self.heli_currentForward * cosDir
        local zForce = self.heli_currentForward * sinDir

        -- FIZIKAI LÉGFÉK (Csak >20 km/h, hogy ne rángasson)
        if self.heli_inputS and speed > 20 then
            local air = clamp(speed / (spec.brakeRefStartKmh or 120.0), 0, 1)
            -- Kicsit erősebb fizikai fékhatás, hogy kompenzálja a motorerő gyors elvételét
            local mag = air * (spec.airbrakeBaseGain or 1.1) * 0.08 * (spec.forwardForce)
            xForce = xForce - sign(self.heli_currentForward) * mag * cosDir * dtSec
            zForce = zForce - sign(self.heli_currentForward) * mag * sinDir * dtSec
        end

        local time = g_currentMission.time / 1000
        local wave = math.sin(time * 1.5) * 5
        local fy = upForce + wave
        if self.heli_currentForward ~= 0 or upForce ~= 0 then
            addForce(comp, xForce, fy, zForce, 0, 0, 0, true)
        end
        
        local yawTorque = 0
        if self.heli_inputA then yawTorque = spec.yawTorque
        elseif self.heli_inputD then yawTorque = -spec.yawTorque end
        if yawTorque ~= 0 then addTorque(comp, 0, yawTorque, 0, true) end

        if self.heli_isFlying or upForce > -20 then
            local upX, upY, upZ = localDirectionToWorld(comp, 0, 1, 0)
            addTorque(comp, -upZ * spec.gyroStrength * 5, 0, upX * spec.gyroStrength * 5, true)
        end

        local linearD = spec.linearDamping
        if self.heli_inputS then linearD = linearD + spec.airbrakeExtraDamping end
        local angularD = spec.angularDamping
        if not self.heli_inputA and not self.heli_inputD then
            angularD = 25.0 
        end
        setLinearDamping(self.components[1].node, linearD)
        setAngularDamping(self.components[1].node, angularD)
    end

    -- === VIZUÁLIS ÉS ANIMÁCIÓK ===
    if self.heli_visualNode ~= nil then
        local targetRoll = 0
        local targetPitch = 0

        if self.altAboveGround > spec.minBankHeight then
            if self.heli_inputA then targetRoll = -spec.maxBankAngle
            elseif self.heli_inputD then targetRoll = spec.maxBankAngle end

            local speedFraction = clamp(speed / spec.autoPitchMaxSpeed, 0, 1) 
            local autoPitch = 0
            if self.heli_currentForward > 1 then 
                autoPitch = spec.autoPitchAngle * speedFraction 
            elseif self.heli_currentForward < -1 then 
                autoPitch = -spec.autoPitchAngle * speedFraction 
            end

            local manualPitch = 0
            if self.heli_inputLMB then manualPitch = -spec.maxPitchAngle
            elseif self.heli_inputRMB then manualPitch = spec.maxPitchAngle end

            targetPitch = autoPitch + manualPitch
        else
            targetRoll = 0
            targetPitch = 0
        end

        local rollDiff = targetRoll - self.heli_currentVisualRoll
        self.heli_currentVisualRoll = self.heli_currentVisualRoll + rollDiff * math.min(1, dtSec * spec.bankSpeed)
        
        local pitchDiff = targetPitch - self.heli_currentVisualPitch
        self.heli_currentVisualPitch = self.heli_currentVisualPitch + pitchDiff * math.min(1, dtSec * spec.bankSpeed)

        local _, oldRy, _ = getRotation(self.heli_visualNode)
        setRotation(self.heli_visualNode, self.heli_currentVisualPitch, oldRy, self.heli_currentVisualRoll)
    end

    -- === REPÜLŐGÉP KORMÁNYFELÜLETEK ===
    local targetRudder = 0
    if self.heli_inputA then targetRudder = math.rad(-20)
    elseif self.heli_inputD then targetRudder = math.rad(20) end
    
    if self.animNodeRudder ~= nil then
        local diff = targetRudder - self.curRotRudder
        self.curRotRudder = self.curRotRudder + diff * math.min(1, dtSec * spec.animSpeed)
        local rx, _, rz = getRotation(self.animNodeRudder)
        setRotation(self.animNodeRudder, rx, self.curRotRudder, rz)
    end

    local targetElevator = 0
    if self.heli_inputLMB then targetElevator = math.rad(-20) 
    elseif self.heli_inputRMB then targetElevator = math.rad(20) end
    
    if self.animNodeElevator ~= nil then
        local diff = targetElevator - self.curRotElevator
        self.curRotElevator = self.curRotElevator + diff * math.min(1, dtSec * spec.animSpeed)
        local _, ey, ez = getRotation(self.animNodeElevator)
        setRotation(self.animNodeElevator, self.curRotElevator, ey, ez)
    end

    local targetLeftWing = 0
    local targetRightWing = 0
    if self.heli_inputA then
        targetLeftWing = math.rad(-20); targetRightWing = math.rad(20)
    elseif self.heli_inputD then
        targetLeftWing = math.rad(20); targetRightWing = math.rad(-20)
    end

    if self.animNodeLeftWing ~= nil then
        local diff = targetLeftWing - self.curRotLeftWing
        self.curRotLeftWing = self.curRotLeftWing + diff * math.min(1, dtSec * spec.animSpeed)
        local _, wy, wz = getRotation(self.animNodeLeftWing)
        setRotation(self.animNodeLeftWing, self.curRotLeftWing, wy, wz)
    end
    if self.animNodeRightWing ~= nil then
        local diff = targetRightWing - self.curRotRightWing
        self.curRotRightWing = self.curRotRightWing + diff * math.min(1, dtSec * spec.animSpeed)
        local _, wy, wz = getRotation(self.animNodeRightWing)
        setRotation(self.animNodeRightWing, self.curRotRightWing, wy, wz)
    end
end

function HelicopterMode:onDraw()
    if self:getIsControlled() and self.showLowSpeedWarning then
        setTextColor(1, 0.2, 0.2, 1); setTextBold(true); setTextAlignment(RenderText.ALIGN_CENTER)
        renderText(0.5, 0.05, 0.025, g_i18n:getText("warning_lowHeliSpeed") or "Too low speed for lift-off!")
        setTextBold(false); setTextAlignment(RenderText.ALIGN_LEFT); setTextColor(1, 1, 1, 1)
    end

    if self.components ~= nil and self.components[1] ~= nil then
        local px, py, pz = getWorldTranslation(self.components[1].node)
        local groundY = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, px, 0, pz)
        local relativeHeight = math.max(0, py - groundY)
        local label = g_i18n:getText("heli_heightText") or "Alt"

        setTextColor(1, 1, 0, 1); setTextBold(false); setTextAlignment(RenderText.ALIGN_CENTER)
        renderText(0.5, 0.02, 0.02, label .. ": " .. string.format("%.1f", relativeHeight) .. " m")

        if self.altAboveGround ~= nil then
            if self.altAboveGround > self.spec_helicopterMode.minSprayHeight and self.altAboveGround <= self.spec_helicopterMode.maxSprayHeight then
                setTextColor(0.2, 1, 0.2, 1); setTextBold(true)
                renderText(0.5, 0.07, 0.02, g_i18n:getText("info_spray_height_ok") or "SPRAY OK")
            else
                setTextColor(1, 0.2, 0.2, 1); setTextBold(true)
                renderText(0.5, 0.07, 0.02, g_i18n:getText("info_spray_height_not_ok") or "BAD ALT")
            end
        end
        setTextAlignment(RenderText.ALIGN_LEFT); setTextColor(1, 1, 1, 1)
    end
end