<!DOCTYPE html>
<html>
<head>
    <title>Pickle Vision - Referee System</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            background: #0a0a1a;
            color: #e0e0e0;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
            overflow-x: hidden;
        }

        /* Header */
        .header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 12px 24px;
            background: #111128;
            border-bottom: 1px solid #2a2a4a;
        }
        .logo { font-size: 20px; font-weight: 700; color: #4ecca3; }
        .tabs { display: flex; gap: 4px; }
        .tab {
            padding: 8px 20px;
            border: 1px solid #333;
            border-radius: 6px;
            background: transparent;
            color: #888;
            cursor: pointer;
            font-size: 14px;
            transition: all 0.2s;
        }
        .tab:hover { color: #ccc; border-color: #555; }
        .tab.active {
            background: #4ecca3;
            color: #000;
            border-color: #4ecca3;
            font-weight: 600;
        }
        .status-bar {
            display: flex;
            gap: 16px;
            font-size: 13px;
            color: #666;
        }
        .status-bar .val { color: #4ecca3; font-weight: 600; }

        /* Tab content */
        .tab-content { display: none; }
        .tab-content.active { display: block; }

        /* Camera feeds */
        .cameras {
            display: flex;
            gap: 8px;
            padding: 8px;
            justify-content: center;
        }
        .cam-box {
            flex: 1;
            max-width: 50%;
            position: relative;
        }
        .cam-box img {
            width: 100%;
            border-radius: 6px;
            border: 1px solid #222;
            display: block;
        }
        .cam-label {
            position: absolute;
            top: 8px;
            left: 8px;
            background: rgba(0,0,0,0.7);
            color: #4ecca3;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 12px;
            font-weight: 600;
        }

        /* 3D viewport */
        .viewport-3d {
            width: 100%;
            height: 400px;
            border-top: 1px solid #222;
            position: relative;
        }
        .viewport-3d canvas { width: 100% !important; height: 100% !important; }

        /* Full-height tab layout: 3D on top, small bottom bar */
        .tab-full {
            display: flex;
            flex-direction: column;
            height: calc(100vh - 52px);
        }
        .tab-full .viewport-3d {
            flex: 1;
            height: auto;
            border-top: none;
        }
        .bottom-bar {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            padding: 6px 8px;
            background: #0d0d20;
            border-top: 1px solid #222;
        }
        .cam-thumb {
            width: 200px;
            flex-shrink: 0;
        }
        .cam-thumb img {
            width: 100%;
            border-radius: 4px;
            border: 1px solid #222;
            display: block;
        }

        /* Sidebar panel (calibration, etc.) */
        .sidebar-panel {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 4px 12px;
        }
        .btn-calibrate {
            width: 100%;
            padding: 8px 12px;
            background: #4ecca3;
            color: #000;
            border: none;
            border-radius: 6px;
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
        }
        .btn-calibrate:hover { background: #3dbb92; }
        .btn-calibrate:disabled { background: #333; color: #666; cursor: not-allowed; }
        .calibrate-status {
            font-size: 11px;
            color: #666;
            line-height: 1.6;
        }
        .calibrate-status .ok { color: #4ecca3; }
        .calibrate-status .fail { color: #ff4444; }

        /* VAR panel (bottom bar version) */
        .var-panel-bottom {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 4px 12px;
        }
        .var-indicator {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .var-dot {
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #333;
            transition: background 0.3s;
        }
        .var-dot.active {
            background: #ff3333;
            box-shadow: 0 0 12px rgba(255, 51, 51, 0.6);
            animation: var-pulse 1.5s infinite;
        }
        @keyframes var-pulse {
            0%, 100% { box-shadow: 0 0 8px rgba(255, 51, 51, 0.4); }
            50% { box-shadow: 0 0 20px rgba(255, 51, 51, 0.8); }
        }
        .var-label { font-size: 14px; font-weight: 700; color: #888; }
        .var-label.active { color: #ff3333; }

        .var-info {
            display: flex;
            flex-direction: column;
            justify-content: center;
            font-size: 13px;
            color: #888;
            min-width: 200px;
        }
        .var-info .var-line { color: #e0e0e0; font-weight: 600; }
        .var-info .var-timer { color: #ff6666; font-size: 16px; font-weight: 700; }
        .var-info .var-dist { color: #aaa; }

        .var-snapshot {
            width: 100%;
            border-radius: 4px;
            border: 1px solid #333;
            object-fit: cover;
            background: #1a1a2e;
        }
        .var-snapshot.empty {
            display: flex;
            align-items: center;
            justify-content: center;
            color: #444;
            font-size: 11px;
            height: 60px;
        }

        /* Event banner */
        .event-banner {
            display: none;
            position: fixed;
            top: 60px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(255, 60, 60, 0.95);
            color: white;
            padding: 12px 32px;
            border-radius: 8px;
            font-size: 18px;
            font-weight: 700;
            z-index: 100;
            animation: pulse 1s infinite;
        }
        .event-banner.show { display: block; }
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.7; }
        }

        /* Info panel */
        .info-panel {
            display: flex;
            gap: 24px;
            padding: 8px 24px;
            background: #111128;
            border-top: 1px solid #2a2a4a;
            font-size: 13px;
            justify-content: center;
            flex-wrap: wrap;
        }
        .info-item .label { color: #666; }
        .info-item .value { color: #4ecca3; font-weight: 600; margin-left: 4px; }
    </style>
</head>
<body>

<div class="header">
    <div class="logo">Pickle Vision</div>
    <div class="tabs">
        <button class="tab active" data-tab="detection">Detection</button>
        <button class="tab" data-tab="court">Court</button>
        <button class="tab" data-tab="trajectory">Trajectory</button>
    </div>
    <div class="status-bar">
        <div>CAM0: <span class="val" id="fps0">--</span> fps</div>
        <div>CAM1: <span class="val" id="fps1">--</span> fps</div>
    </div>
</div>

<div class="event-banner" id="eventBanner">VAR: Close Call</div>

<!-- Tab 1: Detection -->
<div class="tab-content active" id="tab-detection">
    <div class="cameras">
        <div class="cam-box">
            <img id="det-cam1" alt="Camera 1">
        </div>
        <div class="cam-box">
            <img id="det-cam0" alt="Camera 0">
        </div>
    </div>
</div>

<!-- Tab 2: Court — 3D main, cameras small bottom center -->
<div class="tab-content" id="tab-court">
    <div class="tab-full">
        <div class="viewport-3d" id="court-3d"></div>
        <div class="bottom-bar">
            <div class="cam-thumb"><img id="court-cam1" alt="Camera 1"></div>
            <div class="cam-thumb"><img id="court-cam0" alt="Camera 0"></div>
            <div class="sidebar-panel">
                <button class="btn-calibrate" id="btnCalibrate" onclick="doCalibrate()">Calibrate Court</button>
                <div class="calibrate-status" id="calStatus">
                    <span id="calStatusText">Not calibrated</span>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- Tab 3: Trajectory — 3D main, cameras small bottom center -->
<div class="tab-content" id="tab-trajectory">
    <div class="tab-full">
        <div class="viewport-3d" id="trajectory-3d"></div>
        <div class="bottom-bar">
            <div class="cam-thumb"><img id="traj-cam1" alt="Camera 1"></div>
            <div class="cam-thumb"><img id="traj-cam0" alt="Camera 0"></div>
            <div class="var-panel-bottom">
                <div class="var-indicator">
                    <div class="var-dot" id="varDot"></div>
                    <div class="var-label" id="varLabel">VAR</div>
                </div>
                <div class="var-info" id="varInfo">
                    <div class="var-line" id="varLine">No events</div>
                    <div class="var-timer" id="varTimer"></div>
                    <div class="var-dist" id="varDist"></div>
                </div>
                <img class="var-snapshot" id="varSnapshot" style="display:none">
                <div class="var-snapshot empty" id="varSnapshotEmpty">No snapshot</div>
            </div>
        </div>
    </div>
</div>

<div class="info-panel" id="infoPanel" style="display:none">
    <div class="info-item"><span class="label">Speed:</span><span class="value" id="ball-speed">--</span></div>
    <div class="info-item"><span class="label">Height:</span><span class="value" id="ball-height">--</span></div>
    <div class="info-item"><span class="label">Landing:</span><span class="value" id="ball-landing">--</span></div>
    <div class="info-item"><span class="label">Events:</span><span class="value" id="event-count">0</span></div>
</div>

<script>
// ===================== Tab switching =====================
var activeTab = 'detection';
document.querySelectorAll('.tab').forEach(function(tab) {
    tab.addEventListener('click', function() {
        var target = this.dataset.tab;
        activeTab = target;
        document.querySelectorAll('.tab').forEach(function(t) { t.classList.remove('active'); });
        document.querySelectorAll('.tab-content').forEach(function(c) { c.classList.remove('active'); });
        this.classList.add('active');
        document.getElementById('tab-' + target).classList.add('active');

        document.getElementById('infoPanel').style.display = (target === 'trajectory') ? 'flex' : 'none';
        if (target === 'court' && !courtSceneInitialized) initCourtScene();
        if (target === 'trajectory' && !trajSceneInitialized) initTrajectoryScene();
    });
});

// ===================== Calibration =====================
function doCalibrate() {
    var btn = document.getElementById('btnCalibrate');
    btn.disabled = true;
    btn.textContent = 'Calibrating...';

    fetch('/api/calibration/trigger', { method: 'POST' })
        .then(function(r) { return r.json(); })
        .then(function(data) {
            btn.disabled = false;
            if (data.ok) {
                btn.textContent = 'Re-calibrate';
                updateCalibrationStatus();

                // Fetch camera positions and add to 3D scene
                fetch('/api/calibration/data')
                    .then(function(r) { return r.json(); })
                    .then(function(camData) { addCamerasToScene(camData); });
            } else {
                btn.textContent = 'Calibrate Court';
                alert('Calibration failed: ' + (data.error || 'Unknown error'));
            }
        })
        .catch(function(e) {
            btn.disabled = false;
            btn.textContent = 'Calibrate Court';
            alert('Error: ' + e);
        });
}

function updateCalibrationStatus() {
    fetch('/api/calibration/status')
        .then(function(r) { return r.json(); })
        .then(function(data) {
            var el = document.getElementById('calStatusText');
            var ok0 = data['0'], ok1 = data['1'];
            if (ok0 && ok1) {
                el.textContent = 'Calibrated';
                el.className = 'ok';
            } else if (ok0 || ok1) {
                el.textContent = 'Partially calibrated';
                el.className = 'ok';
            } else {
                el.textContent = 'Not calibrated';
                el.className = '';
            }
        });
}
// Check on load
updateCalibrationStatus();

function addCamerasToScene(camData) {
    if (!courtSceneInitialized) return;

    for (var sid in camData) {
        var cam = camData[sid];
        var pos = cam.position;

        // Camera pyramid
        var geo = new THREE.ConeGeometry(0.3, 0.5, 4);
        var mat = new THREE.MeshBasicMaterial({
            color: sid === '0' ? 0x44aaff : 0xff44aa,
            wireframe: true
        });
        var mesh = new THREE.Mesh(geo, mat);
        mesh.position.set(pos[0], pos[1], pos[2]);

        // Point cone toward look direction
        var dir = cam.look_direction;
        mesh.lookAt(pos[0] + dir[0], pos[1] + dir[1], pos[2] + dir[2]);

        courtScene.add(mesh);

        // Label
        // (Three.js r128 doesn't have CSS2DRenderer built-in, so skip label for now)
    }
}

// ===================== Camera frame polling =====================
var camPrefixes = { 'detection': 'det', 'court': 'court', 'trajectory': 'traj' };

function refreshCam(tabName, camId) {
    var prefix = camPrefixes[tabName];
    var img = document.getElementById(prefix + '-cam' + camId);
    if (!img) return;

    var newImg = new Image();
    newImg.onload = function() {
        img.src = newImg.src;
        setTimeout(function() { refreshCam(tabName, camId); }, 50);
    };
    newImg.onerror = function() {
        setTimeout(function() { refreshCam(tabName, camId); }, 500);
    };
    newImg.src = '/frame/' + camId + '?' + Date.now();
}

['detection', 'court', 'trajectory'].forEach(function(tab) {
    refreshCam(tab, 0);
    refreshCam(tab, 1);
});

// ===================== Stats polling =====================
setInterval(function() {
    fetch('/api/stats').then(function(r) { return r.json(); }).then(function(d) {
        document.getElementById('fps0').textContent = d['0'] ? d['0'].fps.toFixed(1) : '--';
        document.getElementById('fps1').textContent = d['1'] ? d['1'].fps.toFixed(1) : '--';
    });
}, 2000);

// ===================== Three.js: Court Scene (Tab 2) =====================
var courtSceneInitialized = false;
var courtScene, courtCamera, courtRenderer, courtBallMesh;

function initCourtScene() {
    courtSceneInitialized = true;
    var container = document.getElementById('court-3d');
    var w = container.clientWidth;
    var h = container.clientHeight;

    courtScene = new THREE.Scene();
    courtScene.background = new THREE.Color(0x0a0a1a);

    courtCamera = new THREE.PerspectiveCamera(50, w / h, 0.1, 100);
    courtCamera.position.set(6.7, -6, 10);
    courtCamera.lookAt(6.7, 3.05, 0);

    courtRenderer = new THREE.WebGLRenderer({ antialias: true });
    courtRenderer.setSize(w, h);
    container.appendChild(courtRenderer.domElement);

    var controls = new THREE.OrbitControls(courtCamera, courtRenderer.domElement);
    controls.target.set(6.7, 3.05, 0);
    controls.update();

    // Court surface
    var courtGeo = new THREE.PlaneGeometry(13.4, 6.1);
    var courtMat = new THREE.MeshBasicMaterial({ color: 0x1a5c3a, side: THREE.DoubleSide });
    var courtMesh = new THREE.Mesh(courtGeo, courtMat);
    courtMesh.position.set(6.7, 3.05, 0);
    courtScene.add(courtMesh);

    drawCourtLines(courtScene);

    // Net (wide plane)
    var netMat = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.4, side: THREE.DoubleSide });
    var netWide = new THREE.PlaneGeometry(0.914, 6.1);
    var netWideMesh = new THREE.Mesh(netWide, netMat);
    netWideMesh.rotation.y = Math.PI / 2;
    netWideMesh.position.set(6.7, 3.05, 0.457);
    courtScene.add(netWideMesh);

    // Ball
    var ballGeo = new THREE.SphereGeometry(0.15, 16, 16);
    var ballMat = new THREE.MeshBasicMaterial({ color: 0xffff00 });
    courtBallMesh = new THREE.Mesh(ballGeo, ballMat);
    courtBallMesh.visible = false;
    courtScene.add(courtBallMesh);

    courtScene.add(new THREE.AmbientLight(0xffffff, 0.8));

    // Physical camera marker: 1m from net, center, 1m height
    addCameraMarker(courtScene, 7.7, 3.05, 1);

    // Load existing calibration cameras
    fetch('/api/calibration/data')
        .then(function(r) { return r.json(); })
        .then(function(camData) { addCamerasToScene(camData); })
        .catch(function() {});

    function animateCourt() {
        requestAnimationFrame(animateCourt);
        controls.update();
        courtRenderer.render(courtScene, courtCamera);
    }
    animateCourt();

    window.addEventListener('resize', function() {
        var w2 = container.clientWidth;
        var h2 = container.clientHeight;
        courtCamera.aspect = w2 / h2;
        courtCamera.updateProjectionMatrix();
        courtRenderer.setSize(w2, h2);
    });
}

// ===================== Three.js: Trajectory Scene (Tab 3) =====================
var trajSceneInitialized = false;
var trajScene, trajCamera, trajRenderer, trajBallMesh, trajLine;

function initTrajectoryScene() {
    trajSceneInitialized = true;
    var container = document.getElementById('trajectory-3d');
    var w = container.clientWidth;
    var h = container.clientHeight;

    trajScene = new THREE.Scene();
    trajScene.background = new THREE.Color(0x0a0a1a);

    trajCamera = new THREE.PerspectiveCamera(50, w / h, 0.1, 100);
    trajCamera.position.set(6.7, -6, 10);
    trajCamera.lookAt(6.7, 3.05, 0);

    trajRenderer = new THREE.WebGLRenderer({ antialias: true });
    trajRenderer.setSize(w, h);
    container.appendChild(trajRenderer.domElement);

    var controls = new THREE.OrbitControls(trajCamera, trajRenderer.domElement);
    controls.target.set(6.7, 3.05, 0);
    controls.update();

    // Court surface
    var courtGeo = new THREE.PlaneGeometry(13.4, 6.1);
    var courtMat = new THREE.MeshBasicMaterial({ color: 0x1a5c3a, side: THREE.DoubleSide });
    var courtMesh = new THREE.Mesh(courtGeo, courtMat);
    courtMesh.position.set(6.7, 3.05, 0);
    trajScene.add(courtMesh);

    drawCourtLines(trajScene);

    // Net
    var netMat = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.3, side: THREE.DoubleSide });
    var netMesh = new THREE.Mesh(new THREE.PlaneGeometry(0.914, 6.1), netMat);
    netMesh.rotation.y = Math.PI / 2;
    netMesh.position.set(6.7, 3.05, 0.457);
    trajScene.add(netMesh);

    // Ball
    trajBallMesh = new THREE.Mesh(
        new THREE.SphereGeometry(0.15, 16, 16),
        new THREE.MeshBasicMaterial({ color: 0xffff00 })
    );
    trajBallMesh.visible = false;
    trajScene.add(trajBallMesh);

    // Trajectory line
    trajLine = new THREE.Line(
        new THREE.BufferGeometry(),
        new THREE.LineBasicMaterial({ color: 0xff6600, linewidth: 2 })
    );
    trajScene.add(trajLine);

    // Landing marker
    window.landingMarker = new THREE.Mesh(
        new THREE.RingGeometry(0.1, 0.2, 32),
        new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide, transparent: true, opacity: 0.6 })
    );
    window.landingMarker.position.z = 0.01;
    window.landingMarker.visible = false;
    trajScene.add(window.landingMarker);

    // Shadow
    window.ballShadow = new THREE.Mesh(
        new THREE.CircleGeometry(0.1, 16),
        new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0.3 })
    );
    window.ballShadow.position.z = 0.005;
    window.ballShadow.visible = false;
    trajScene.add(window.ballShadow);

    trajScene.add(new THREE.AmbientLight(0xffffff, 0.8));

    // Physical camera marker: 1m from net, center, 1m height
    addCameraMarker(trajScene, 7.7, 3.05, 1);

    function animateTraj() {
        requestAnimationFrame(animateTraj);
        controls.update();
        trajRenderer.render(trajScene, trajCamera);
    }
    animateTraj();

    window.addEventListener('resize', function() {
        var w2 = container.clientWidth;
        var h2 = container.clientHeight;
        trajCamera.aspect = w2 / h2;
        trajCamera.updateProjectionMatrix();
        trajRenderer.setSize(w2, h2);
    });
}

// ===================== Camera marker =====================
function addCameraMarker(scene, x, y, z) {
    // Camera body (box)
    var body = new THREE.Mesh(
        new THREE.BoxGeometry(0.2, 0.15, 0.15),
        new THREE.MeshBasicMaterial({ color: 0x44aaff })
    );
    body.position.set(x, y, z);
    scene.add(body);

    // Lens (cone pointing toward net at x=6.7)
    var lens = new THREE.Mesh(
        new THREE.ConeGeometry(0.06, 0.15, 8),
        new THREE.MeshBasicMaterial({ color: 0x2288dd })
    );
    lens.rotation.z = Math.PI / 2; // point along -X toward net
    lens.position.set(x - 0.17, y, z);
    scene.add(lens);

    // Pole from ground to camera
    var poleGeo = new THREE.BufferGeometry().setFromPoints([
        new THREE.Vector3(x, y, 0),
        new THREE.Vector3(x, y, z)
    ]);
    scene.add(new THREE.Line(poleGeo, new THREE.LineBasicMaterial({ color: 0x666666 })));
}

// ===================== Draw court lines =====================
function drawCourtLines(scene) {
    var mat = new THREE.LineBasicMaterial({ color: 0xffffff });

    function addLine(x1, y1, x2, y2, material) {
        var geo = new THREE.BufferGeometry().setFromPoints([
            new THREE.Vector3(x1, y1, 0.01),
            new THREE.Vector3(x2, y2, 0.01)
        ]);
        scene.add(new THREE.Line(geo, material || mat));
    }

    // Outer boundaries
    addLine(0, 0, 13.4, 0);
    addLine(13.4, 0, 13.4, 6.1);
    addLine(13.4, 6.1, 0, 6.1);
    addLine(0, 6.1, 0, 0);

    // Net / center line
    addLine(6.7, 0, 6.7, 6.1, new THREE.LineBasicMaterial({ color: 0xcccccc }));

    // Kitchen lines (NVZ)
    var kitchenMat = new THREE.LineBasicMaterial({ color: 0xff6666 });
    addLine(6.7 - 2.13, 0, 6.7 - 2.13, 6.1, kitchenMat);
    addLine(6.7 + 2.13, 0, 6.7 + 2.13, 6.1, kitchenMat);

    // Center service lines
    var svcMat = new THREE.LineBasicMaterial({ color: 0x888888 });
    addLine(0, 3.05, 6.7 - 2.13, 3.05, svcMat);
    addLine(6.7 + 2.13, 3.05, 13.4, 3.05, svcMat);
}

// ===================== Trajectory data polling =====================
setInterval(function() {
    if (activeTab !== 'trajectory' && activeTab !== 'court') return;

    fetch('/api/trajectory').then(function(r) { return r.json(); }).then(function(data) {
        var points = data.points || [];
        var speed = data.speed;
        var landing = data.landing;

        document.getElementById('ball-speed').textContent =
            speed !== null ? (speed * 3.6).toFixed(1) + ' km/h' : '--';

        if (points.length > 0) {
            var last = points[points.length - 1];
            document.getElementById('ball-height').textContent =
                last.z !== null ? last.z.toFixed(2) + ' m' : '--';
        }

        document.getElementById('ball-landing').textContent =
            landing ? '(' + landing.x.toFixed(1) + ', ' + landing.y.toFixed(1) + ') ' + landing.t.toFixed(2) + 's' : '--';

        if (points.length > 0) {
            var last = points[points.length - 1];

            if (courtBallMesh) {
                courtBallMesh.visible = true;
                courtBallMesh.position.set(last.x, last.y, last.z || 0.15);
            }

            if (trajBallMesh) {
                trajBallMesh.visible = true;
                trajBallMesh.position.set(last.x, last.y, last.z || 0.15);

                if (window.ballShadow) {
                    window.ballShadow.visible = true;
                    window.ballShadow.position.set(last.x, last.y, 0.005);
                }

                var linePoints = points.map(function(p) {
                    return new THREE.Vector3(p.x, p.y, p.z || 0);
                });
                if (linePoints.length > 1) {
                    trajLine.geometry.dispose();
                    trajLine.geometry = new THREE.BufferGeometry().setFromPoints(linePoints);
                }
            }

            if (landing && window.landingMarker) {
                window.landingMarker.visible = true;
                window.landingMarker.position.set(landing.x, landing.y, 0.01);
            } else if (window.landingMarker) {
                window.landingMarker.visible = false;
            }
        }
    }).catch(function() {});
}, 100);

// ===================== VAR panel polling =====================
var varTimerInterval = null;
var lastVarTimestamp = null;

function updateVarTimer() {
    if (!lastVarTimestamp) return;
    var ago = (Date.now() / 1000) - lastVarTimestamp;
    var el = document.getElementById('varTimer');
    if (ago < 60) {
        el.textContent = ago.toFixed(0) + 's ago';
    } else if (ago < 3600) {
        el.textContent = Math.floor(ago / 60) + 'm ' + Math.floor(ago % 60) + 's ago';
    } else {
        el.textContent = Math.floor(ago / 3600) + 'h ago';
    }

    // Red dot stays active for 30 seconds
    var dot = document.getElementById('varDot');
    var label = document.getElementById('varLabel');
    if (ago < 30) {
        dot.classList.add('active');
        label.classList.add('active');
        label.textContent = 'VAR ACTIVE';
    } else {
        dot.classList.remove('active');
        label.classList.remove('active');
        label.textContent = 'VAR';
    }
}

setInterval(function() {
    fetch('/api/var/last')
        .then(function(r) { return r.json(); })
        .then(function(data) {
            if (!data) return;

            var event = data.event;
            lastVarTimestamp = event.timestamp;

            document.getElementById('varLine').textContent =
                'Line: ' + event.line;
            document.getElementById('varDist').textContent =
                'Distance: ' + (event.distance_m * 100).toFixed(0) + ' cm';

            updateVarTimer();

            // Show snapshot
            if (data.snapshot_b64) {
                var img = document.getElementById('varSnapshot');
                img.src = 'data:image/jpeg;base64,' + data.snapshot_b64;
                img.style.display = 'block';
                document.getElementById('varSnapshotEmpty').style.display = 'none';
            }
        })
        .catch(function() {});
}, 1000);

// Update timer every second
setInterval(updateVarTimer, 1000);

// ===================== Event banner =====================
var lastEventCount = 0;
setInterval(function() {
    fetch('/api/events').then(function(r) { return r.json(); }).then(function(events) {
        document.getElementById('event-count').textContent = events.length;

        if (events.length > lastEventCount) {
            var banner = document.getElementById('eventBanner');
            var latest = events[events.length - 1];
            banner.textContent = 'VAR: Close Call - ' + latest.line +
                ' (' + (latest.distance_m * 100).toFixed(0) + 'cm)';
            banner.classList.add('show');
            setTimeout(function() { banner.classList.remove('show'); }, 5000);
            lastEventCount = events.length;
        }
    }).catch(function() {});
}, 1000);
</script>
</body>
</html>
