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

print("[HandToolHolderBuildingsSilo] file loaded")

HandToolHolderBuildingsSilo = {}

local DEBUG = false

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

local modDirectory = g_currentModDirectory

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

function HandToolHolderBuildingsSilo.registerXMLPaths(schema, baseKey)
    schema:setXMLSpecializationType("HandToolHolderBuildingsSilo")
    schema:register(XMLValueType.FLOAT, baseKey .. ".handToolHolders.handToolHolder(?)#maxRange", "Maximum range for tethered tool", 10.0)
    schema:register(XMLValueType.NODE_INDEX, baseKey .. ".handToolHolders.handToolHolder(?)#visualNode", "Visual node")
    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)", "right")
    SoundManager.registerSampleXMLPaths(schema, baseKey .. ".sounds", "pumpAmbient")
    schema:setXMLSpecializationType()
end

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

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

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

function HandToolHolderBuildingsSilo: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("[HandToolHolderBuildingsSilo] Holder %d visualNode visibility set to %s", holderIndex, tostring(visible)))
    end
    
    if not noEventSend then
        SiloHandToolVisibilityEvent.sendEvent(self, holderIndex, visible, noEventSend)
    end
    
    SpecializationUtil.raiseEvent(self, "onHandToolVisibilityChanged", holderIndex, visible)
end

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

    for i, holder in ipairs(spec.handToolHolders) do
        if holder.originalSetOwnerFarmId == nil then
            holder.originalSetOwnerFarmId = holder.setOwnerFarmId
            
            function holder:setOwnerFarmId(farmId, noEventSend)
                self.originalSetOwnerFarmId(self, farmId, noEventSend)
                
                if self.spawnedHandTool ~= nil then
                    self.spawnedHandTool:setOwnerFarmId(FarmManager.SPECTATOR_FARM_ID, true)
                    debugPrint(string.format("[HandToolHolderBuildingsSilo] Holder %d: HandTool kept at SPECTATOR_FARM_ID", i))
                end
            end
            
            debugPrint(string.format("[HandToolHolderBuildingsSilo] Holder %d: setOwnerFarmId overridden", i))
        end
    end

    if g_server ~= nil then
        for i, holder in ipairs(spec.handToolHolders) do
            if holder.handTool == nil and spec.spawnHandTool ~= nil then
                debugPrint(string.format("[HandToolHolderBuildingsSilo] Initial spawn for holder %d", i))
                spec:spawnHandTool(i)
            end
            
            if holder.spawnedHandTool ~= nil then
                holder.spawnedHandTool:setOwnerFarmId(FarmManager.SPECTATOR_FARM_ID, true)
                debugPrint(string.format("[HandToolHolderBuildingsSilo] 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("[HandToolHolderBuildingsSilo] HandTool %d set to SPECTATOR_FARM_ID", i))
            end
        end
    end
    
    debugPrint(string.format("[HandToolHolderBuildingsSilo] Found %d holders from PlaceableHandToolHolders", #spec.handToolHolders))
    
    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.placeable = self
        
        debugPrint(string.format("[HandToolHolderBuildingsSilo] 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))
        
        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("[HandToolHolderBuildingsSilo] Pump ambient sound loaded for holder %d", i))
            else
                print(string.format("[HandToolHolderBuildingsSilo] 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!")
        end
        
        holder.originalOnPickupHandTool = holder.onPickupHandTool
        holder.originalOnDropHandTool = holder.onDropHandTool
        
        holder.onPickupHandTool = function(self, handTool)
            debugPrint("[HandToolHolderBuildingsSilo] 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("[HandToolHolderBuildingsSilo] 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("[HandToolHolderBuildingsSilo] Tethering deactivated")
            end
            
            if handTool.spec_fuelingSilo ~= nil then
                if handTool.stopFueling then
                    handTool:stopFueling()
                end
                handTool.spec_fuelingSilo.siloPlaceable = nil
                debugPrint("[HandToolHolderBuildingsSilo] Silo reference removed from tool")
            end

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

            return result
        end
        
        holder.onDropHandTool = function(self, handTool)
            debugPrint("[HandToolHolderBuildingsSilo] 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("[HandToolHolderBuildingsSilo] 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_fuelingSilo ~= nil then
                handTool.spec_fuelingSilo.totalLitersFilled = 0
                handTool.spec_fuelingSilo.totalCost = 0
                handTool.spec_fuelingSilo.lastLogTime = 0
                handTool.spec_fuelingSilo.holderDisplaySide = self.displaySide
                debugPrint("[HandToolHolderBuildingsSilo] Fueling counters reset")
            end
            
            if placeable and placeable.clearFuelingDisplayByIndex then
                placeable:clearFuelingDisplayByIndex(self.displayIndex)
                debugPrint(string.format("[HandToolHolderBuildingsSilo] 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("[HandToolHolderBuildingsSilo] Pump ambient sound STARTED (local)")
                end
            end
            
            SiloHandToolPumpSoundEvent.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("[HandToolHolderBuildingsSilo] Tethering activated: MaxRange=%.2fm", self.maxRange))
                else
                    print("[HandToolHolderBuildingsSilo] WARNING: setAttachedHolder() not found!")
                end
            end
            
            if handTool.spec_fuelingSilo ~= nil then
                handTool.spec_fuelingSilo.siloPlaceable = placeable
                debugPrint("[HandToolHolderBuildingsSilo] Silo reference set in tool")
            end

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

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

function HandToolHolderBuildingsSilo: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("[HandToolHolderBuildingsSilo] Pump ambient sound deleted")
            end
        end
    end
end

SiloHandToolVisibilityEvent = {}
local SiloHandToolVisibilityEvent_mt = Class(SiloHandToolVisibilityEvent, Event)

InitEventClass(SiloHandToolVisibilityEvent, "SiloHandToolVisibilityEvent")

function SiloHandToolVisibilityEvent.emptyNew()
    local self = Event.new(SiloHandToolVisibilityEvent_mt)
    return self
end

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

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

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

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

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

SiloHandToolPumpSoundEvent = {}
local SiloHandToolPumpSoundEvent_mt = Class(SiloHandToolPumpSoundEvent, Event)

InitEventClass(SiloHandToolPumpSoundEvent, "SiloHandToolPumpSoundEvent")

function SiloHandToolPumpSoundEvent.emptyNew()
    local self = Event.new(SiloHandToolPumpSoundEvent_mt)
    return self
end

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

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

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

function SiloHandToolPumpSoundEvent: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("[HandToolHolderBuildingsSilo] Pump sound STARTED (synced) for holder %d", self.holderIndex))
                    end
                else
                    g_soundManager:stopSample(holder.pumpAmbientSample)
                    debugPrint(string.format("[HandToolHolderBuildingsSilo] 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 SiloHandToolPumpSoundEvent.sendEvent(placeable, holderIndex, play)
    if g_server ~= nil then
        g_server:broadcastEvent(SiloHandToolPumpSoundEvent.new(placeable, holderIndex, play), nil, nil, placeable)
    else
        g_client:getServerConnection():sendEvent(SiloHandToolPumpSoundEvent.new(placeable, holderIndex, play))
    end
end

print("[SiloHandToolPumpSoundEvent] Network event registered")