-- ============================================================================
-- === HandToolHolderBuildings.Lua
-- === Mod by [LSMT] Modding Team 
-- === LS25 /FS25
-- === Script by [LSMT] BaTt3RiE @ 2025
-- === Ver 1.0.0.0
-- ============================================================================

print("[HandToolHolderBuildings] file loaded")

HandToolHolderBuildings = {}

local DEBUG = false

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

local modDirectory = g_currentModDirectory

function HandToolHolderBuildings.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(PlaceableHandToolHolders, specializations)
end

function HandToolHolderBuildings.registerXMLPaths(schema, baseKey)
    schema:register(XMLValueType.FLOAT, baseKey .. ".handToolHolders.handToolHolder(?)#maxRange", "Maximum range for tethered tool")
    schema:register(XMLValueType.NODE_INDEX, baseKey .. ".handToolHolders.handToolHolder(?)#visualNode", "Visual node (Diesel_Tank_1)")
    schema:register(XMLValueType.NODE_INDEX, baseKey .. ".handToolHolders.handToolHolder(?)#soundNode", "Sound node for pump ambient")
    schema:register(XMLValueType.STRING, baseKey .. ".handToolHolders.handToolHolder(?)#displaySide", "Display side (right or left)")
    SoundManager.registerSampleXMLPaths(schema, baseKey .. ".sounds", "pumpAmbient")
end

function HandToolHolderBuildings.registerEventListeners(placeableType)
    print("[HandToolHolderBuildings] registerEventListeners")
    SpecializationUtil.registerEventListener(placeableType, "onLoadFinished", HandToolHolderBuildings)
    SpecializationUtil.registerEventListener(placeableType, "onDelete", HandToolHolderBuildings)
end

function HandToolHolderBuildings.registerEvents(placeableType)
    SpecializationUtil.registerEvent(placeableType, "onHandToolVisibilityChanged")
end

function HandToolHolderBuildings.registerFunctions(placeableType)
    SpecializationUtil.registerFunction(placeableType, "setHandToolHolderVisibility", HandToolHolderBuildings.setHandToolHolderVisibility)
    SpecializationUtil.registerFunction(placeableType, "disableAutomaticRefueling", HandToolHolderBuildings.disableAutomaticRefueling)
end

function HandToolHolderBuildings:setHandToolHolderVisibility(holderIndex, visible, noEventSend)
    local spec = self.spec_handToolHolders
    
    if spec == nil or spec.handToolHolders == nil then
        return
    end
    
    local holder = spec.handToolHolders[holderIndex]
    if holder == nil then
        return
    end
    
    if holder.visualNode ~= nil and holder.visualNode ~= 0 then
        setVisibility(holder.visualNode, visible)
        debugPrint(string.format("[HandToolHolderBuildings] Holder %d visualNode visibility set to %s", holderIndex, tostring(visible)))
    end
    
    if not noEventSend then
        HandToolHolderVisibilityEvent.sendEvent(self, holderIndex, visible, noEventSend)
    end
    
    SpecializationUtil.raiseEvent(self, "onHandToolVisibilityChanged", holderIndex, visible)
end

