// Engagement heatmap display
// Fetches aggregated watch data and renders vertical bar heatmap directly on the Plyr progress bar track.

let heatmapContainer = null;
let heatmapCanvas = null;
let heatmapResizeObserver = null;

/**
 * Fetch engagement data from the server and render the heatmap.
 * @param {string} episodeId - The episode ID.
 * @param {number} duration - Video duration in seconds.
 */
export async function renderHeatmap(episodeId, duration) {
    try {
        const response = await window.axios.get(`/player/engagement/${episodeId}`);
        const data = response.data;

        if (!data || Object.keys(data).length === 0) {
            return;
        }

        drawHeatmapCurve(data, duration);
    } catch (error) {
        console.error('Failed to load engagement data:', error);
    }
}

/**
 * Draw a smooth area chart on a canvas element above the progress bar.
 * @param {Object} data - Key-value map of segment -> watch_count.
 * @param {number} duration - Video duration in seconds.
 */
function drawHeatmapCurve(data, duration) {
    const SEGMENT_DURATION = 10;
    const totalSegments = Math.ceil(duration / SEGMENT_DURATION);

    // Build raw counts array, filling gaps with 0
    const rawCounts = [];
    for (let i = 0; i < totalSegments; i++) {
        rawCounts.push(data[i] || 0);
    }

    // Apply 3-point moving average to smooth individual spikes
    const counts = smoothData(rawCounts);

    const maxCount = Math.max(...counts, 1);

    // Remove existing heatmap if present
    if (heatmapContainer) {
        if (heatmapResizeObserver) heatmapResizeObserver.disconnect();
        heatmapContainer.remove();
        heatmapCanvas = null;
    }

    // Find the progress bar wrapper
    const progressBar = document.querySelector('.plyr__progress');
    if (!progressBar) return;

    // Create container
    heatmapContainer = document.createElement('div');
    heatmapContainer.className = 'plyr__progress__heatmap';
    heatmapContainer.setAttribute('aria-hidden', 'true');

    // Create canvas
    heatmapCanvas = document.createElement('canvas');
    heatmapCanvas.className = 'plyr__progress__heatmap-canvas';
    heatmapContainer.appendChild(heatmapCanvas);

    // Insert as first child of the progress bar so it sits behind the scrubber
    progressBar.insertBefore(heatmapContainer, progressBar.firstChild);

    // Defer drawing to get container dimensions
    requestAnimationFrame(() => {
        requestAnimationFrame(() => drawCurve(heatmapCanvas, counts, maxCount));
    });

    // Redraw on resize
    heatmapResizeObserver = new ResizeObserver(() => {
        drawCurve(heatmapCanvas, counts, maxCount);
    });
    heatmapResizeObserver.observe(heatmapContainer);
}

/**
 * Apply a 3-point moving average to smooth out jaggedness.
 * Preserves the first and last points.
 */
function smoothData(data) {
    if (data.length <= 2) return [...data];

    const smoothed = [data[0]]; // preserve first

    for (let i = 1; i < data.length - 1; i++) {
        smoothed.push((data[i - 1] + data[i] + data[i + 1]) / 3);
    }

    smoothed.push(data[data.length - 1]); // preserve last
    return smoothed;
}

/**
 * Render vertical bar heatmap directly on the progress bar track.
 * Each bar represents a time segment; taller bars = more engagement.
 */
function drawCurve(canvas, counts, maxCount) {
    const parent = canvas.parentElement;
    if (!parent) return;

    const rect = parent.getBoundingClientRect();
    if (rect.width === 0 || rect.height === 0) return;

    const dpr = window.devicePixelRatio || 1;
    const w = rect.width;
    const h = rect.height;

    canvas.width = Math.round(w * dpr);
    canvas.height = Math.round(h * dpr);
    canvas.style.width = w + 'px';
    canvas.style.height = h + 'px';

    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);
    ctx.clearRect(0, 0, w, h);

    if (counts.length === 0 || maxCount === 0) return;

    // Padding: leave 1px on each side so the curve doesn't clip at edges
    const paddingX = 1;
    const paddingY = 1;
    const drawW = w - paddingX * 2;
    const drawH = h - paddingY * 2;
    const baseline = paddingY + drawH / 2; // curve oscillates around the center
    const amplitude = (drawH / 2) * 0.8;   // 80% of half-height to keep inside bounds
    const n = counts.length;

    // Build data points: x = horizontal position, y = vertical offset from center
    const pts = [];
    for (let i = 0; i < n; i++) {
        const x = paddingX + (i / (n - 1 || 1)) * drawW;
        const ratio = counts[i] / maxCount;
        // ratio 0 = bottom of amplitude range, ratio 1 = top of amplitude range
        const y = baseline - (ratio - 0.5) * amplitude * 2;
        pts.push({ x, y });
    }

    if (pts.length < 2) return;

    // Build the smooth path using quadratic bezier curves through midpoints
    const path = [{ x: pts[0].x, y: pts[0].y }];

    for (let i = 0; i < pts.length - 1; i++) {
        const midX = (pts[i].x + pts[i + 1].x) / 2;
        const midY = (pts[i].y + pts[i + 1].y) / 2;
        path.push({ x: midX, y: midY, cp: { x: pts[i].x, y: pts[i].y } });
    }
    path.push({ x: pts[pts.length - 1].x, y: pts[pts.length - 1].y });

    // --- Draw a subtle glow behind the line ---
    ctx.beginPath();
    ctx.moveTo(path[0].x, path[0].y);
    for (let i = 1; i < path.length; i++) {
        const prev = path[i - 1];
        const curr = path[i];
        if (curr.cp) {
            ctx.quadraticCurveTo(curr.cp.x, curr.cp.y, curr.x, curr.y);
        } else {
            ctx.lineTo(curr.x, curr.y);
        }
    }
    ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';
    ctx.lineWidth = 3.0;
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.stroke();

    // --- Draw the main waveform line ---
    ctx.beginPath();
    ctx.moveTo(path[0].x, path[0].y);
    for (let i = 1; i < path.length; i++) {
        const prev = path[i - 1];
        const curr = path[i];
        if (curr.cp) {
            ctx.quadraticCurveTo(curr.cp.x, curr.cp.y, curr.x, curr.y);
        } else {
            ctx.lineTo(curr.x, curr.y);
        }
    }
    ctx.strokeStyle = 'rgba(255, 255, 255, 0.55)';
    ctx.lineWidth = 1.5;
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.stroke();
}

/**
 * Remove the heatmap from the DOM.
 */
export function removeHeatmap() {
    if (heatmapResizeObserver) {
        heatmapResizeObserver.disconnect();
        heatmapResizeObserver = null;
    }
    if (heatmapContainer) {
        heatmapContainer.remove();
        heatmapContainer = null;
        heatmapCanvas = null;
    }
}