/**
 * B-Scan Click Handler
 * Handles column deletion clicks on the B-Scan heatmap
 */

import { createPlotlyPlot, cleanupPlotly } from '../plotly-utils.js';

export class BScanClickHandler {
    constructor(websocket, notifications) {
        this.websocket = websocket;
        this.notifications = notifications;
        this.activeListeners = new Map();
        this.selectedColumn = null;
        this.selectedProcessorId = null;
        this.keyboardListener = null;
    }

    /**
     * Attach click handler to a B-Scan plot container
     * @param {string} processorId - Processor ID (e.g., "bscan")
     * @param {HTMLElement} plotContainer - Plot container element
     */
    attachClickHandler(processorId, plotContainer) {
        if (!plotContainer || this.activeListeners.has(processorId)) {
            return;
        }

        const clickHandler = (data) => {
            // Check if user clicked on a heatmap point
            if (!data.points || data.points.length === 0) {
                return;
            }

            const point = data.points[0];
            const columnIndex = point.x; // X-axis represents sweep/column number (1-based)

            if (!columnIndex || typeof columnIndex !== 'number') {
                return;
            }

            // Select/highlight the column
            this.selectColumn(processorId, columnIndex, plotContainer);
        };

        // Attach Plotly click event
        plotContainer.on('plotly_click', clickHandler);
        this.activeListeners.set(processorId, { clickHandler, plotContainer });

        // Setup keyboard listener if not already done
        if (!this.keyboardListener) {
            this.setupKeyboardListener();
        }
    }

    /**
     * Remove click handler from a plot container
     * @param {string} processorId - Processor ID
     * @param {HTMLElement} plotContainer - Plot container element
     */
    detachClickHandler(processorId, plotContainer) {
        const listenerData = this.activeListeners.get(processorId);
        if (listenerData && plotContainer) {
            plotContainer.removeListener('plotly_click', listenerData.clickHandler);
            this.activeListeners.delete(processorId);
        }

        // Clear selection if this processor was selected
        if (this.selectedProcessorId === processorId) {
            this.clearSelection();
        }
    }

    /**
     * Select and highlight a column
     * @param {string} processorId - Processor ID
     * @param {number} columnIndex - Column index (1-based)
     * @param {HTMLElement} plotContainer - Plot container element
     */
    selectColumn(processorId, columnIndex, plotContainer) {
        this.selectedColumn = columnIndex;
        this.selectedProcessorId = processorId;

        // Add visual highlight by adding a vertical line shape
        this.highlightColumn(plotContainer, columnIndex);

        console.log(`Column ${columnIndex} selected. Press 'D' to delete, 'P' to preview depth profile.`);
    }

    /**
     * Add visual highlight to the selected column
     * @param {HTMLElement} plotContainer - Plot container element
     * @param {number} columnIndex - Column index (1-based)
     */
    highlightColumn(plotContainer, columnIndex) {
        if (!plotContainer || typeof Plotly === 'undefined') {
            return;
        }

        // Add a vertical line shape to highlight the column
        const update = {
            shapes: [{
                type: 'line',
                x0: columnIndex - 0.5,
                x1: columnIndex - 0.5,
                y0: 0,
                y1: 1,
                yref: 'paper',
                line: {
                    color: 'rgba(255, 0, 0, 0.8)',
                    width: 3,
                    dash: 'solid'
                }
            }, {
                type: 'line',
                x0: columnIndex + 0.5,
                x1: columnIndex + 0.5,
                y0: 0,
                y1: 1,
                yref: 'paper',
                line: {
                    color: 'rgba(255, 0, 0, 0.8)',
                    width: 3,
                    dash: 'solid'
                }
            }]
        };

        Plotly.relayout(plotContainer, update);
    }

    /**
     * Clear column selection and highlighting
     */
    clearSelection() {
        if (!this.selectedProcessorId || !this.selectedColumn) {
            return;
        }

        const listenerData = this.activeListeners.get(this.selectedProcessorId);
        if (listenerData && listenerData.plotContainer && typeof Plotly !== 'undefined') {
            // Remove shapes (highlighting)
            Plotly.relayout(listenerData.plotContainer, { shapes: [] });
        }

        this.selectedColumn = null;
        this.selectedProcessorId = null;

        console.log('Selection cleared');
    }

