-- ============================================================================
-- === AdBlueSettings.Lua
-- === Mod by [LSMT] Modding Team 
-- === LS25 /FS25
-- === Script by [LSMT] BaTt3RiE @ 2025
-- === Ver 1.0.0.0
-- === Steuert die AdBlue Verbrauchseinstellungen und Synchronisation
-- ============================================================================

AdBlueSettings = {}
AdBlueSettings.SETTINGS = {}
AdBlueSettings.CONTROLS = {}

AdBlueSettingsEvent = {}
AdBlueSettingsEvent_mt = Class(AdBlueSettingsEvent, Event)

local DEBUG = false -- Setze auf true, um Debug-Logs zu aktivieren

local function debugPrint(...)
    if DEBUG then
        print(...)
    end
end

InitEventClass(AdBlueSettingsEvent, "AdBlueSettingsEvent")

function AdBlueSettingsEvent.emptyNew()
    local self = Event.new(AdBlueSettingsEvent_mt)
    return self
end

function AdBlueSettingsEvent.new(adblueUsage, customUsageFactor)
    local self = AdBlueSettingsEvent.emptyNew()
    self.adblueUsage = adblueUsage
    self.customUsageFactor = customUsageFactor or 1.0
    return self
end

function AdBlueSettingsEvent:readStream(streamId, connection)
    self.adblueUsage = streamReadInt32(streamId)
    self.customUsageFactor = streamReadFloat32(streamId)
    self:run(connection)
end

function AdBlueSettingsEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, self.adblueUsage)
    streamWriteFloat32(streamId, self.customUsageFactor)
end

function AdBlueSettingsEvent:run(connection)
    if AA_DAMAGE_UNIFIED_OPTIONS == true then
        local fromServer = connection ~= nil and connection.getIsServer ~= nil and connection:getIsServer()
        if g_server ~= nil and not fromServer
            and AAIntegration ~= nil
            and AAIntegration.isAuthorizedSettingsConnection ~= nil
            and not AAIntegration.isAuthorizedSettingsConnection(connection) then
            connection:sendEvent(AdBlueSettingsEvent.new(AdBlueSettings.adblueUsage, AdBlueSettings.customUsageFactor))
            return
        end

        local usage = math.clamp(math.floor(tonumber(self.adblueUsage) or 2), 1, 4)
        local customFactor = math.clamp(tonumber(self.customUsageFactor) or 1, 0.1, 5)
        AdBlueSettings.adblueUsage = usage
        AdBlueSettings.current = usage
        AdBlueSettings.customUsageFactor = customFactor

        if g_server ~= nil and not fromServer then
            AdBlueSettings.saveSettings()
            g_server:broadcastEvent(AdBlueSettingsEvent.new(usage, customFactor), false, connection)
        end
        return
    end

    -- Wenn Client: Einstellungen vom Server übernehmen
    if not connection:getIsServer() then
        if AdBlueSettings.isChangingSettings then
            AdBlueSettings.isChangingSettings = false
            return
        end
        
        debugPrint("AdBlue: Einstellungen vom Server empfangen - Verbrauch: " .. self.adblueUsage .. 
                   ", Custom Factor: " .. tostring(self.customUsageFactor))
              
        -- Lokale Einstellungen aktualisieren
        AdBlueSettings.adblueUsage = self.adblueUsage
        AdBlueSettings.current = self.adblueUsage
        AdBlueSettings.customUsageFactor = self.customUsageFactor
        
        -- UI aktualisieren, falls Menü geöffnet ist
        local menu = g_gui.screenControllers[InGameMenu]
        if menu ~= nil and menu.isOpen then
            for _, control in pairs(AdBlueSettings.CONTROLS or {}) do
                if control.id == "adblueUsage" then
                    local stateIndex = AdBlueSettings.getStateIndex("adblueUsage")
                    control:setState(stateIndex)
                end
            end
        end
    else
        -- Server empfängt Einstellungen von einem Client
        debugPrint("AdBlue (Server): Neue Einstellungen empfangen - Verbrauch: " .. self.adblueUsage ..
                   ", Custom Factor: " .. tostring(self.customUsageFactor))
              
        -- Lokale Einstellungen aktualisieren
        AdBlueSettings.adblueUsage = self.adblueUsage
        AdBlueSettings.current = self.adblueUsage
        AdBlueSettings.customUsageFactor = self.customUsageFactor
        
        -- An alle anderen Clients weiterleiten
        AdBlueSettings.sendSettingsToClients()
    end
end

