/**
 * Chart Manager
 * Handles Plotly.js chart creation, updates, and management
 */

import { formatProcessorName, safeClone, downloadJSON } from './utils.js';
import { renderIcons } from './icons.js';
import { ChartSettingsManager } from './charts/chart-settings.js';
import {
    defaultPlotlyLayout,
    defaultPlotlyConfig,
    createPlotlyPlot,
    updatePlotlyPlot,
    togglePlotlyFullscreen,
    downloadPlotlyImage,
    cleanupPlotly
} from './plotly-utils.js';

export class ChartManager {
    constructor(config, notifications) {
        this.config = config;
        this.notifications = notifications;

        this.charts = new Map();
        this.chartData = new Map();
        this.disabledProcessors = new Set();

        this.chartsGrid = null;
        this.emptyState = null;

        this.updateQueue = new Map();
        this.isUpdating = false;
        this.isPaused = false;

        this.performanceStats = {
            chartsCreated: 0,
            updatesProcessed: 0,
            avgUpdateTime: 0,
            lastUpdateTime: null
        };

        this.settingsManager = new ChartSettingsManager();
    }

    async init() {
        console.log('Initializing Chart Manager...');
        this.chartsGrid = document.getElementById('chartsGrid');
        this.emptyState = document.getElementById('emptyState');
        if (!this.chartsGrid || !this.emptyState) throw new Error('Required DOM elements not found');
        if (typeof Plotly === 'undefined') throw new Error('Plotly.js not loaded');
        console.log('Chart Manager initialized');
    }

