/**
 * Live cursor tracker for the plot area.
 *
 * Captures mousemove events on the Plotly graph and converts
 * the pixel X position to data coordinates. Writes the result to
 * window.__impakt_hover_x so the Dash Interval callback can poll it.
 *
 * Draws a vertical crosshair line that follows the mouse.
 */
(function () {
    "use strict";

    console.log("[Impakt] cursor_tracker.js loaded");

    var activeLine = null;
    var activeGraphDiv = null;
    var attached = false;

    function findGraphDiv() {
        // Dash renders pattern-matching IDs as JSON strings in the id attribute
        var candidates = document.querySelectorAll(".dash-graph .js-plotly-plot");
        if (candidates.length > 0) return candidates[0];

        // Fallback: any plotly plot
        candidates = document.querySelectorAll(".js-plotly-plot");
        if (candidates.length > 0) return candidates[0];

        return null;
    }

    function getPlotArea(graphDiv) {
        // The drag overlay that covers the plot area
        // Plotly uses different class names across versions
        var area = graphDiv.querySelector(".nsewdrag");
        if (area) return area;

        // Plotly 6.x may use .drag[data-subplot]
        area = graphDiv.querySelector(".drag");
        if (area) return area;

        // Try the cartesian layer
        area = graphDiv.querySelector(".cartesianlayer");
        return area;
    }

    function pixelToDataX(graphDiv, pixelX, plotAreaRect) {
        // Method 1: Use Plotly's _fullLayout.xaxis (most reliable)
        var layout = graphDiv._fullLayout;
        if (layout && layout.xaxis) {
            var xaxis = layout.xaxis;

            // p2d converts pixel to data coordinate
            if (typeof xaxis.p2d === "function") {
                // p2d expects pixels relative to the plot area left edge
                var plotLeft = xaxis._offset || 0;
                return xaxis.p2d(pixelX - plotLeft + xaxis._offset);
            }

            // Fallback: manual linear interpolation from axis range and pixel domain
            if (xaxis.range && xaxis._length) {
                var dataMin = xaxis.range[0];
                var dataMax = xaxis.range[1];
                var pxOffset = xaxis._offset || 0;
                var pxLength = xaxis._length;
                var fraction = (pixelX) / pxLength;
                return dataMin + fraction * (dataMax - dataMin);
            }
        }

        return null;
    }

    function initTracker() {
        var graphDiv = findGraphDiv();
        if (!graphDiv) {
            console.log("[Impakt] No graph div found yet, retrying...");
            setTimeout(initTracker, 500);
            return;
        }

        var plotArea = getPlotArea(graphDiv);
        if (!plotArea) {
            console.log("[Impakt] No plot area found yet, retrying...");
            setTimeout(initTracker, 500);
            return;
        }

        if (attached && activeGraphDiv === graphDiv) return;

        console.log("[Impakt] Attaching cursor tracker to", graphDiv.id || "(unnamed graph)");
        console.log("[Impakt] Plot area element:", plotArea.className);

        // Log what axis info is available
        if (graphDiv._fullLayout && graphDiv._fullLayout.xaxis) {
            var xa = graphDiv._fullLayout.xaxis;
            console.log("[Impakt] xaxis available:", {
                range: xa.range,
                _offset: xa._offset,
                _length: xa._length,
                p2d: typeof xa.p2d,
                p2l: typeof xa.p2l,
                l2p: typeof xa.l2p,
                d2p: typeof xa.d2p,
            });
        } else {
            console.log("[Impakt] No _fullLayout.xaxis yet");
        }

        activeGraphDiv = graphDiv;

        // Attach to the entire graph container, not just the drag area,
        // to ensure we capture mouse events everywhere
        graphDiv.addEventListener("mousemove", function (e) {
            var layout = graphDiv._fullLayout;
            if (!layout || !layout.xaxis) return;

            var xa = layout.xaxis;
            var graphRect = graphDiv.getBoundingClientRect();

            // Pixel position relative to the graph div
            var pixelFromLeft = e.clientX - graphRect.left;

            // The plot area starts at xa._offset from the left of the graph div
            var plotAreaLeft = xa._offset || 0;
            var plotAreaWidth = xa._length || 1;

            // Pixel position within the plot area
            var plotPixel = pixelFromLeft - plotAreaLeft;

            // Only process if within the plot area
            if (plotPixel < 0 || plotPixel > plotAreaWidth) {
                return;
            }

            // Convert to data coordinate
            var dataX;
            if (typeof xa.p2d === "function") {
                dataX = xa.p2d(plotPixel);
            } else if (typeof xa.p2l === "function") {
                // p2l converts pixel to "linear" value, which for linear axes = data value
                dataX = xa.p2l(plotPixel);
            } else if (xa.range) {
                // Manual linear interpolation
                var fraction = plotPixel / plotAreaWidth;
                dataX = xa.range[0] + fraction * (xa.range[1] - xa.range[0]);
            } else {
                return;
            }

            if (dataX === undefined || dataX === null || isNaN(dataX)) return;

            window.__impakt_hover_x = dataX;

            // Draw vertical crosshair
            drawCrosshair(graphDiv, plotAreaLeft + plotPixel, graphRect);
        });

        graphDiv.addEventListener("mouseleave", function () {
            removeCrosshair();
        });

        attached = true;
    }

    function drawCrosshair(graphDiv, pixelX, graphRect) {
        removeCrosshair();

        var container = graphDiv.querySelector(".plot-container") || graphDiv;

        var line = document.createElement("div");
        line.className = "impakt-crosshair";
        line.style.cssText = [
            "position: absolute",
            "top: 0",
            "bottom: 0",
            "width: 1px",
            "background-color: rgba(0,0,0,0.25)",
            "pointer-events: none",
            "z-index: 1000",
            "left: " + pixelX + "px",
        ].join(";");

        // Ensure container is positioned
        if (!container.style.position || container.style.position === "static") {
            container.style.position = "relative";
        }

        container.appendChild(line);
        activeLine = line;
    }

    function removeCrosshair() {
        if (activeLine && activeLine.parentNode) {
            activeLine.parentNode.removeChild(activeLine);
        }
        activeLine = null;
        // Clean up any stale ones
        document.querySelectorAll(".impakt-crosshair").forEach(function (el) {
            el.remove();
        });
    }

    // Re-initialize when Dash re-renders the graph (e.g., after channel selection changes)
    function watchForGraphChanges() {
        var observer = new MutationObserver(function (mutations) {
            // Check if a new graph appeared
            var graphDiv = findGraphDiv();
            if (graphDiv && graphDiv !== activeGraphDiv) {
                attached = false;
                initTracker();
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    // Start
    function boot() {
        console.log("[Impakt] cursor_tracker.js booting");
        initTracker();
        watchForGraphChanges();
    }

    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", function () {
            setTimeout(boot, 500);
        });
    } else {
        setTimeout(boot, 500);
    }
})();