-- AdBlue Verbrauchs-Optionen
AdBlueSettings.SETTINGS.adblueUsage = {
    ['default'] = 2, -- Index des Standardwerts (Normal)
    ['values'] = {1, 2, 3, 4},
    ['strings'] = {
        g_i18n:getText("adblue_setting_usage_low"),
        g_i18n:getText("adblue_setting_usage_normal"),
        g_i18n:getText("adblue_setting_usage_high"),
        g_i18n:getText("adblue_setting_usage_custom")
    }
}

-- Standardwert (wird später aus XML geladen)
AdBlueSettings.adblueUsage = 2  -- Normal
AdBlueSettings.current = 2
AdBlueSettings.customUsageFactor = 1.0  -- Eigener Wert (Standard 100%)
AdBlueSettings.customDialogOpen = false

-- Sende Einstellungen an alle Clients
function AdBlueSettings.sendSettingsToClients()
    if g_server ~= nil then
        -- Event für alle Clients erstellen und senden (MIT customUsageFactor)
        g_server:broadcastEvent(AdBlueSettingsEvent.new(
            AdBlueSettings.adblueUsage, 
            AdBlueSettings.customUsageFactor
        ))
        debugPrint("AdBlue: Einstellungen an alle Clients gesendet (inkl. Custom Factor)")
    end
end

function AdBlueSettings.sendSettingsToServer()
    if g_client ~= nil and not g_currentMission:getIsServer() then
        -- Client sendet Änderungen an Server (MIT customUsageFactor)
        g_client:getServerConnection():sendEvent(AdBlueSettingsEvent.new(
            AdBlueSettings.adblueUsage,
            AdBlueSettings.customUsageFactor
        ))
        debugPrint("AdBlue: Einstellungen an Server gesendet (inkl. Custom Factor)")
    end
end

-- Setze einen Wert
function AdBlueSettings.setValue(id, value)
    AdBlueSettings[id] = value
    
    -- Globale Variable aktualisieren, die vom AdblueConsumer verwendet wird
    if id == "adblueUsage" then
        AdBlueSettings.current = value
        debugPrint("AdBlue: Verbrauch auf Stufe " .. value .. " gesetzt")
    end
end

-- Hole einen Wert
function AdBlueSettings.getValue(id)
    return AdBlueSettings[id]
end

-- Dialog für eigenen Verbrauchswert
function AdBlueSettings.showCustomUsageDialog()
    if not (TextInputDialog and TextInputDialog.show) then
        print("Fehler: TextInputDialog nicht verfügbar!")
        AdBlueSettings.setValue("adblueUsage", 2)
        AdBlueSettings.customDialogOpen = false
        return
    end

    local function onTextEntered(self, text)
        AdBlueSettings.customDialogOpen = false
        
        if text and text ~= "" then
            local value = tonumber(text)
            if value and value >= 0.1 and value <= 5.0 then
                -- ERFOLG
                AdBlueSettings.customUsageFactor = value
                AdBlueSettings.isChangingSettings = true
                AdBlueSettings.saveSettings()
                
                debugPrint(string.format("AdBlue: Eigener Verbrauchsfaktor auf %.1f gesetzt", value))
                
                if g_currentMission:getIsServer() then
                    AdBlueSettings.sendSettingsToClients()
                else
                    AdBlueSettings.sendSettingsToServer()
                end
                
                -- Erfolgs-Dialog
                YesNoDialog.show(
                    function() end,
                    AdBlueSettings,
                    string.format(g_i18n:getText("adblue_success_message"), value, value * 100),
                    g_i18n:getText("adblue_success_title"),
                    g_i18n:getText("button_ok"),
                    nil
                )
                
            else
                -- FEHLER-Dialog
                YesNoDialog.show(
                    function()
                        AdBlueSettings.setValue("adblueUsage", 2)
                        
                        local menu = g_gui.screenControllers[InGameMenu]
                        if menu and menu.isOpen then
                            for _, control in pairs(AdBlueSettings.CONTROLS or {}) do
                                if control.id == "adblueUsage" then
                                    control:setState(2)
                                end
                            end
                        end
                    end,
                    AdBlueSettings,
                    string.format(g_i18n:getText("adblue_error_message"), tostring(text)),
                    g_i18n:getText("adblue_error_title"),
                    g_i18n:getText("button_ok"),
                    nil
                )
                
                debugPrint(string.format("AdBlue: Ungültiger Wert '%s' eingegeben", tostring(text)))
            end
        else
            -- Dialog abgebrochen
            debugPrint("AdBlue: Dialog abgebrochen, setze auf Normal zurück")
            AdBlueSettings.setValue("adblueUsage", 2)
            
            local menu = g_gui.screenControllers[InGameMenu]
            if menu and menu.isOpen then
                for _, control in pairs(AdBlueSettings.CONTROLS or {}) do
                    if control.id == "adblueUsage" then
                        control:setState(2)
                    end
                end
            end
        end
    end

    TextInputDialog.show(
        onTextEntered,
        AdBlueSettings,
        string.format("%.1f", AdBlueSettings.customUsageFactor),
        g_i18n:getText("adblue_dialog_title"),
        g_i18n:getText("adblue_dialog_prompt"),
        5,
        g_i18n:getText("button_ok")
    )
