window.LogiLadder = window.LogiLadder || {};

LogiLadder.Simulator = {
    isRunning: false,
    timer: null,
    state: {}, // Speichert Timer, Flanken-Zustände etc.
    mem: {},   // Zentraler Speicher für Variablen (Var Lesen/Schreiben)
    
    toggle: function(editor) {
        this.isRunning = !this.isRunning;
        const btn = document.getElementById('btn-sim');
        
        if (this.isRunning) {
            btn.innerText = "⏹ Simulation Stoppen";
            btn.style.backgroundColor = "#dc3545"; // Rot
            document.body.classList.add('sim-active');
            
            this.state = {}; 
            this.mem = {};
            this.timer = setInterval(() => this.step(editor), 100); // 100ms SPS-Zyklus
        } else {
            btn.innerText = "▶ Simulation Starten";
            btn.style.backgroundColor = "";
            document.body.classList.remove('sim-active');
            
            clearInterval(this.timer);
            this.clearVisuals();
        }
    },
    
    step: function(editor) {
        const data = editor.export();
        if (!data || !data.drawflow.Home.data) return;
        const nodes = data.drawflow.Home.data;
        const currentMillis = Date.now();
        
        let stepValues = {}; 
        let evaluating = new Set(); // Verhindert Endlosschleifen bei Rückkopplungen
        
        // Rekursive Berechnungsfunktion (Topologische Sortierung on the fly)
        const evaluateNode = (id) => {
            if (stepValues[id] !== undefined) return stepValues[id];
            if (evaluating.has(id)) return 0; // Zyklus erkannt
            evaluating.add(id);
            
            const node = nodes[id];
            const def = LogiLadder.Nodes[node.name];
            if (!def) return 0;
            
            if (!this.state[id]) this.state[id] = {};
            
            // Eingänge des Bausteins auswerten
            let inValues = [];
            for (let i = 1; i <= def.inputs; i++) {
                const conn = node.inputs[`input_${i}`].connections;
                if (conn.length > 0) {
                    inValues.push(evaluateNode(conn[0].node));
                } else {
                    inValues.push(def.outType === 'float' ? 0.0 : false);
                }
            }
            
            // JavaScript Simulations-Logik des Bausteins ausführen
            let outVal = def.outType === 'bool' ? false : 0.0;
            if (def.sim) {
                outVal = def.sim(id, node.data, inValues, this.state[id], currentMillis);
            }
            
            stepValues[id] = outVal;
            this.updateNodeVisual(id, outVal, def.outType);
            return outVal;
        };
        
        // Alle Knoten erzwingen (auch wenn sie an keinem Ausgang hängen)
        for (const id in nodes) {
            evaluateNode(id);
        }
        
        this.updateLines(nodes, stepValues);
    },
    
    updateNodeVisual: function(id, val, type) {
        const nodeEl = document.getElementById(`node-${id}`);
        if (!nodeEl) return;
        
        let valBox = nodeEl.querySelector('.sim-val-display');
        if (!valBox) {
            valBox = document.createElement('div');
            valBox.className = 'sim-val-display';
            nodeEl.appendChild(valBox);
        }
        
        if (type === 'bool') {
            valBox.innerText = val ? "ON" : "OFF";
            valBox.style.backgroundColor = val ? "#28a745" : "#6c757d";
        } else {
            valBox.innerText = Number(val).toFixed(1);
            valBox.style.backgroundColor = "#fd7e14";
        }
    },
    
    updateLines: function(nodes, stepValues) {
        for (const id in nodes) {
            const outVal = stepValues[id];
            const node = nodes[id];
            const outConns = node.outputs.output_1?.connections;
            if (outConns) {
                outConns.forEach(conn => {
                    const path = document.querySelector(`.connection.node_in_node-${conn.node}.node_out_node-${id} .main-path`);
                    if (path) {
                        if (typeof outVal === 'boolean') {
                            path.style.stroke = outVal ? '#28a745' : '#495057';
                            path.style.strokeWidth = outVal ? '4px' : '3px';
                        } else {
                            // Analoge Linien bleiben orange, werden aber bei Wertänderung leicht dicker
                            path.style.stroke = '#fd7e14';
                            path.style.strokeWidth = '4px';
                        }
                    }
                });
            }
        }
    },
    
    clearVisuals: function() {
        document.querySelectorAll('.sim-val-display').forEach(el => el.remove());
        document.querySelectorAll('.connection .main-path').forEach(path => {
            path.style.stroke = '';
            path.style.strokeWidth = '';
        });
    }
};