/**
 * heartbeat.js — rAF-driven ECG-style SVG pulse rings for operative pills.
 * One shared requestAnimationFrame loop — no timer storms.
 */

const _registry = new Map(); // el → { el, lastAt, interval, status }
let _rafId = null;

/** Register an operative element for heartbeat animation.
 * @param {HTMLElement} el           - The pill/card element
 * @param {number}   lastAt          - Last sortie timestamp (ms)
 * @param {number}   intervalMs      - Expected sortie interval (ms)
 * @param {string}   status          - 'active'|'idle'|'blocked'|'dead'
 */
export function register(el, lastAt, intervalMs, status) {
    _registry.set(el, { el, lastAt, interval: intervalMs || 60_000, status });
    if (!_rafId) _rafId = requestAnimationFrame(_tick);
}

/** Unregister an element (call when it's removed from DOM). */
export function unregister(el) {
    _registry.delete(el);
}

/** Unregister all elements (e.g. on view teardown). */
export function clear() {
    _registry.clear();
    if (_rafId) { cancelAnimationFrame(_rafId); _rafId = null; }
}

const PULSE_PERIOD = 2_000; // ms per full ring animation

function _tick(now) {
    if (_registry.size === 0) { _rafId = null; return; }
    for (const [, entry] of _registry) {
        _updateEntry(entry, now);
    }
    _rafId = requestAnimationFrame(_tick);
}

function _updateEntry(entry, now) {
    const { el, lastAt, interval, status } = entry;
    if (!el.isConnected) { _registry.delete(el); return; }

    const age = now - lastAt;
    const ratio = age / interval;

    // Derive health from age relative to expected interval
    let cls = 'active';
    if (status === 'dead' || status === 'zombie') cls = 'dead';
    else if (ratio > 4) cls = 'dead';
    else if (ratio > 2) cls = 'warn';

    // Find or create ring element
    let ring = el.querySelector('.heartbeat-ring');
    if (!ring) {
        ring = document.createElement('span');
        ring.className = 'heartbeat-ring';
        el.style.position = 'relative';
        el.appendChild(ring);
    }

    // Update class only on change to avoid style recalculation every frame
    if (ring.dataset.cls !== cls) {
        ring.dataset.cls = cls;
        ring.className = 'heartbeat-ring ' + (cls === 'active' ? '' : cls);
    }

    // Pulse phase: remap age mod PULSE_PERIOD to [0,1]
    const phase = (now % PULSE_PERIOD) / PULSE_PERIOD;
    const scale = 1 + phase * 0.6;
    const opacity = Math.max(0, 0.8 * (1 - phase));
    ring.style.transform = `scale(${scale.toFixed(2)})`;
    ring.style.opacity = opacity.toFixed(2);
}