function HandToolHolderBuildings:onLoadFinished(savegame)
    local spec = self.spec_handToolHolders
    
    if spec == nil or spec.handToolHolders == nil then
        print("[HandToolHolderBuildings] ERROR: PlaceableHandToolHolders not loaded!")
        return
    end

    -- -------------------------------------------------------------------------
    -- 1. Override setOwnerFarmId für jeden Holder - Tools bleiben SPECTATOR
    -- -------------------------------------------------------------------------
    for i, holder in ipairs(spec.handToolHolders) do
        if holder.originalSetOwnerFarmId == nil then
            holder.originalSetOwnerFarmId = holder.setOwnerFarmId
            
            function holder:setOwnerFarmId(farmId, noEventSend)
                -- Placeable darf FarmID ändern
                self.originalSetOwnerFarmId(self, farmId, noEventSend)
                
                -- ABER: HandTool bleibt IMMER SPECTATOR
                if self.spawnedHandTool ~= nil then
                    self.spawnedHandTool:setOwnerFarmId(FarmManager.SPECTATOR_FARM_ID, true)
                    debugPrint(string.format("[HandToolHolderBuildings] Holder %d: HandTool kept at SPECTATOR_FARM_ID", i))
                end
            end
            
            debugPrint(string.format("[HandToolHolderBuildings] Holder %d: setOwnerFarmId overridden", i))
        end
    end

    -- -------------------------------------------------------------------------
    -- 2. Initial auf dem Server alle Tools spawnen und auf SPECTATOR setzen
    -- -------------------------------------------------------------------------
    if g_server ~= nil then
        for i, holder in ipairs(spec.handToolHolders) do
            -- Tool spawnen falls noch nicht vorhanden
            if holder.handTool == nil and spec.spawnHandTool ~= nil then
                debugPrint(string.format("[HandToolHolderBuildings] Initial spawn for holder %d", i))
                spec:spawnHandTool(i)
            end
            
            -- Sicherstellen dass das Tool SPECTATOR ist
            if holder.spawnedHandTool ~= nil then
                holder.spawnedHandTool:setOwnerFarmId(FarmManager.SPECTATOR_FARM_ID, true)
                debugPrint(string.format("[HandToolHolderBuildings] SpawnedHandTool %d set to SPECTATOR_FARM_ID", i))
            end
            
            if holder.handTool ~= nil then
                holder.handTool:setOwnerFarmId(FarmManager.SPECTATOR_FARM_ID, true)
                debugPrint(string.format("[HandToolHolderBuildings] HandTool %d set to SPECTATOR_FARM_ID", i))
            end
        end
    end
    
    debugPrint(string.format("[HandToolHolderBuildings] Found %d holders from PlaceableHandToolHolders", #spec.handToolHolders))
    
    local buyingStation = nil
    if self.spec_buyingStation ~= nil then
        buyingStation = self.spec_buyingStation.buyingStation
        debugPrint("[HandToolHolderBuildings] BuyingStation found!")
        
        self:disableAutomaticRefueling(buyingStation)
    else
        Logging.warning("[HandToolHolderBuildings] No BuyingStation found in placeable!")
    end
    
    for i, holder in ipairs(spec.handToolHolders) do
        local key = string.format("placeable.handToolHolders.handToolHolder(%d)", i-1)
        local maxRange = self.xmlFile:getValue(key .. "#maxRange", 10)
        local visualNode = self.xmlFile:getValue(key .. "#visualNode", nil, self.components, self.i3dMappings)
        local soundNode = self.xmlFile:getValue(key .. "#soundNode", nil, self.components, self.i3dMappings)
        local displaySide = self.xmlFile:getValue(key .. "#displaySide", "right")
        
        holder.displaySide = displaySide
        holder.displayIndex = (displaySide == "left") and 0 or 1
        holder.maxRange = maxRange
        holder.visualNode = visualNode
        holder.soundNode = soundNode
        holder.holderIndex = i
        holder.buyingStation = buyingStation
        holder.placeable = self
        
        debugPrint(string.format("[HandToolHolderBuildings] Holder %d:", i))
        debugPrint(string.format("  maxRange = %.1fm", maxRange))
        debugPrint(string.format("  visualNode = %s", tostring(visualNode)))
        debugPrint(string.format("  soundNode = %s", tostring(soundNode)))
        debugPrint(string.format("  displaySide = %s (index: %d)", displaySide, holder.displayIndex))
        debugPrint(string.format("  buyingStation = %s", tostring(buyingStation ~= nil)))
        
        if self.isClient and soundNode ~= nil then
            holder.pumpAmbientSample = g_soundManager:loadSampleFromXML(
                self.xmlFile, "placeable.sounds", "pumpAmbient", self.baseDirectory,
                soundNode, 0, AudioGroup.ENVIRONMENT, self.i3dMappings, self
            )
            
            if holder.pumpAmbientSample ~= nil then
                debugPrint(string.format("[HandToolHolderBuildings] Pump ambient sound loaded for holder %d (loop from XML)", i))
            else
                print(string.format("[HandToolHolderBuildings] ERROR: Pump ambient sound NOT loaded for holder %d", i))
            end
        end

        if visualNode ~= nil and visualNode ~= 0 then
            local nodeName = getName(visualNode)
            debugPrint(string.format("  visualNode name = '%s'", tostring(nodeName)))
            setVisibility(visualNode, true)
            debugPrint("  Initial: visualNode VISIBLE")
        else
            print("  WARNING: visualNode is nil or 0 - cannot control visibility!")
        end
        
        holder.originalOnPickupHandTool = holder.onPickupHandTool
        holder.originalOnDropHandTool = holder.onDropHandTool
        
        holder.onPickupHandTool = function(self, handTool)
            debugPrint("[HandToolHolderBuildings] Tool returned to holder (onPickupHandTool)")
            
            -- Tool beim Zurücklegen wieder auf SPECTATOR setzen
            if handTool and g_server ~= nil then
                handTool:setOwnerFarmId(FarmManager.SPECTATOR_FARM_ID, true)
                debugPrint("[HandToolHolderBuildings] HandTool reset to SPECTATOR on return")
            end
            
            local placeable = self.placeable
            local result = self.originalOnPickupHandTool(self, handTool)
            
            if placeable.setHandToolHolderVisibility then
                placeable:setHandToolHolderVisibility(self.holderIndex, true)
            end
            
            if handTool and handTool.spec_tethered then
                handTool.spec_tethered.attachedHolder = nil
                debugPrint("[HandToolHolderBuildings] Tethering deactivated (tool in holder)")
            end
            
            if handTool.spec_fueling ~= nil then
                handTool:stopFueling()
                handTool.spec_fueling.buyingStation = nil
                handTool.spec_fueling.buyingStationPlaceable = nil
                debugPrint("[HandToolHolderBuildings] BuyingStation reference removed from tool")
            end

            if placeable.isClient and self.pumpAmbientSample ~= nil then
                g_soundManager:stopSample(self.pumpAmbientSample)
                debugPrint("[HandToolHolderBuildings] Pump ambient sound STOPPED (local)")
            end
            
            HandToolHolderPumpSoundEvent.sendEvent(placeable, self.holderIndex, false)

            return result
        end
        
        holder.onDropHandTool = function(self, handTool)
            debugPrint("[HandToolHolderBuildings] Tool taken from holder (onDropHandTool)")
            
            -- Beim Herausnehmen auch SPECTATOR sicherstellen
            if handTool and g_server ~= nil then
                handTool:setOwnerFarmId(FarmManager.SPECTATOR_FARM_ID, true)
                debugPrint("[HandToolHolderBuildings] HandTool kept at SPECTATOR on pickup")
            end
            
            local placeable = self.placeable
            local result = self.originalOnDropHandTool(self, handTool)
            
            if placeable.setHandToolHolderVisibility then
                placeable:setHandToolHolderVisibility(self.holderIndex, false)
            end
            
            if handTool.spec_fueling ~= nil then
                handTool.spec_fueling.totalLitersFilled = 0
                handTool.spec_fueling.totalCost = 0
                handTool.spec_fueling.lastLogTime = 0
                debugPrint("[HandToolHolderBuildings] Fueling counters reset")
            end
            
            if placeable and placeable.clearFuelingDisplayByIndex then
                placeable:clearFuelingDisplayByIndex(self.displayIndex)
                debugPrint(string.format("[HandToolHolderBuildings] Display %d cleared on tool pickup", self.displayIndex))
            end
            
            if placeable.isClient and self.pumpAmbientSample ~= nil then
                if not g_soundManager:getIsSamplePlaying(self.pumpAmbientSample) then
                    g_soundManager:playSample(self.pumpAmbientSample)
                    debugPrint("[HandToolHolderBuildings] Pump ambient sound STARTED (local)")
                end
            end
            
            HandToolHolderPumpSoundEvent.sendEvent(placeable, self.holderIndex, true)

            if handTool and handTool.spec_tethered then
                if type(handTool.setAttachedHolder) == "function" then
                    handTool:setAttachedHolder(self)
                    
                    handTool.spec_tethered.maximumRange = self.maxRange
                    handTool.spec_tethered.actionRange = self.maxRange * 0.7
                    if handTool.spec_tethered.range then
                        handTool.spec_tethered.range = self.maxRange
                    end
                    
                    debugPrint(string.format("[HandToolHolderBuildings] Tethering activated: MaxRange=%.2fm, ActionRange=%.2fm", 
                        handTool.spec_tethered.maximumRange, 
                        handTool.spec_tethered.actionRange))
                else
                    print("[HandToolHolderBuildings] WARNING: setAttachedHolder() not found!")
                end
            else
                print("[HandToolHolderBuildings] WARNING: Tool has no tethered spec!")
            end
            
            if handTool.spec_fueling ~= nil then
                handTool.spec_fueling.buyingStation = self.buyingStation
                handTool.spec_fueling.buyingStationPlaceable = placeable
                
                if self.buyingStation ~= nil then
                    debugPrint("[HandToolHolderBuildings] BuyingStation reference set in tool")
                else
                    print("[HandToolHolderBuildings] WARNING: No BuyingStation available!")
                end
            end

            return result
        end
        
        debugPrint(string.format("[HandToolHolderBuildings] Holder %d configured!", i))
    end

    debugPrint("[HandToolHolderBuildings] All holders configured!")
end

function HandToolHolderBuildings:onDelete()

    local spec = self.spec_handToolHolders
    
    if spec ~= nil and spec.handToolHolders ~= nil then
        for _, holder in ipairs(spec.handToolHolders) do
            if self.isClient and holder.pumpAmbientSample ~= nil then
                g_soundManager:deleteSample(holder.pumpAmbientSample)
                holder.pumpAmbientSample = nil
                debugPrint("[HandToolHolderBuildings] Pump ambient sound deleted")
            end
        end
    end

    local buyingStation = self.spec_buyingStation and self.spec_buyingStation.buyingStation
    
    if buyingStation == nil or buyingStation.customFuelTriggers == nil then
        return
    end
    
    debugPrint("[HandToolHolderBuildings] Removing custom fuel triggers...")
    
    for triggerName, triggerData in pairs(buyingStation.customFuelTriggers) do
        if triggerData.node ~= nil and triggerData.node ~= 0 then
            removeTrigger(triggerData.node)
            debugPrint(string.format("[HandToolHolderBuildings] Trigger '%s' removed", triggerName))
        end
    end

    buyingStation.customFuelTriggers = {}
    debugPrint("[HandToolHolderBuildings] All custom fuel triggers removed!")
end

function HandToolHolderBuildings:disableAutomaticRefueling(buyingStation)
    if buyingStation.loadTriggers ~= nil then
        for triggerIndex, loadTrigger in pairs(buyingStation.loadTriggers) do
            if loadTrigger.setIsEnabled ~= nil then
                loadTrigger:setIsEnabled(false)
                debugPrint(string.format("[HandToolHolderBuildings] LoadTrigger %d (gasStationTrigger) DISABLED!", triggerIndex))
            end
        end
    end
    
    if buyingStation.addFillLevelToFillableObject ~= nil then
        buyingStation.originalAddFillLevel = buyingStation.addFillLevelToFillableObject
        
        buyingStation.addFillLevelToFillableObject = function(self, vehicle, fillUnitIndex, fillTypeIndex, fillDelta, toolType, extraAttributes)
            debugPrint("[HandToolHolderBuildings] Automatic refueling blocked!")
            return 0
        end
        
        debugPrint("[HandToolHolderBuildings] Automatic refueling function DISABLED!")
    end
end


HandToolHolderVisibilityEvent = {}
local HandToolHolderVisibilityEvent_mt = Class(HandToolHolderVisibilityEvent, Event)

InitEventClass(HandToolHolderVisibilityEvent, "HandToolHolderVisibilityEvent")

function HandToolHolderVisibilityEvent.emptyNew()
    local self = Event.new(HandToolHolderVisibilityEvent_mt)
    return self
end

function HandToolHolderVisibilityEvent.new(placeable, holderIndex, visible)
    local self = HandToolHolderVisibilityEvent.emptyNew()
    self.placeable = placeable
    self.holderIndex = holderIndex
    self.visible = visible
    return self
end

function HandToolHolderVisibilityEvent:readStream(streamId, connection)
    self.placeable = NetworkUtil.readNodeObject(streamId)
    self.holderIndex = streamReadUInt8(streamId)
    self.visible = streamReadBool(streamId)
    self:run(connection)
end

function HandToolHolderVisibilityEvent:writeStream(streamId, connection)
    NetworkUtil.writeNodeObject(streamId, self.placeable)
    streamWriteUInt8(streamId, self.holderIndex)
    streamWriteBool(streamId, self.visible)
end

function HandToolHolderVisibilityEvent:run(connection)
    if self.placeable ~= nil and self.placeable:getIsSynchronized() then
        self.placeable:setHandToolHolderVisibility(self.holderIndex, self.visible, true)
    end
end

function HandToolHolderVisibilityEvent.sendEvent(placeable, holderIndex, visible, noEventSend)
    if noEventSend == nil or not noEventSend then
        if g_server ~= nil then
            g_server:broadcastEvent(HandToolHolderVisibilityEvent.new(placeable, holderIndex, visible), nil, nil, placeable)
        else
            g_client:getServerConnection():sendEvent(HandToolHolderVisibilityEvent.new(placeable, holderIndex, visible))
        end
    end
end

HandToolHolderPumpSoundEvent = {}
local HandToolHolderPumpSoundEvent_mt = Class(HandToolHolderPumpSoundEvent, Event)

InitEventClass(HandToolHolderPumpSoundEvent, "HandToolHolderPumpSoundEvent")

function HandToolHolderPumpSoundEvent.emptyNew()
    local self = Event.new(HandToolHolderPumpSoundEvent_mt)
    return self
end

function HandToolHolderPumpSoundEvent.new(placeable, holderIndex, play)
    local self = HandToolHolderPumpSoundEvent.emptyNew()
    self.placeable = placeable
    self.holderIndex = holderIndex
    self.play = play
    return self
end

function HandToolHolderPumpSoundEvent:readStream(streamId, connection)
    self.placeable = NetworkUtil.readNodeObject(streamId)
    self.holderIndex = streamReadUInt8(streamId)
    self.play = streamReadBool(streamId)
    self:run(connection)
end

function HandToolHolderPumpSoundEvent:writeStream(streamId, connection)
    NetworkUtil.writeNodeObject(streamId, self.placeable)
    streamWriteUInt8(streamId, self.holderIndex)
    streamWriteBool(streamId, self.play)
end

function HandToolHolderPumpSoundEvent:run(connection)
    if self.placeable ~= nil and self.placeable:getIsSynchronized() then
        local spec = self.placeable.spec_handToolHolders
        if spec ~= nil and spec.handToolHolders ~= nil then
            local holder = spec.handToolHolders[self.holderIndex]
            
            if holder ~= nil and self.placeable.isClient and holder.pumpAmbientSample ~= nil then
                if self.play then
                    if not g_soundManager:getIsSamplePlaying(holder.pumpAmbientSample) then
                        g_soundManager:playSample(holder.pumpAmbientSample)
                        debugPrint(string.format("[HandToolHolderBuildings] Pump sound STARTED (synced) for holder %d", self.holderIndex))
                    end
                else
                    g_soundManager:stopSample(holder.pumpAmbientSample)
                    debugPrint(string.format("[HandToolHolderBuildings] Pump sound STOPPED (synced) for holder %d", self.holderIndex))
                end
            end
        end
    end
    
    if not connection:getIsServer() then
        g_server:broadcastEvent(self, false, connection, self.placeable)
    end
end

function HandToolHolderPumpSoundEvent.sendEvent(placeable, holderIndex, play)
    if g_server ~= nil then
        g_server:broadcastEvent(HandToolHolderPumpSoundEvent.new(placeable, holderIndex, play), nil, nil, placeable)
    else
        g_client:getServerConnection():sendEvent(HandToolHolderPumpSoundEvent.new(placeable, holderIndex, play))
    end
end

print("[HandToolHolderPumpSoundEvent] Network event registered")