    addResult(payload) {
        try {
            const { processor_id, timestamp, plotly_config, metadata, data } = payload;
            if (!processor_id) {
                console.warn('Invalid result - missing processor_id:', payload);
                return;
            }

            if (this.disabledProcessors.has(processor_id)) {
                return;
            }

            this.chartData.set(processor_id, {
                timestamp: new Date((timestamp ?? Date.now()) * 1000),
                metadata: metadata || {},
                data: data || {},
                plotly_config: plotly_config || { data: [], layout: {} }
            });

            if (!this.charts.has(processor_id)) this.createChart(processor_id);

            this.updateChart(processor_id, plotly_config || { data: [], layout: {} });
            this.hideEmptyState();
        } catch (e) {
            console.error('Error adding chart result:', e);
            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка графика',
                message: 'Не удалось обновить график'
            });
        }
    }

    createChart(processorId) {
        console.log(`Creating chart for processor: ${processorId}`);
        const card = this.createChartCard(processorId);
        this.chartsGrid.appendChild(card);

        const plotContainer = card.querySelector('.chart-card__plot');
        const layoutOverrides = {
            title: { text: formatProcessorName(processorId), font: { size: 16, color: '#f1f5f9' } },
            width: plotContainer.clientWidth || 500,
            height: plotContainer.clientHeight || 420
        };

        createPlotlyPlot(plotContainer, [], layoutOverrides);

        this.charts.set(processorId, { element: card, plotContainer, isVisible: true, settingsInitialized: false });
        this.performanceStats.chartsCreated++;

        if (this.config.animation) {
            setTimeout(() => card.classList.add('chart-card--animated'), 50);
        }
    }

    updateChart(processorId, plotlyConfig) {
        if (this.isPaused) return;

        const chart = this.charts.get(processorId);
        if (!chart?.plotContainer) {
            console.warn(`Chart not found for processor: ${processorId}`);
            return;
        }

        try {
            const start = performance.now();
            this.queueUpdate(processorId, async () => {
                const layoutOverrides = {
                    ...(plotlyConfig.layout || {}),
                    title: { text: formatProcessorName(processorId), font: { size: 16, color: '#f1f5f9' } }
                };

                await updatePlotlyPlot(chart.plotContainer, plotlyConfig.data || [], layoutOverrides);

                this.updateChartMetadata(processorId);

                if (!chart.settingsInitialized) {
                    this.updateChartSettings(processorId);
                    chart.settingsInitialized = true;
                } else {
                    this.updateChartSettings(processorId);
                }

                const dt = performance.now() - start;
                this.updatePerformanceStats(dt);
            });
        } catch (e) {
            console.error(`Error updating chart ${processorId}:`, e);
        }
    }

    queueUpdate(id, fn) {
        this.updateQueue.set(id, fn);
        if (!this.isUpdating) this.processUpdateQueue();
    }

    async processUpdateQueue() {
        if (this.isPaused) return;
        this.isUpdating = true;
        while (this.updateQueue.size > 0 && !this.isPaused) {
            const [id, fn] = this.updateQueue.entries().next().value;
            this.updateQueue.delete(id);
            try { await fn(); } catch (e) { console.error(`Error in queued update for ${id}:`, e); }
            await new Promise(r => setTimeout(r, 0));
        }
        this.isUpdating = false;
    }

    createChartCard(processorId) {
        const card = document.createElement('div');
        card.className = 'chart-card';
        card.dataset.processor = processorId;

        card.innerHTML = `
            <div class="chart-card__header">
                <div class="chart-card__title">
                    <span data-icon="bar-chart-3" class="chart-card__icon"></span>
                    ${formatProcessorName(processorId)}
                </div>
                <div class="chart-card__actions">
                    <button class="chart-card__action" data-action="fullscreen" title="Fullscreen">
                        <span data-icon="expand"></span>
                    </button>
                    <button class="chart-card__action" data-action="upload" title="Load History">
                        <span data-icon="upload"></span>
                    </button>
                    <button class="chart-card__action" data-action="download" title="Download">
                        <span data-icon="download"></span>
                    </button>
                    <button class="chart-card__action" data-action="hide" title="Hide">
                        <span data-icon="eye-off"></span>
                    </button>
                </div>
                <input type="file" id="historyFileInput_${processorId}" accept=".json" style="display: none;">
            </div>
            <div class="chart-card__content">
                <div class="chart-card__plot" id="plot-${processorId}"></div>
                <div class="chart-card__settings" id="settings-${processorId}">
                    <div class="chart-settings">
                        <div class="chart-settings__header">Settings</div>
                        <div class="chart-settings__controls">
                            <!-- Settings will be populated here -->
                        </div>
                    </div>
                </div>
            </div>
            <div class="chart-card__meta">
                <div class="chart-card__timestamp" data-timestamp="">Last update: --</div>
                <div class="chart-card__sweep" data-sweep=""></div>
            </div>
        `;

        this.setupChartCardEvents(card, processorId);
        this.updateChartSettings(processorId);

        renderIcons(card);
        return card;
    }

    setupChartCardEvents(card, processorId) {
        card.addEventListener('click', (e) => {
            const action = e.target.closest('[data-action]')?.dataset.action;
            if (!action) return;
            e.stopPropagation();
            switch (action) {
                case 'fullscreen': this.toggleFullscreen(processorId); break;
                case 'upload': this.uploadHistory(processorId); break;
                case 'download': this.downloadChart(processorId); break;
                case 'hide':
                    this.hideChart(processorId);
                    if (window.vnaDashboard?.ui) window.vnaDashboard.ui.setProcessorEnabled(processorId, false);
                    break;
            }
        });

        // Setup file input handler
        const fileInput = card.querySelector(`#historyFileInput_${processorId}`);
        if (fileInput) {
            fileInput.addEventListener('change', async (e) => {
                await this.handleHistoryUpload(processorId, e);
            });
        }
    }

    updateChartMetadata(processorId) {
        const chart = this.charts.get(processorId);
        const latestData = this.chartData.get(processorId);
        if (!chart || !latestData) return;

        const tsEl = chart.element.querySelector('[data-timestamp]');
        if (tsEl) {
            const dt = latestData.timestamp instanceof Date ? latestData.timestamp : new Date();
            tsEl.textContent = `Last update: ${dt.toLocaleTimeString()}`;
            tsEl.dataset.timestamp = dt.toISOString();
        }
    }

    updateChartSettings(processorId) {
        const chart = this.charts.get(processorId);
        const settingsContainer = chart?.element?.querySelector('.chart-settings__controls');
        const latestData = this.chartData.get(processorId);

        if (settingsContainer && latestData) {
            this.settingsManager.updateSettings(processorId, settingsContainer, latestData);
        }
    }

    toggleProcessor(id, enabled) { enabled ? this.showChart(id) : this.hideChart(id); }

    showChart(id) {
        const c = this.charts.get(id);
        if (c) {
            c.element.classList.remove('chart-card--hidden');
            c.isVisible = true;
            setTimeout(() => c.plotContainer && Plotly.Plots.resize(c.plotContainer), 100);
        }
        this.updateEmptyStateVisibility();
    }

    hideChart(id) {
        const c = this.charts.get(id);
        if (c) { c.element.classList.add('chart-card--hidden'); c.isVisible = false; }
        this.updateEmptyStateVisibility();
    }

    removeChart(id) {
        const c = this.charts.get(id);
        if (c) {
            cleanupPlotly(c.plotContainer);
            c.element.remove();
            this.charts.delete(id);
            this.chartData.delete(id);
            this.disabledProcessors.delete(id);
        }
        this.updateEmptyStateVisibility();
    }

    clearAll() {
        for (const [id] of this.charts) this.removeChart(id);
        this.charts.clear();
        this.chartData.clear();
        this.updateQueue.clear();
        this.updateEmptyStateVisibility();
    }

    async downloadChart(id) {
        const c = this.charts.get(id);
        if (!c?.plotContainer) return;

        try {
            const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
            const baseFilename = `${id}_${timestamp}`;

            await downloadPlotlyImage(c.plotContainer, `${baseFilename}_plot`);

            const processorData = this.prepareDownloadData(id);
            if (processorData) {
                downloadJSON(processorData, `${baseFilename}_data.json`);
            }

            this.notifications?.show?.({
                type: 'success',
                title: 'Скачивание завершено',
                message: `Скачаны график и данные ${formatProcessorName(id)}`
            });
        } catch (e) {
            console.error('Chart download failed:', e);
            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка скачивания',
                message: 'Не удалось скачать данные графика'
            });
        }
    }

    prepareDownloadData(processorId) {
        const chart = this.charts.get(processorId);
        const latestData = this.chartData.get(processorId);

        if (!chart || !latestData) return null;

        // Extract sweep_history from metadata if available
        const sweepHistory = latestData.metadata?.sweep_history || [];

        return {
            processor_info: {
                processor_id: processorId,
                processor_name: formatProcessorName(processorId),
                download_timestamp: new Date().toISOString()
            },
            current_data: {
                data: safeClone(latestData.data),
                metadata: safeClone(latestData.metadata),
                timestamp: latestData.timestamp instanceof Date ? latestData.timestamp.toISOString() : latestData.timestamp,
                plotly_config: safeClone(latestData.plotly_config)
            },
            sweep_history: sweepHistory
        };
    }

    async toggleFullscreen(id) {
        const c = this.charts.get(id);
        if (!c?.element) return;
        await togglePlotlyFullscreen(c.element, c.plotContainer);
    }

    hideEmptyState() {
        if (this.emptyState) this.emptyState.classList.add('empty-state--hidden');
    }

    updateEmptyStateVisibility() {
        if (!this.emptyState) return;
        const hasVisible = Array.from(this.charts.values()).some(c => c.isVisible);
        this.emptyState.classList.toggle('empty-state--hidden', hasVisible);
    }

    updatePerformanceStats(dt) {
        this.performanceStats.updatesProcessed++;
        this.performanceStats.lastUpdateTime = new Date();
        const total = this.performanceStats.avgUpdateTime * (this.performanceStats.updatesProcessed - 1) + dt;
        this.performanceStats.avgUpdateTime = total / this.performanceStats.updatesProcessed;
    }

    pause() { this.isPaused = true; console.log('Chart updates paused'); }
    resume() { this.isPaused = false; console.log('Chart updates resumed'); if (this.updateQueue.size) this.processUpdateQueue(); }

    getDisabledProcessors() { return Array.from(this.disabledProcessors); }

    getStats() {
        return {
            ...this.performanceStats,
            totalCharts: this.charts.size,
            visibleCharts: Array.from(this.charts.values()).filter(c => c.isVisible).length,
            disabledProcessors: this.disabledProcessors.size,
            queuedUpdates: this.updateQueue.size,
            isPaused: this.isPaused
        };
    }

    uploadHistory(processorId) {
        const chart = this.charts.get(processorId);
        if (!chart) return;

        const fileInput = chart.element.querySelector(`#historyFileInput_${processorId}`);
        if (fileInput) {
            fileInput.click();
        }
    }

    async handleHistoryUpload(processorId, event) {
        const file = event.target.files?.[0];
        if (!file) return;

        try {
            const text = await file.text();
            const jsonData = JSON.parse(text);

            // Extract sweep_history from the saved JSON file
            const sweepHistory = jsonData.sweep_history || [];

            if (!sweepHistory || sweepHistory.length === 0) {
                this.notifications?.show?.({
                    type: 'error',
                    title: 'Ошибка загрузки',
                    message: 'Файл не содержит истории свипов'
                });
                return;
            }

            // Send load_history message via WebSocket
            const websocket = window.vnaDashboard?.websocket;
            if (websocket && websocket.ws && websocket.ws.readyState === WebSocket.OPEN) {
                websocket.ws.send(JSON.stringify({
                    type: 'load_history',
                    processor_id: processorId,
                    history_data: sweepHistory
                }));

                this.notifications?.show?.({
                    type: 'success',
                    title: 'История загружена',
                    message: `Загружено ${sweepHistory.length} записей для ${formatProcessorName(processorId)}`
                });
            } else {
                this.notifications?.show?.({
                    type: 'error',
                    title: 'Ошибка подключения',
                    message: 'WebSocket не подключен'
                });
            }

        } catch (err) {
            console.error('Error loading history:', err);
            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка загрузки',
                message: `Не удалось прочитать файл: ${err.message}`
            });
        }

        // Reset file input
        event.target.value = '';
    }

    destroy() {
        console.log('Cleaning up Chart Manager...');
        this.clearAll();
        this.settingsManager.destroy();
        this.updateQueue.clear();
        this.isUpdating = false;
        this.isPaused = true;
        console.log('Chart Manager cleanup complete');
    }
}
