/**
 * SigUIManager - Handles DOM updates and signal card rendering
 */
class SigUIManager {
    constructor() {
        this.targetEl = null;
        this.formElement = null;
        this.onDeleteSignal = null;
    }

    /**
     * Initializes the UI elements with provided IDs.
     * @param {string} targetId - The ID of the HTML element where signals will be displayed.
     * @param {string} formElId - The ID of the HTML element for the signal creation form.
     */
    initUI(targetId, formElId) {
        this.targetEl = document.getElementById(targetId);
        if (!this.targetEl) {
            console.warn(`Element for displaying signals "${targetId}" not found.`);
        }

        this.formElement = document.getElementById(formElId);
        if (!this.formElement) {
            console.warn(`Signals form element "${formElId}" not found.`);
        }
    }

    /**
     * Displays the form for creating or editing a signal.
     * @param {string} action - The action to perform ('new' or 'edit').
     * @param {object|null} signalData - The data of the signal to edit (only applicable for 'edit' action).
     */
    displayForm(action, signalData = null) {
        if (!this.formElement) {
            console.error("Form element not initialized.");
            return;
        }

        const headerTitle = this.formElement.querySelector("h1");
        const submitCreateBtn = this.formElement.querySelector("#submit-create-signal");
        const submitEditBtn = this.formElement.querySelector("#submit-edit-signal");
        const nameBox = this.formElement.querySelector('#signal_name');
        const publicCheckbox = this.formElement.querySelector('#signal_public_checkbox');
        const tblKeyInput = this.formElement.querySelector('#signal_tbl_key');

        // Reset form to panel 1
        const panel1 = this.formElement.querySelector('#panel_1');
        const panel2 = this.formElement.querySelector('#panel_2');
        const panel3 = this.formElement.querySelector('#panel_3');
        if (panel1) panel1.style.display = 'grid';
        if (panel2) panel2.style.display = 'none';
        if (panel3) panel3.style.display = 'none';

        if (action === 'new') {
            if (headerTitle) headerTitle.textContent = "Add New Signal";
            if (submitCreateBtn) submitCreateBtn.style.display = "inline-block";
            if (submitEditBtn) submitEditBtn.style.display = "none";
            if (nameBox) nameBox.value = '';
            if (publicCheckbox) publicCheckbox.checked = false;
            if (tblKeyInput) tblKeyInput.value = '';

            // Initialize property dropdowns based on first selected source
            const sigSource = this.formElement.querySelector('#sig_source');
            const sig2Source = this.formElement.querySelector('#sig2_source');
            if (sigSource && sigSource.value && UI.signals) {
                UI.signals.fill_prop('sig_prop', sigSource.value);
            }
            if (sig2Source && sig2Source.value && UI.signals) {
                UI.signals.fill_prop('sig2_prop', sig2Source.value);
            }
        } else if (action === 'edit' && signalData) {
            if (headerTitle) headerTitle.textContent = "Edit Signal";
            if (submitCreateBtn) submitCreateBtn.style.display = "none";
            if (submitEditBtn) submitEditBtn.style.display = "inline-block";
            if (nameBox) nameBox.value = signalData.name || '';
            if (publicCheckbox) publicCheckbox.checked = !!signalData.public;
            if (tblKeyInput) tblKeyInput.value = signalData.tbl_key || '';

            // Pre-fill source fields
            const sigSource = this.formElement.querySelector('#sig_source');
            const sigProp = this.formElement.querySelector('#sig_prop');
            const sig2Source = this.formElement.querySelector('#sig2_source');
            const sig2Prop = this.formElement.querySelector('#sig2_prop');
            const sigType = this.formElement.querySelector('#select_s_type');
            const valueInput = this.formElement.querySelector('#value');

            if (sigSource && signalData.source1) sigSource.value = signalData.source1;
            if (sigProp && signalData.prop1) {
                // Fill prop options first, then set value
                if (UI.signals && signalData.source1) {
                    UI.signals.fill_prop('sig_prop', signalData.source1);
                }
                setTimeout(() => { if (sigProp) sigProp.value = signalData.prop1; }, 50);
            }

            // Handle source2 - could be 'value' for fixed value type
            if (signalData.source2 === 'value') {
                if (sigType) sigType.value = 'Value';
                if (valueInput) valueInput.value = signalData.prop2 || '';
            } else {
                if (sigType) sigType.value = 'Comparison';
                if (sig2Source && signalData.source2) sig2Source.value = signalData.source2;
                if (sig2Prop && signalData.prop2) {
                    if (UI.signals && signalData.source2) {
                        UI.signals.fill_prop('sig2_prop', signalData.source2);
                    }
                    setTimeout(() => { if (sig2Prop) sig2Prop.value = signalData.prop2; }, 50);
                }
            }

            // Set operator
            const operatorRadios = this.formElement.querySelectorAll('input[name="Operator"]');
            operatorRadios.forEach(radio => {
                radio.checked = radio.value === signalData.operator;
            });

            // Set range if applicable
            if (signalData.operator === '+/-' && signalData.range) {
                const rangeVal = this.formElement.querySelector('#rangeVal');
                const rangeSlider = this.formElement.querySelector('#rangeSlider');
                if (rangeVal) rangeVal.value = signalData.range;
                if (rangeSlider) rangeSlider.value = signalData.range;
            }
        }

        this.formElement.style.display = "grid";
    }