end

-- Finde den Index für einen bestimmten Wert
function AdBlueSettings.getStateIndex(id, value)
    local value = value or AdBlueSettings.getValue(id) 
    local values = AdBlueSettings.SETTINGS[id].values
    
    if type(value) == 'number' then
        for i, v in ipairs(values) do
            if v == value then
                return i
            end
        end
        
        -- Wenn kein exakter Treffer, nehme den nächstliegenden Wert
        local index = AdBlueSettings.SETTINGS[id].default
        local initialdiff = math.huge
        for i, v in ipairs(values) do
            local currentdiff = math.abs(v - value)
            if currentdiff < initialdiff then
                initialdiff = currentdiff
                index = i
            end 
        end
        return index
    end
    
    return AdBlueSettings.SETTINGS[id].default
end

-- Controls zum Einstellen der Einstellungen
AdBlueControls = {}

function AdBlueControls:onMenuOptionChanged(state, menuOption)
    local id = menuOption.id
    local setting = AdBlueSettings.SETTINGS
    local value = setting[id].values[state]
    
    if value ~= nil then
        local previousValue = AdBlueSettings.getValue(id)
        
        -- Speichere den neuen State
        AdBlueSettings.setValue(id, value)
        
        -- NEU: Dialog NUR öffnen wenn:
        -- 1. Custom ausgewählt wurde (value == 4)
        -- 2. Es war vorher NICHT Custom (previousValue ~= 4)
        -- 3. Dialog ist NICHT bereits offen
        if value == 4 and previousValue ~= 4 and not AdBlueSettings.customDialogOpen then
            AdBlueSettings.customDialogOpen = true  -- ← Setze Flag
            AdBlueSettings.showCustomUsageDialog()
            return
        end
        
        -- Für alle anderen Werte: Normal speichern und synchronisieren
        AdBlueSettings.isChangingSettings = true
        AdBlueSettings.saveSettings()
        
        if g_currentMission:getIsServer() then
            AdBlueSettings.sendSettingsToClients()
        else
            AdBlueSettings.sendSettingsToServer()
        end
    end
end

-- Einstellungen aus XML-Datei laden
function AdBlueSettings.loadSettings()
    local xmlFilePath = Utils.getFilename("modSettings/AdBlueSettings.xml", getUserProfileAppPath())
    
    if not fileExists(xmlFilePath) then
        return
    end
    
    local xmlFile = loadXMLFile("AdBlueXML", xmlFilePath)
    if xmlFile == 0 then
        return
    end
    
    -- AdBlue-Verbrauch laden
    local adblueUsage = getXMLInt(xmlFile, "adBlue.settings#adblueUsage")
    if adblueUsage ~= nil then
        AdBlueSettings.setValue("adblueUsage", adblueUsage)
        debugPrint("AdBlue: Verbrauchsstufe " .. adblueUsage .. " geladen")
    end
    
    -- NEU: Eigenen Verbrauchsfaktor laden
    local customFactor = getXMLFloat(xmlFile, "adBlue.settings#customUsageFactor")
    if customFactor ~= nil then
        AdBlueSettings.customUsageFactor = customFactor
        debugPrint(string.format("AdBlue: Eigener Verbrauchsfaktor %.1f geladen", customFactor))
    end
    
    delete(xmlFile)
end

