/**
 * Chart Settings Manager
 * Handles chart parameter controls and WebSocket communication
 */

import { createParameterControl } from '../utils.js';
import { renderIcons } from '../icons.js';

export class ChartSettingsManager {
    constructor() {
        this.lastSettingValues = {};
        this.settingDebounceTimers = {};
        this.lastUiParameters = new Map();
        this.lastUserInteractionTime = new Map();
        this.parameterChangeTimestamps = {};
        this.containerListeners = new Map(); // Store listeners per container
    }

    updateSettings(processorId, settingsContainer, latestData) {
        if (!settingsContainer) return;

        const uiParameters = latestData?.metadata?.ui_parameters;

        // Check if parameters have changed
        const lastParams = this.lastUiParameters.get(processorId);
        const parametersChanged = !lastParams || JSON.stringify(uiParameters) !== JSON.stringify(lastParams);

        if (!parametersChanged) {
            return;
        }

        // Check if user recently interacted with controls
        const lastInteraction = this.lastUserInteractionTime.get(processorId);
        if (lastInteraction && Date.now() - lastInteraction < 1000) {
            console.log(`Skipping update for ${processorId} - user is actively editing`);
            return;
        }

        console.log(`Updating settings for ${processorId}`);
        this.lastUiParameters.set(processorId, uiParameters ? JSON.parse(JSON.stringify(uiParameters)) : null);

        // Fallback to UI manager if no data available
        if (!uiParameters || !Array.isArray(uiParameters) || uiParameters.length === 0) {
            const uiManager = window.vnaDashboard?.ui;
            const processor = uiManager?.processors?.get(processorId);

            if (processor?.uiParameters && Array.isArray(processor.uiParameters) && processor.uiParameters.length > 0) {
                const settingsHtml = processor.uiParameters.map(param =>
                    createParameterControl(param, processorId, 'chart')
                ).join('');
                settingsContainer.innerHTML = settingsHtml;
                this.setupEvents(settingsContainer, processorId);
                return;
            }

            settingsContainer.innerHTML = '<div class="settings-empty">Настройки недоступны</div>';
            return;
        }

        // Smart update: only update changed parameters, skip focused elements
        const hasExistingControls = settingsContainer.children.length > 0;
        if (hasExistingControls) {
            this.updateParametersSelectively(processorId, settingsContainer, uiParameters);
        } else {
            // Initial render: full rebuild
            const settingsHtml = uiParameters.map(param =>
                createParameterControl(param, processorId, 'chart')
            ).join('');
            settingsContainer.innerHTML = settingsHtml;
            this.setupEvents(settingsContainer, processorId);
        }

        // Initialize last values
        if (uiParameters) {
            uiParameters.forEach(param => {
                const settingKey = `${processorId}_${param.name}`;
                this.lastSettingValues[settingKey] = param.value;
            });
        }

        renderIcons(settingsContainer);
    }

    updateParametersSelectively(processorId, settingsContainer, newParameters) {
        const now = Date.now();

        // Temporarily remove event listeners to prevent programmatic changes from triggering events
        this.removeEventListeners(settingsContainer);

        for (const param of newParameters) {
            const settingElement = settingsContainer.querySelector(`[data-param="${param.name}"]`);
            if (!settingElement) continue;

            const settingKey = `${processorId}_${param.name}`;
            const currentValue = this.lastSettingValues[settingKey];

            console.log(`[UPDATE CHECK] ${param.name}: currentValue=${currentValue}, newValue=${param.value}`);

            // ALWAYS sync lastSettingValues with backend value
            const valueChanged = currentValue !== param.value;
            if (valueChanged) {
                this.lastSettingValues[settingKey] = param.value;
                console.log(`[SYNCED] lastSettingValues["${settingKey}"] = ${param.value}`);
            } else {
                console.log(`[SKIP] ${param.name}: value unchanged`);
                continue;
            }

            // Skip UI update if element has focus
            if (settingElement.contains(document.activeElement)) {
                console.log(`Skipping UI update for ${param.name} - has focus`);
                continue;
            }

            // Skip UI update if user recently changed this parameter
            const lastChange = this.parameterChangeTimestamps[settingKey];
            if (lastChange && now - lastChange < 2000) {
                console.log(`Skipping UI update for ${param.name} - user changed it ${now - lastChange}ms ago`);
                continue;
            }

            // Update UI control based on type (without triggering events)
            if (param.type === 'toggle') {
                const checkbox = settingElement.querySelector('input[type="checkbox"]');
                if (checkbox && checkbox.checked !== param.value) {
                    console.log(`[UPDATE] Toggle ${param.name}: ${checkbox.checked} -> ${param.value}`);
                    checkbox.checked = param.value;
                }
            } else if (param.type === 'slider') {
                const slider = settingElement.querySelector('input[type="range"]');
                const valueDisplay = settingElement.querySelector('.chart-setting__value');
                if (slider && parseFloat(slider.value) !== param.value) {
                    slider.value = param.value;
                    if (valueDisplay) {
                        valueDisplay.textContent = param.value;
                    }
                }
            } else if (param.type === 'select') {
                const select = settingElement.querySelector('select');
                if (select && select.value !== String(param.value)) {
                    console.log(`[UPDATE] Select ${param.name}: ${select.value} -> ${param.value}`);
                    select.value = String(param.value);
                }
            }
        }

        // Re-add event listeners after all updates are complete
        this.restoreEventListeners(settingsContainer, processorId);
    }