    /**
     * Hides the signal form.
     */
    hideForm() {
        if (this.formElement) {
            this.formElement.style.display = 'none';
        }
    }

    /**
     * Updates the HTML representation of the signals as cards.
     * @param {Object[]} signals - The list of signals to display.
     */
    updateSignalsHtml(signals) {
        if (!this.targetEl) {
            console.error("Target element for displaying signals is not set.");
            return;
        }

        // Clear existing content
        while (this.targetEl.firstChild) {
            this.targetEl.removeChild(this.targetEl.firstChild);
        }

        // Create and append new elements for all signals
        for (const signal of signals) {
            try {
                const signalCard = this._createSignalCard(signal);
                this.targetEl.appendChild(signalCard);
            } catch (error) {
                console.error(`Error processing signal:`, error, signal);
            }
        }
    }

    /**
     * Creates a signal card HTML element.
     * @param {Object} signal - The signal data.
     * @returns {HTMLElement} - The card element.
     */
    _createSignalCard(signal) {
        const signalItem = document.createElement('div');
        signalItem.className = 'signal-item';
        signalItem.setAttribute('data-signal-id', signal.tbl_key || signal.name);

        // Add state-based styling
        const isTrue = signal.state === true || signal.state === 'true' || signal.state === 1;
        if (isTrue) {
            signalItem.classList.add('signal-true');
        } else {
            signalItem.classList.add('signal-false');
        }

        // Delete button
        const deleteButton = document.createElement('button');
        deleteButton.className = 'delete-button';
        deleteButton.innerHTML = '&#10008;';
        deleteButton.addEventListener('click', (e) => {
            e.stopPropagation();
            if (this.onDeleteSignal) {
                this.onDeleteSignal(signal.tbl_key || signal.name);
            }
        });
        signalItem.appendChild(deleteButton);

        // Signal icon container
        const signalIcon = document.createElement('div');
        signalIcon.className = 'signal-icon';
        signalIcon.addEventListener('click', () => {
            // Open edit form when clicking on signal
            this.displayForm('edit', signal);
        });

        // Signal name
        const signalName = document.createElement('div');
        signalName.className = 'signal-name';
        signalName.textContent = signal.name || 'Unnamed Signal';
        signalIcon.appendChild(signalName);

        // State indicator
        const stateIndicator = document.createElement('div');
        stateIndicator.className = 'signal-state';
        stateIndicator.id = `${signal.name}_state`;
        stateIndicator.textContent = isTrue ? 'TRUE' : 'FALSE';
        signalIcon.appendChild(stateIndicator);

        signalItem.appendChild(signalIcon);

        // Hover details panel
        const signalHover = document.createElement('div');
        signalHover.className = 'signal-hover';

        // Build hover content
        let hoverHtml = `<strong>${signal.name || 'Unnamed Signal'}</strong>`;
        hoverHtml += `<div class="signal-details">`;
        hoverHtml += `<span>Source 1: ${signal.source1} (${signal.prop1})</span>`;
        hoverHtml += `<span id="${signal.name}_value1">Value: ${signal.value1 ?? signal.last_value1 ?? 'N/A'}</span>`;
        hoverHtml += `<span>Operator: ${signal.operator}${signal.operator === '+/-' ? ` (range: ${signal.range})` : ''}</span>`;

        if (signal.source2 === 'value') {
            hoverHtml += `<span>Compare to: ${signal.prop2}</span>`;
        } else {
            hoverHtml += `<span>Source 2: ${signal.source2} (${signal.prop2})</span>`;
            hoverHtml += `<span id="${signal.name}_value2">Value: ${signal.value2 ?? signal.last_value2 ?? 'N/A'}</span>`;
        }

        // State display
        const stateClass = isTrue ? 'state-true' : 'state-false';
        hoverHtml += `<span class="${stateClass}">State: ${isTrue ? 'TRUE' : 'FALSE'}</span>`;

        if (signal.public) {
            hoverHtml += `<span class="signal-public-badge">Public</span>`;
        }

        hoverHtml += `</div>`;

        signalHover.innerHTML = hoverHtml;
        signalItem.appendChild(signalHover);

        return signalItem;
    }