    /**
     * Setup keyboard listener for 'D' key
     */
    setupKeyboardListener() {
        this.keyboardListener = (event) => {
            // Ignore if user is typing in an input field
            const activeElement = document.activeElement;
            if (activeElement && (
                activeElement.tagName === 'INPUT' ||
                activeElement.tagName === 'TEXTAREA' ||
                activeElement.isContentEditable
            )) {
                return;
            }

            // Check if 'D' key is pressed (case insensitive)
            if (event.key === 'd' || event.key === 'D') {
                // Delete selected column if any
                if (this.selectedColumn !== null && this.selectedProcessorId !== null) {
                    event.preventDefault();
                    this.showDeleteConfirmation(this.selectedProcessorId, this.selectedColumn);
                }
            } else if (event.key === 'p' || event.key === 'P') {
                // Show column depth profile (A-scan)
                if (this.selectedColumn !== null && this.selectedProcessorId !== null) {
                    event.preventDefault();
                    this.showColumnProfile(this.selectedProcessorId, this.selectedColumn);
                }
            } else if (event.key === 'Escape') {
                // Clear selection on Escape
                this.clearSelection();
            }
        };

        document.addEventListener('keydown', this.keyboardListener);
        console.log('Keyboard shortcuts: D - delete column, P - preview column depth profile, Escape - deselect');
    }

    /**
     * Show confirmation dialog for column deletion
     * @param {string} processorId - Processor ID
     * @param {number} columnIndex - Column index to delete (1-based)
     */
    showDeleteConfirmation(processorId, columnIndex) {
        const message = `Вы хотите удалить столбец ${columnIndex}?`;

        if (confirm(message)) {
            this.deleteColumn(processorId, columnIndex);
        }
    }