    setupEvents(settingsContainer, processorId) {
        const onParamChange = (e) => {
            if (!e.target.closest('.chart-setting')) return;
            this.handleSettingChange(e, processorId);
        };

        const onButtonClick = (e) => {
            if (!e.target.classList.contains('chart-setting__button')) return;
            this.handleButtonClick(e, processorId);
        };

        // Store listeners for later removal/restoration
        this.containerListeners.set(settingsContainer, {
            input: onParamChange,
            change: onParamChange,
            click: onButtonClick
        });

        settingsContainer.addEventListener('input', onParamChange);
        settingsContainer.addEventListener('change', onParamChange);
        settingsContainer.addEventListener('click', onButtonClick);
    }

    removeEventListeners(settingsContainer) {
        const listeners = this.containerListeners.get(settingsContainer);
        if (!listeners) return;

        settingsContainer.removeEventListener('input', listeners.input);
        settingsContainer.removeEventListener('change', listeners.change);
        settingsContainer.removeEventListener('click', listeners.click);
    }

    restoreEventListeners(settingsContainer, processorId) {
        const listeners = this.containerListeners.get(settingsContainer);
        if (!listeners) {
            // If listeners don't exist, set them up
            this.setupEvents(settingsContainer, processorId);
            return;
        }

        settingsContainer.addEventListener('input', listeners.input);
        settingsContainer.addEventListener('change', listeners.change);
        settingsContainer.addEventListener('click', listeners.click);
    }

    handleSettingChange(event, processorId) {
        const settingElement = event.target.closest('.chart-setting');
        if (!settingElement) return;

        const now = Date.now();
        const paramName = settingElement.dataset.param;
        const settingKey = `${processorId}_${paramName}`;

        // Mark user interaction time for both processor and specific parameter
        this.lastUserInteractionTime.set(processorId, now);
        this.parameterChangeTimestamps[settingKey] = now;

        const input = event.target;

        let value;
        if (input.type === 'checkbox') {
            value = input.checked;
        } else if (input.type === 'range') {
            value = parseFloat(input.value);
            const valueDisplay = settingElement.querySelector('.chart-setting__value');
            if (valueDisplay) valueDisplay.textContent = value;
        } else {
            value = input.value;
        }

        // Normalize boolean values
        if (typeof value === 'string' && (value === 'true' || value === 'false')) {
            value = value === 'true';
        }

        let lastValue = this.lastSettingValues[settingKey];
        if (typeof lastValue === 'string' && (lastValue === 'true' || lastValue === 'false')) {
            lastValue = lastValue === 'true';
        }

        console.log(`[CHANGE] ${processorId}.${paramName}: ${lastValue} -> ${value} (type: ${typeof value})`);

        // Check for duplicate
        if (lastValue === value) {
            console.log(`Skipping duplicate value for ${processorId}.${paramName}: ${value}`);
            return;
        }

        this.lastSettingValues[settingKey] = value;
        console.log(`[SAVED] lastSettingValues["${settingKey}"] = ${value}`);

        // Debounce updates
        const debounceKey = `${processorId}_${paramName}`;
        if (this.settingDebounceTimers[debounceKey]) {
            clearTimeout(this.settingDebounceTimers[debounceKey]);
        }

        this.settingDebounceTimers[debounceKey] = setTimeout(() => {
            console.log(`Sending setting update: ${processorId}.${paramName} = ${value}`);
            const websocket = window.vnaDashboard?.websocket;
            if (websocket && websocket.recalculate) {
                websocket.recalculate(processorId, { [paramName]: value });
            } else {
                console.warn('WebSocket not available for settings update');
            }
            delete this.settingDebounceTimers[debounceKey];
        }, 300);
    }

    handleButtonClick(event, processorId) {
        const button = event.target;
        const paramName = button.dataset.param;

        if (!paramName || button.disabled) return;

        console.log(`Button clicked: ${processorId}.${paramName}`);

        const originalText = button.textContent;
        button.disabled = true;
        button.textContent = '...';

        const websocket = window.vnaDashboard?.websocket;
        if (websocket && websocket.recalculate) {
            websocket.recalculate(processorId, { [paramName]: true });
        } else {
            console.warn('WebSocket not available for button action');
        }

        setTimeout(() => {
            button.disabled = false;
            button.textContent = originalText;
        }, 1000);
    }

    destroy() {
        // Clear timers
        Object.keys(this.settingDebounceTimers).forEach(key => {
            clearTimeout(this.settingDebounceTimers[key]);
        });
        this.settingDebounceTimers = {};
        this.lastSettingValues = {};
        this.lastUiParameters.clear();
    }
}