    /**
     * Updates a single signal's state display.
     * @param {string} signalName - The name of the signal.
     * @param {boolean} state - The new state.
     */
    updateSignalState(signalName, state) {
        const stateEl = document.getElementById(`${signalName}_state`);
        if (stateEl) {
            const isTrue = state === true || state === 'true' || state === 1;
            stateEl.textContent = isTrue ? 'TRUE' : 'FALSE';

            // Update parent card styling
            const card = stateEl.closest('.signal-item');
            if (card) {
                card.classList.remove('signal-true', 'signal-false');
                card.classList.add(isTrue ? 'signal-true' : 'signal-false');
            }
        }
    }

    /**
     * Sets the callback function for deleting a signal.
     * @param {Function} callback - The callback function.
     */
    registerDeleteSignalCallback(callback) {
        this.onDeleteSignal = callback;
    }
}


/**
 * SigDataManager - Manages in-memory signal data store
 */
class SigDataManager {
    constructor() {
        this.signals = [];
    }

    /**
     * Fetches the saved signals from the server.
     * @param {Object} comms - The communications instance.
     * @param {Object} data - An object containing user data.
     */
    fetchSavedSignals(comms, data) {
        if (comms) {
            try {
                const requestData = {
                    request: 'signals',
                    user_name: data?.user_name
                };
                comms.sendToApp('request', requestData);
            } catch (error) {
                console.error("Error fetching saved signals:", error.message);
            }
        } else {
            throw new Error('Communications instance not available.');
        }
    }

    /**
     * Adds a new signal to the local store.
     * @param {Object} data - The signal data.
     */
    addNewSignal(data) {
        const signalData = data.signal || data;
        console.log("Adding new signal:", signalData);
        if (!signalData.name) {
            console.error("Signal data missing 'name' field:", signalData);
            return;
        }

        // Check for duplicates
        const exists = this.signals.find(s => s.tbl_key === signalData.tbl_key || s.name === signalData.name);
        if (!exists) {
            this.signals.push(signalData);
        }
    }

    /**
     * Retrieves a signal by its tbl_key.
     * @param {string} tbl_key - The tbl_key of the signal.
     * @returns {Object|null} - The signal object or null.
     */
    getSignalById(tbl_key) {
        return this.signals.find(signal => signal.tbl_key === tbl_key) || null;
    }

    /**
     * Retrieves a signal by its name.
     * @param {string} name - The name of the signal.
     * @returns {Object|null} - The signal object or null.
     */
    getSignalByName(name) {
        return this.signals.find(signal => signal.name === name) || null;
    }

