-- HelicopterMode.lua – "Heavy Takeoff" Edition
-- Frissítve: Ágica kérésére - Szigorúbb felszállás
-- 1. 0-75 km/h: -30 (súlyos) -> 3 (könnyülő)
-- 2. 75 km/h alatt a BAL KLIKK (emelkedés) TILTVA van + Figyelmeztetés!
-- 3. 75-120 km/h: 3 -> 31 (erős emelés)
-- 4. Himbilimbi mentesítő (AngularDamping = 25) aktív.

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)
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", 638)
    
    -- Alapérték az XML-ből, de a kód felülírja sebesség alapján
    spec.hoverForce       = gfloat("vehicle.helicopterMode#hoverForce", 24) 
    
    spec.accelerationRate = gfloat("vehicle.helicopterMode#accelerationRate", 2.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)

    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(10) 
    spec.autoPitchMaxSpeed = 35        
    spec.bankSpeed    = 1.5
    spec.minBankHeight = 2.0 

    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
    self.brakeActive = false
    self.brakeStartSpeedKmh = 0
    self.brakeTimer = 0

    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>0' node!")
    end

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

function HelicopterMode.setHelicopterInput(self, w, s, a, d, lmb, 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
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)
    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

                g_client:getServerConnection():sendEvent(HelicopterInputEvent.new(self, w, s, a, d, lmb, rmb))
            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)

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

            -- === 1. DINAMIKUS FELHAJTÓERŐ KALKULÁCIÓ ===
            -- Ágica kérése: Kezdésnél (-30), 75 km/h-nál (3), 120 km/h-nál (31)
            
            local dynamicHoverForce = 0
            
            if speed < 269 then
                -- 0 és 75 km/h között: -30-ról (NEHÉZ) megy fel +3-ig
                local ratio = speed / 269.0
                dynamicHoverForce = lerp(-30, 3, ratio)
            elseif speed < 395 then
                -- 75 és 120 km/h között: +3-ról megy fel +31-ig
                local ratio = (speed - 269.0) / (395.0 - 269.0)
                dynamicHoverForce = lerp(3, 37, ratio)
            else
                -- 120 km/h felett
                dynamicHoverForce = 37
            end

            -- Alkalmazzuk az erőt
            local upForce = 0
            self.showLowSpeedWarning = false
            
            if self.heli_inputRMB then
                -- Süllyedés
                upForce = spec.gravityForce 
            elseif self.heli_inputLMB then
                -- === FELSZÁLLÁS BLOKKOLÁSA ===
                if speed < 287 then
                    -- Ha nincs meg a 75 km/h, NEM ENGED felszállni
                    self.showLowSpeedWarning = true
                    -- Maradunk a dinamikus erőnél (ami ilyenkor még negatív, szóval lent tart)
                    upForce = dynamicHoverForce 
                else
                    -- Ha megvan a 75 km/h, mehet a lift
                    upForce = math.max(dynamicHoverForce + 10, spec.liftForce)
                    self.heli_hasLifted = true
                end
            elseif self.heli_hasLifted then
                -- Automata lebegés (ha már a levegőben vagyunk)
                if self.altAboveGround < 3.0 and speed < 141 then
                    -- Smart Landing: Ha nagyon lelassulsz földközelben
                    upForce = -5.0 
                else
                    -- Normál repülés a sebességfüggő erővel
                    upForce = dynamicHoverForce
                end
            else
                -- Még a földön vagyunk és nem nyomunk semmit: tapadjon a földhöz
                upForce = dynamicHoverForce 
            end

            -- === 2. ELŐRE / HÁTRA ===
            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_inputS and speed > 0.5 then
                if not self.brakeActive then
                    self.brakeActive = true; self.brakeTimer = 0
                    local ref = spec.brakeRefStartKmh or 120.0
                    self.brakeStartSpeedKmh = clamp(speed, 0, ref)
                end
            else
                self.brakeActive = false; self.brakeTimer = 0; self.brakeStartSpeedKmh = 0
            end

            if self.heli_inputW then
                self.heli_currentForward = math.min(spec.forwardForce, self.heli_currentForward + acceleration)
            elseif self.heli_inputS then
                local targetT = math.max(0.1, spec.brakeTargetTimeFrom120 or 7.5)
                self.brakeTimer = self.brakeTimer + dtSec
                local ref = spec.brakeRefStartKmh or 120.0
                local frac = clamp(self.brakeTimer / targetT, 0, 1)
                local desiredFromRef = (1.0 - frac) * ref
                local scale = (self.brakeStartSpeedKmh > 0.1) and (self.brakeStartSpeedKmh / ref) or 0.0
                local desiredSpeed = desiredFromRef * scale
                local gain = (spec.airbrakeBaseGain or 1.1)
                if self.altAboveGround < (spec.landingAssistAlt or 10.0) then
                    gain = gain * (spec.landingBrakeBonus or 1.2)
                end
                local err = speed - desiredSpeed
                local brakeStep = clamp(gain * 0.65 * (err / (ref + 0.001)) * (spec.forwardForce) * dtSec, 0, spec.forwardForce * 0.12 * dtSec)
                
                if self.heli_currentForward > 0 then self.heli_currentForward = math.max(0, self.heli_currentForward - brakeStep)
                elseif self.heli_currentForward < 0 then self.heli_currentForward = math.min(0, self.heli_currentForward + brakeStep * 0.5) end
            else
                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

            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

            if self.heli_inputS and speed > 1 then
                local air = clamp(speed / (spec.brakeRefStartKmh or 120.0), 0, 1)
                local mag = air * (spec.airbrakeBaseGain or 1.1) * 0.35 * (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
            
            -- Repülés jelző
            self.heli_isFlying = (upForce > 0)

            -- === 3. STABILIZÁLÁS ÉS VIZUÁLIS ANIMÁCIÓ ===
            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

            if self.heli_visualNode ~= nil then
                local targetRoll = 0
                local targetPitch = 0
                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
                if self.altAboveGround > spec.minBankHeight then
                    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)
                else
                    local rollDiff = 0 - self.heli_currentVisualRoll
                    self.heli_currentVisualRoll = self.heli_currentVisualRoll + rollDiff * math.min(1, dtSec * spec.bankSpeed)
                    local pitchDiff = 0 - self.heli_currentVisualPitch
                    self.heli_currentVisualPitch = self.heli_currentVisualPitch + pitchDiff * math.min(1, dtSec * spec.bankSpeed)
                end
                local _, oldRy, _ = getRotation(self.heli_visualNode)
                setRotation(self.heli_visualNode, self.heli_currentVisualPitch, oldRy, self.heli_currentVisualRoll)
            end

            -- === D: ULTRA STABILIZÁTOR (Himbilimbi-mentesítő) ===
            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(comp, linearD)
            setAngularDamping(comp, angularD)
        end
    end
end

function HelicopterMode:onDraw()
    -- ITT A FIGYELMEZTETÉS VISSZAÁLLÍTVA
    if self:getIsControlled() and self.showLowSpeedWarning then
        setTextColor(1, 0.2, 0.2, 1); setTextBold(true); setTextAlignment(RenderText.ALIGN_CENTER)
        -- A warning_lowHeliSpeed szöveget veszi az l10n-ből
        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