-- Einstellungen in XML-Datei speichern
function AdBlueSettings.saveSettings()
    local xmlFilePath = Utils.getFilename("modSettings/AdBlueSettings.xml", getUserProfileAppPath())
    local xmlFile = nil
    
    createFolder(getUserProfileAppPath() .. "modSettings/")
    
    if fileExists(xmlFilePath) then
        xmlFile = loadXMLFile("AdBlueXML", xmlFilePath)
    else
        xmlFile = createXMLFile("AdBlueXML", xmlFilePath, "adBlue")
    end
    
    if xmlFile == 0 then
        print("AdBlue: Fehler beim Öffnen der XML-Datei.")
        return
    end
    
    -- AdBlue-Verbrauch speichern
    local adblueUsage = AdBlueSettings.adblueUsage
    setXMLInt(xmlFile, "adBlue.settings#adblueUsage", adblueUsage)
    
    -- NEU: Eigenen Verbrauchsfaktor speichern
    setXMLFloat(xmlFile, "adBlue.settings#customUsageFactor", AdBlueSettings.customUsageFactor)
    
    saveXMLFile(xmlFile)
    delete(xmlFile)
    
    debugPrint("AdBlue: Einstellungen gespeichert - Verbrauchsstufe: " .. adblueUsage)
end

-- Helfer-Funktion für FocusManager
local function updateFocusIds(element)
    if not element then
        return
    end
    element.focusId = FocusManager:serveAutoFocusId()
    for _, child in pairs(element.elements or {}) do
        updateFocusIds(child)
    end
end

-- Einstellungen ins InGame-Menü einfügen
function AdBlueSettings.injectMenu()
    local inGameMenu = g_gui.screenControllers[InGameMenu]
    if not inGameMenu then
        print("AdBlue: InGameMenu nicht gefunden!")
        return
    end
    
    local settingsPage = inGameMenu.pageSettings
    if not settingsPage then
        print("AdBlue: Settings-Page nicht gefunden!")
        return
    end
    
    local layoutToUse = settingsPage.gameSettingsLayout
    if not layoutToUse then
        print("AdBlue: gameSettingsLayout nicht gefunden!")
        return
    end
    
    -- Sektionsüberschrift erstellen
    local sectionTitle = nil
    for _, elem in ipairs(layoutToUse.elements) do
        if elem.name == "sectionHeader" then
            sectionTitle = elem:clone(layoutToUse)
            break
        end
    end
    
    if sectionTitle then
        sectionTitle:setText(g_i18n:getText("adblue_menu_section_title"))
    else
        sectionTitle = TextElement.new()
        sectionTitle:applyProfile("fs25_settingsSectionHeader", true)
        sectionTitle:setText(g_i18n:getText("adblue_menu_section_title"))
        sectionTitle.name = "sectionHeader"
        layoutToUse:addElement(sectionTitle)
    end
    
    sectionTitle.focusId = FocusManager:serveAutoFocusId()
    table.insert(settingsPage.controlsList, sectionTitle)
    AdBlueSettings.CONTROLS["sectionHeader"] = sectionTitle
    
    -- Verbrauchseinstellung erstellen
    local originalBox = settingsPage.multiVolumeVoiceBox
    if not originalBox then
        print("AdBlue: multiVolumeVoiceBox nicht gefunden!")
        return
    end
    
    -- AdBlue-Verbrauchs-Einstellung
    local usageBox = originalBox:clone(layoutToUse)
    usageBox.id = "adblueUsageBox"
    
    local usageOption = usageBox.elements[1]
    usageOption.id = "adblueUsage"
    usageOption.target = AdBlueControls
    
    usageOption:setCallback("onClickCallback", "onMenuOptionChanged")
    usageOption:setDisabled(false)
    
    local toolTip = usageOption.elements[1]
    toolTip:setText(g_i18n:getText("adblue_menu_usage_tooltip"))
    usageBox.elements[2]:setText(g_i18n:getText("adblue_menu_usage"))
    
    usageOption:setTexts(AdBlueSettings.SETTINGS.adblueUsage.strings)
    
    local usageStateIndex = AdBlueSettings.getStateIndex("adblueUsage")
    usageOption:setState(usageStateIndex)
    
    AdBlueSettings.CONTROLS["adblueUsage"] = usageOption
    
    updateFocusIds(usageBox)
    table.insert(settingsPage.controlsList, usageBox)
    
    layoutToUse:invalidateLayout()
end

-- Initialisieren, wenn das Spiel geladen ist
Mission00.loadMission00Finished = Utils.appendedFunction(Mission00.loadMission00Finished, function()
    AdBlueSettings.loadSettings()
    if AA_DAMAGE_UNIFIED_OPTIONS ~= true and g_dedicatedServer == nil then
        AdBlueSettings.injectMenu()
    end
    
    -- NEU: Auto-Sync beim Server-Start
    if g_currentMission:getIsServer() then
        AdBlueSettings.sendSettingsToClients()
        debugPrint("AdBlue: Initial-Sync an alle Clients beim Server-Start")
    end
end)