    /**
     * Updates signal data.
     * @param {Object} data - The updated signal data.
     */
    updateSignalData(data) {
        const signalData = data.signal || data;
        const signalKey = signalData.tbl_key || signalData.name;
        if (!signalKey) return;

        const index = this.signals.findIndex(
            signal => signal.tbl_key === signalKey || signal.name === signalKey
        );

        if (index !== -1) {
            this.signals[index] = { ...this.signals[index], ...signalData };
        } else {
            this.signals.push(signalData);
        }
    }

    /**
     * Removes a signal from the store.
     * @param {string} identifier - The tbl_key or name of the signal.
     */
    removeSignal(identifier) {
        console.log(`Removing signal: ${identifier}`);
        this.signals = this.signals.filter(
            sig => sig.tbl_key !== identifier && sig.name !== identifier
        );
    }

    /**
     * Updates signal states from server updates.
     * @param {Object} stateUpdates - Map of signal names to states.
     */
    applyStateUpdates(stateUpdates) {
        for (const name in stateUpdates) {
            const signal = this.getSignalByName(name);
            if (signal) {
                signal.state = stateUpdates[name];
            }
        }
    }

    /**
     * Returns all signals.
     * @returns {Object[]} - The list of signals.
     */
    getAllSignals() {
        return this.signals;
    }

    /**
     * Sets all signals (used when loading from server).
     * @param {Object[]} signals - The list of signals.
     */
    setSignals(signals) {
        this.signals = Array.isArray(signals) ? signals : [];
    }
}


/**
 * Signals - Main coordinator class that manages SigUIManager, SigDataManager, and SocketIO communication
 */
class Signals {
    constructor(ui) {
        this.ui = ui;
        this.comms = ui?.data?.comms;
        this.indicatorData = ui?.data?.indicators;
        this.data = ui?.data;

        this.dataManager = new SigDataManager();
        this.uiManager = new SigUIManager();

        // Set up delete callback
        this.uiManager.registerDeleteSignalCallback(this.deleteSignal.bind(this));

        // Bind methods
        this.submitSignal = this.submitSignal.bind(this);

        this._initialized = false;
    }

    /**
     * Initializes the Signals instance.
     * @param {string} targetId - The ID of the signals container element.
     * @param {string} formElId - The ID of the signal form element.
     */
    initialize(targetId, formElId) {
        try {
            this.uiManager.initUI(targetId, formElId);

            if (!this.comms) {
                console.error("Communications instance not available.");
                return;
            }

            // Register handlers with Comms
            this.comms.on('signals', this.handleSignalsResponse.bind(this));
            this.comms.on('signal_created', this.handleSignalCreated.bind(this));
            this.comms.on('signal_updated', this.handleSignalUpdated.bind(this));
            this.comms.on('signal_deleted', this.handleSignalDeleted.bind(this));
            this.comms.on('signal_error', this.handleSignalError.bind(this));
            this.comms.on('updates', this.handleUpdates.bind(this));

            // Fetch saved signals
            this.dataManager.fetchSavedSignals(this.comms, this.data);

            this._initialized = true;
        } catch (error) {
            console.error("Error initializing Signals:", error);
        }
    }

    /**
     * Handle initial signals list response from server.
     * @param {Array} data - List of signal objects.
     */
    handleSignalsResponse(data) {
        console.log("Received signals list:", data);
        if (Array.isArray(data)) {
            this.dataManager.setSignals(data);
            this.uiManager.updateSignalsHtml(this.dataManager.getAllSignals());
        }
    }

    /**
     * Handle new signal created event.
     * @param {Object} data - Server response with signal data.
     */
    handleSignalCreated(data) {
        console.log("Signal created:", data);
        if (data.success) {
            this.dataManager.addNewSignal(data);
            this.uiManager.updateSignalsHtml(this.dataManager.getAllSignals());
        } else {
            alert(`Failed to create signal: ${data.message}`);
        }
    }