    /**
     * Send delete column command to backend
     * @param {string} processorId - Processor ID
     * @param {number} columnIndex - Column index to delete (1-based)
     */
    deleteColumn(processorId, columnIndex) {
        // Get websocket from global window object if not available in instance
        const websocket = this.websocket || window.vnaDashboard?.websocket;

        console.log('deleteColumn called:', { processorId, columnIndex, websocket, ws: websocket?.ws, readyState: websocket?.ws?.readyState });

        if (!websocket || !websocket.ws || websocket.ws.readyState !== WebSocket.OPEN) {
            console.error('WebSocket not available or not open:', {
                hasWebsocket: !!websocket,
                hasWs: !!websocket?.ws,
                readyState: websocket?.ws?.readyState,
                OPEN: WebSocket.OPEN
            });

            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка подключения',
                message: 'WebSocket не подключен'
            });
            return;
        }

        try {
            const message = {
                type: 'delete_column',
                processor_id: processorId,
                column_index: columnIndex
            };

            console.log('Sending delete column message:', message);
            websocket.ws.send(JSON.stringify(message));

            this.notifications?.show?.({
                type: 'info',
                title: 'Удаление столбца',
                message: `Удаление столбца ${columnIndex}...`
            });

        } catch (error) {
            console.error('Failed to send delete column command:', error);
            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка удаления',
                message: `Не удалось удалить столбец ${columnIndex}`
            });
        }
    }

    /**
     * Show column depth profile (A-scan) modal for selected column
     * @param {string} processorId - Processor ID
     * @param {number} columnIndex - Column index (1-based)
     */
    showColumnProfile(processorId, columnIndex) {
        // Get websocket from global window object if not available in instance
        const websocket = this.websocket || window.vnaDashboard?.websocket;

        if (!websocket || !websocket.ws || websocket.ws.readyState !== WebSocket.OPEN) {
            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка подключения',
                message: 'WebSocket не подключен'
            });
            return;
        }

        try {
            // Request processor state to get column data
            const message = {
                type: 'get_processor_state',
                processor_id: processorId
            };

            console.log('Requesting processor state for column profile:', message);

            // Set up one-time listener for the response
            const handleResponse = (event) => {
                try {
                    const response = JSON.parse(event.data);

                    if (response.type === 'processor_state' && response.processor_id === processorId) {
                        // Remove this listener
                        websocket.ws.removeEventListener('message', handleResponse);

                        // Extract column data from plot history
                        this.displayColumnModal(response, columnIndex);
                    }
                } catch (error) {
                    console.error('Error parsing processor state response:', error);
                }
            };

            websocket.ws.addEventListener('message', handleResponse);
            websocket.ws.send(JSON.stringify(message));

        } catch (error) {
            console.error('Failed to request column profile:', error);
            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка предпросмотра',
                message: 'Не удалось загрузить данные столбца'
            });
        }
    }

    /**
     * Display column depth profile data in modal window
     * @param {Object} processorState - Processor state from backend
     * @param {number} columnIndex - Column index (1-based)
     */
    displayColumnModal(processorState, columnIndex) {
        const plotData = processorState.state?.plot_data || {};
        const config = processorState.state?.config || {};

        // Get plot history data from plot_data
        const allTimeData = plotData.all_time_domain_data || [];
        const allDistanceData = plotData.all_distance_data || [];

        console.log('Plot data available:', {
            columns: allTimeData.length,
            requestedColumn: columnIndex,
            allTimeDataLength: allTimeData.length,
            allDistanceDataLength: allDistanceData.length
        });

        // Convert 1-based column index to 0-based array index
        const columnArrayIndex = columnIndex - 1;

        if (columnArrayIndex < 0 || columnArrayIndex >= allTimeData.length) {
            this.notifications?.show?.({
                type: 'error',
                title: 'Ошибка',
                message: `Столбец ${columnIndex} не найден в данных (доступно столбцов: ${allTimeData.length})`
            });
            return;
        }

        const amplitudeData = allTimeData[columnArrayIndex];
        const depthData = allDistanceData[columnArrayIndex];

        if (!amplitudeData || amplitudeData.length === 0 || !depthData || depthData.length === 0) {
            this.notifications?.show?.({
                type: 'warning',
                title: 'Нет данных',
                message: `Столбец ${columnIndex} не содержит данных для отображения`
            });
            return;
        }

        // Show modal with depth profile plot
        this.showColumnProfileModal(
            columnIndex,
            amplitudeData,
            depthData,
            config
        );
    }

    /**
     * Determine if sweep contains calibrated data that differs from raw points.
     * @param {Object} sweep - Sweep data entry from processor state
     * @returns {boolean} True when calibrated points appear to be applied
     */
    hasCalibratedSweepData(sweep) {
        const calibratedPoints = Array.isArray(sweep?.calibrated_points) ? sweep.calibrated_points : [];
        if (calibratedPoints.length === 0) {
            return false;
        }

        const rawPoints = Array.isArray(sweep?.sweep_points) ? sweep.sweep_points : [];
        if (rawPoints.length === 0 || calibratedPoints.length !== rawPoints.length) {
            return true;
        }

        const tolerance = 1e-9;
        let comparablePoints = 0;

        for (let i = 0; i < calibratedPoints.length; i++) {
            const calibrated = this._extractComplexPoint(calibratedPoints[i]);
            const raw = this._extractComplexPoint(rawPoints[i]);

            if (!this._canCompareComplexPoints(calibrated, raw)) {
                continue;
            }

            comparablePoints++;

            if (!this._areComplexPointsClose(calibrated, raw, tolerance)) {
                return true;
            }
        }

        return false;
    }

    _extractComplexPoint(point) {
        if (!point) {
            return { real: NaN, imag: NaN };
        }

        if (Array.isArray(point)) {
            return {
                real: this._toFiniteNumber(point[0]),
                imag: this._toFiniteNumber(point[1])
            };
        }

        if (typeof point === 'object') {
            const realCandidate = point.real ?? point.r ?? point.Re ?? point.re;
            const imagCandidate = point.imag ?? point.i ?? point.Im ?? point.im;
            return {
                real: this._toFiniteNumber(realCandidate),
                imag: this._toFiniteNumber(imagCandidate)
            };
        }

        return { real: NaN, imag: NaN };
    }

    _toFiniteNumber(value) {
        if (typeof value === 'number') {
            return Number.isFinite(value) ? value : NaN;
        }
        if (typeof value === 'string' && value.trim().length > 0) {
            const parsed = Number(value);
            return Number.isFinite(parsed) ? parsed : NaN;
        }
        return NaN;
    }

    _canCompareComplexPoints(a, b) {
        return Number.isFinite(a.real) && Number.isFinite(a.imag) && Number.isFinite(b.real) && Number.isFinite(b.imag);
    }

    _areComplexPointsClose(a, b, tolerance) {
        const realScale = Math.max(1, Math.abs(a.real), Math.abs(b.real));
        const imagScale = Math.max(1, Math.abs(a.imag), Math.abs(b.imag));

        return Math.abs(a.real - b.real) <= tolerance * realScale &&
            Math.abs(a.imag - b.imag) <= tolerance * imagScale;
    }

    /**
     * Show modal with column depth profile (A-scan) plot
     * @param {number} columnNumber - Column number (1-based)
     * @param {Array} amplitudeData - Amplitude values
     * @param {Array} depthData - Depth values in meters
     * @param {Object} config - Processor configuration
     */
    showColumnProfileModal(columnNumber, amplitudeData, depthData, config) {
        // Get modal element
        const modal = document.getElementById('plotsModal');
        if (!modal) {
            console.error('Plots modal not found');
            return;
        }

        // Create Plotly trace - A-scan format (depth on X-axis, amplitude on Y-axis)
        const traces = [
            {
                x: depthData,
                y: amplitudeData,
                type: 'scatter',
                mode: 'lines',
                name: 'Амплитуда',
                line: { color: '#3b82f6', width: 2 }
            }
        ];

        // Build descriptive title
        const axisType = config.axis || 'abs';
        const refStatus = config.open_air ? 'с вычетом референса' : 'без вычета референса';
        const titleText = `Столбец ${columnNumber} - Профиль глубины (${axisType}, ${refStatus})`;

        const layoutOverrides = {
            title: { text: titleText, font: { size: 16, color: '#f1f5f9' } },
            xaxis: {
                title: 'Глубина (м)',
                gridcolor: '#334155',
                zerolinecolor: '#475569',
                color: '#cbd5e1',
                fixedrange: false
            },
            yaxis: {
                title: 'Амплитуда',
                gridcolor: '#334155',
                zerolinecolor: '#475569',
                color: '#cbd5e1',
                fixedrange: false
            },
            showlegend: false,
            height: 500
        };

        const configOverrides = {
            toImageButtonOptions: {
                format: 'png',
                filename: `column-${columnNumber}-profile`,
                height: 600,
                width: 800,
                scale: 1
            }
        };

        // Update modal title
        const title = modal.querySelector('.modal__title');
        if (title) {
            title.textContent = titleText;
        }

        // Get plots grid container and clear it
        const container = document.getElementById('plotsGrid');
        if (!container) {
            console.error('Plots grid container not found');
            return;
        }
        container.innerHTML = '';

        // Create card wrapper with proper styling
        const card = document.createElement('div');
        card.className = 'chart-card';
        card.innerHTML = `
            <div class="chart-card__header">
                <div class="chart-card__title">${titleText}</div>
            </div>
            <div class="chart-card__content">
                <div class="chart-card__plot" id="column-profile-plot"></div>
            </div>
        `;
        container.appendChild(card);

        // Setup close handlers
        this.setupModalCloseHandlers(modal);

        // Show modal
        modal.classList.add('modal--active');
        document.body.style.overflow = 'hidden';

        // Create plot after modal is shown
        setTimeout(() => {
            const plotElement = document.getElementById('column-profile-plot');
            if (plotElement) {
                createPlotlyPlot(plotElement, traces, layoutOverrides, configOverrides);
            } else {
                console.error('Plot element not found');
            }
        }, 50);
    }

    /**
     * Setup modal close handlers
     * @param {HTMLElement} modal - Modal element
     */
    setupModalCloseHandlers(modal) {
        const closeElements = modal.querySelectorAll('[data-modal-close]');
        closeElements.forEach(el => {
            el.onclick = () => this.closeModal(modal);
        });
    }

    /**
     * Close modal
     * @param {HTMLElement} modal - Modal element
     */
    closeModal(modal) {
        modal.classList.remove('modal--active');
        document.body.style.overflow = '';

        // Cleanup Plotly plot - try both possible plot IDs
        const profilePlot = document.getElementById('column-profile-plot');
        if (profilePlot) {
            cleanupPlotly(profilePlot);
        }

        const sweepPlot = document.getElementById('sweep-preview-plot');
        if (sweepPlot) {
            cleanupPlotly(sweepPlot);
        }
    }

    /**
     * Called when data is updated (new columns added, imported, etc.)
     * Clears the current selection
     * @param {string} processorId - Processor ID
     */
    onDataUpdate(processorId) {
        // Clear selection if this processor's data was updated
        if (this.selectedProcessorId === processorId) {
            this.clearSelection();
        }
    }

    /**
     * Clean up all listeners
     */
    destroy() {
        // Remove keyboard listener
        if (this.keyboardListener) {
            document.removeEventListener('keydown', this.keyboardListener);
            this.keyboardListener = null;
        }

        // Clear selection
        this.clearSelection();

        // Clear active listeners
        this.activeListeners.clear();

        console.log('BScanClickHandler destroyed');
    }
}