    /**
     * Handle signal updated event.
     * @param {Object} data - Server response with updated signal data.
     */
    handleSignalUpdated(data) {
        console.log("Signal updated:", data);
        if (data.success) {
            this.dataManager.updateSignalData(data);
            this.uiManager.updateSignalsHtml(this.dataManager.getAllSignals());
        } else {
            alert(`Failed to update signal: ${data.message}`);
        }
    }

    /**
     * Handle signal deleted event.
     * @param {Object} data - Server response with deleted signal info.
     */
    handleSignalDeleted(data) {
        console.log("Signal deleted:", data);
        const identifier = data.tbl_key || data.name;
        if (identifier) {
            this.dataManager.removeSignal(identifier);
            this.uiManager.updateSignalsHtml(this.dataManager.getAllSignals());
        }
    }

    /**
     * Handle signal error.
     * @param {Object} data - Error data.
     */
    handleSignalError(data) {
        console.error("Signal error:", data.message);
        alert(`Signal error: ${data.message}`);
    }

    /**
     * Handle updates (including signal state changes).
     * @param {Object} data - Update data from server.
     */
    handleUpdates(data) {
        const { s_updates } = data;
        if (s_updates) {
            this.dataManager.applyStateUpdates(s_updates);
            // Update UI for state changes
            for (const name in s_updates) {
                this.uiManager.updateSignalState(name, s_updates[name]);
            }
        }
    }

    // ================ Form Methods ================

    /**
     * Opens the signal creation form.
     */
    open_signal_Form() {
        this.uiManager.displayForm('new');
    }

    /**
     * Closes the signal form.
     */
    close_signal_Form() {
        this.uiManager.hideForm();
    }

    /**
     * Requests signals from server.
     */
    request_signals() {
        if (this.comms) {
            this.comms.sendToApp('request', { request: 'signals', user_name: this.data?.user_name });
        }
    }

    /**
     * Deletes a signal by tbl_key or name.
     * @param {string} identifier - The tbl_key or name of the signal.
     */
    deleteSignal(identifier) {
        if (!this.comms) {
            console.error("Comms instance not available.");
            return;
        }

        const signal = this.dataManager.getSignalById(identifier) ||
                       this.dataManager.getSignalByName(identifier);

        const deleteData = signal
            ? { tbl_key: signal.tbl_key, name: signal.name }
            : { name: identifier };

        this.comms.sendToApp('delete_signal', deleteData);
    }

    /**
     * Submits a new or edited signal.
     * @param {string} action - 'new' or 'edit'.
     */
    submitSignal(action) {
        const formElement = this.uiManager.formElement;
        if (!formElement) {
            console.error("Form element not available.");
            return;
        }

        const name = formElement.querySelector('#signal_name')?.value?.trim();
        const source1 = formElement.querySelector('#sig_source')?.value;
        const prop1 = formElement.querySelector('#sig_prop')?.value;
        const source2 = formElement.querySelector('#sig2_source')?.value;
        const prop2 = formElement.querySelector('#sig2_prop')?.value;
        const operator = formElement.querySelector('input[name="Operator"]:checked')?.value;
        const range = formElement.querySelector('#rangeVal')?.value;
        const sigType = formElement.querySelector('#select_s_type')?.value;
        const value = formElement.querySelector('#value')?.value;
        const publicCheckbox = formElement.querySelector('#signal_public_checkbox');
        const tblKey = formElement.querySelector('#signal_tbl_key')?.value;

        if (!name) {
            alert("Please provide a name for the signal.");
            return;
        }
        if (!prop1) {
            alert("Please select a property for the signal source.");
            return;
        }

        // Build signal data
        let actualSource2 = source2;
        let actualProp2 = prop2;

        if (sigType !== 'Comparison') {
            actualSource2 = 'value';
            actualProp2 = value;
        }

        const signalData = {
            name,
            source1,
            prop1,
            operator,
            source2: actualSource2,
            prop2: actualProp2,
            state: false,
            value1: null,
            value2: null,
            public: publicCheckbox?.checked ? 1 : 0,
            user_name: this.data?.user_name
        };

        if (operator === '+/-') {
            signalData.range = parseFloat(range) || 0;
        }

        if (action === 'edit' && tblKey) {
            signalData.tbl_key = tblKey;
        }

        const messageType = action === 'new' ? 'new_signal' : 'edit_signal';
        this.comms.sendToApp(messageType, signalData);

        this.close_signal_Form();
    }

    /**
     * Submits a new signal (legacy method name).
     */
    submitNewSignal() {
        this.submitSignal('new');
    }

    // ================ Helper Methods ================

    /**
     * Fills property dropdown based on indicator type.
     * @param {string} target_id - The ID of the select element.
     * @param {string} indctr - The indicator name.
     */
    fill_prop(target_id, indctr) {
        const target = document.getElementById(target_id);
        const indicatorConfig = this.indicatorData ? this.indicatorData[indctr] : null;

        if (!target) return;

        // Clear existing options
        while (target.options.length > 0) {
            target.remove(0);
        }

        if (!indicatorConfig) {
            console.warn(`Indicator "${indctr}" not found in indicator data`);
            return;
        }

        // Get the indicator outputs based on type
        const outputMap = {
            'SMA': ['value'],
            'EMA': ['value'],
            'LREG': ['value'],
            'RSI': ['value'],
            'ATR': ['value'],
            'Volume': ['value'],
            'MACD': ['macd', 'signal', 'hist'],
            'BOLBands': ['upper', 'middle', 'lower']
        };

        const indicatorType = indicatorConfig.type;
        const outputs = outputMap[indicatorType] || ['value'];

        for (const output of outputs) {
            const opt = document.createElement("option");
            opt.value = output;
            opt.textContent = output;
            target.appendChild(opt);
        }
    }

    /**
     * Switches between form panels.
     * @param {string} p1 - Panel to hide.
     * @param {string} p2 - Panel to show.
     */
    switch_panel(p1, p2) {
        const panel1 = document.getElementById(p1);
        const panel2 = document.getElementById(p2);
        if (panel1) panel1.style.display = 'none';
        if (panel2) panel2.style.display = 'grid';
    }

    /**
     * Conditionally hides an element.
     * @param {*} firstValue - First value to compare.
     * @param {*} scndValue - Second value to compare.
     * @param {string} id - Element ID to show/hide.
     */
    hideIfTrue(firstValue, scndValue, id) {
        const el = document.getElementById(id);
        if (el) {
            el.style.display = firstValue === scndValue ? 'none' : 'block';
        }
    }

    /**
     * Gets the current value of an indicator property from the DOM.
     * @param {string} source - The indicator source name.
     * @param {string} prop - The property name.
     * @returns {string} - The value.
     */
    _getIndicatorValue(source, prop) {
        let element = document.getElementById(source + '_' + prop)
            || document.getElementById(source + '_value');

        if (!element) {
            console.warn(`Could not find indicator value element for ${source}_${prop}`);
            return '0';
        }

        let rawValue = element.value || element.textContent || '0';

        // Parse multi-value format if needed
        if (rawValue.includes(':') && rawValue.includes(',')) {
            const parts = rawValue.split(',').map(p => p.trim());
            for (const part of parts) {
                const [key, val] = part.split(':').map(s => s.trim());
                if (key === prop) {
                    return val;
                }
            }
        }

        return rawValue;
    }

    /**
     * Handles panel 1 "Next" button click.
     * @param {number} n - Panel number.
     */
    ns_next(n) {
        if (n === 1) {
            const sigName = document.getElementById('signal_name')?.value;
            const sigSource = document.getElementById('sig_source')?.value;
            const sigProp = document.getElementById('sig_prop')?.value;

            if (!sigName) {
                alert('Please give the signal a name.');
                return;
            }
            if (!sigProp) {
                alert('Please select a property.');
                return;
            }

            const display = document.getElementById('sig_display');
            if (display) {
                display.innerHTML = `${sigName}: {${sigSource}:${sigProp}}`;
            }

            // Get current indicator value
            const indctrVal = this._getIndicatorValue(sigSource, sigProp);
            const valueInput = document.getElementById('value');
            if (valueInput) {
                valueInput.value = indctrVal || '0';
            }

            this.switch_panel('panel_1', 'panel_2');
        }

        if (n === 2) {
            const sigName = document.getElementById('signal_name')?.value;
            const sigSource = document.getElementById('sig_source')?.value;
            const sigProp = document.getElementById('sig_prop')?.value;
            const sig2Source = document.getElementById('sig2_source')?.value;
            const sig2Prop = document.getElementById('sig2_prop')?.value;
            const operator = document.querySelector('input[name="Operator"]:checked')?.value;
            const range = document.getElementById('rangeVal')?.value;
            const sigType = document.getElementById('select_s_type')?.value;
            const value = document.getElementById('value')?.value;

            const sig1 = `${sigSource} : ${sigProp}`;
            const sig2 = sigType === 'Comparison' ? `${sig2Source} : ${sig2Prop}` : value;
            const operatorStr = operator === '+/-' ? `${operator} ${range}` : operator;

            const sigDisplayStr = `(${sigName}) (${sig1}) (${operatorStr}) (${sig2})`;

            const sig1_realtime = this._getIndicatorValue(sigSource, sigProp);
            const sig2_realtime = sigType === 'Comparison'
                ? this._getIndicatorValue(sig2Source, sig2Prop)
                : value;

            const display2 = document.getElementById('sig_display2');
            const realtime = document.getElementById('sig_realtime');
            const evalEl = document.getElementById('sig_eval');

            if (display2) display2.innerHTML = sigDisplayStr;
            if (realtime) realtime.innerHTML = `(${sigProp} : ${sig1_realtime}) (${operatorStr}) (${sig2_realtime})`;

            // Evaluate
            let evalStr;
            if (operator === '==') evalStr = parseFloat(sig1_realtime) === parseFloat(sig2_realtime);
            if (operator === '>') evalStr = parseFloat(sig1_realtime) > parseFloat(sig2_realtime);
            if (operator === '<') evalStr = parseFloat(sig1_realtime) < parseFloat(sig2_realtime);
            if (operator === '+/-') evalStr = Math.abs(parseFloat(sig1_realtime) - parseFloat(sig2_realtime)) <= parseFloat(range);

            if (evalEl) evalEl.innerHTML = evalStr ? 'true' : 'false';

            this.switch_panel('panel_2', 'panel_3');
        }
    }

    // Legacy methods for backwards compatibility
    i_update(updates) {
        for (const signal of this.dataManager.getAllSignals()) {
            const s1 = signal.source1;
            if (s1 in updates) {
                const p1 = signal.prop1;
                const value1 = updates[s1].data[0][p1];
                signal.value1 = value1.toFixed(2);
            }
            if (signal.source2 !== 'value') {
                const s2 = signal.source2;
                if (s2 in updates) {
                    const p2 = signal.prop2;
                    const value2 = updates[s2].data[0][p2];
                    signal.value2 = value2.toFixed(2);
                }
            }
            const val1El = document.getElementById(signal.name + '_value1');
            const val2El = document.getElementById(signal.name + '_value2');
            if (val1El) val1El.innerHTML = signal.value1;
            if (val2El) val2El.innerHTML = signal.value2;
        }
    }

    update_signal_states(s_updates) {
        for (const name in s_updates) {
            this.uiManager.updateSignalState(name, s_updates[name]);
        }
    }

    set_data(signals) {
        // Legacy method - now handled by handleSignalsResponse
        if (Array.isArray(signals)) {
            for (const sig of signals) {
                const obj = typeof sig === 'string' ? JSON.parse(sig) : sig;
                this.dataManager.addNewSignal(obj);
            }
            this.uiManager.updateSignalsHtml(this.dataManager.getAllSignals());
        }
    }

    delete_signal(signal_name) {
        // Legacy method - redirect to new method
        this.deleteSignal(signal_name);
    }
}
