/**
 * Optional RTDB read/listener telemetry for debugging download volume.
 * Enable: localStorage.setItem('rtdbTelemetry','1') then reload (or ?rtdbTelemetry=1 in URL).
 *
 * @typedef {{ path: string, kind: string, keys?: number, bytes?: number, t: number }} RtdbTelemetryEvent
 */

const MAX_EVENTS = 250;

/** @param {string} module */
function bumpLifecycle(module, op) {
    if (!telemetryEnabled()) return;
    if (typeof window === 'undefined') return;
    window.__RTDB_TELEMETRY__ = window.__RTDB_TELEMETRY__ || { events: [], byPath: {}, lifecycle: {} };
    const st = window.__RTDB_TELEMETRY__;
    const m = String(module || 'app');
    st.lifecycle[m] = st.lifecycle[m] || { attach: 0, detach: 0 };
    if (op === 'attach') st.lifecycle[m].attach += 1;
    if (op === 'detach') st.lifecycle[m].detach += 1;
}

/**
 * @param {string} module
 * @param {'attach'|'detach'} op
 */
export function recordRtdbListenerLifecycle(module, op) {
    bumpLifecycle(module, op);
}

function telemetryEnabled() {
    try {
        if (typeof window !== 'undefined' && window.__RTDB_TELEMETRY_FORCE__ === true) return true;
        if (typeof window !== 'undefined' && /(?:^|[?&])rtdbTelemetry=1(?:&|$)/.test(String(window.location.search || ''))) return true;
        if (typeof localStorage !== 'undefined' && localStorage.getItem('rtdbTelemetry') === '1') return true;
    } catch (_) {}
    return false;
}

function shallowObjectKeyCount(val) {
    if (!val || typeof val !== 'object') return 0;
    return Object.keys(val).filter((k) => k !== '_meta').length;
}

function approxSnapBytes(snap) {
    try {
        if (snap && typeof snap.size === 'function') return snap.size();
    } catch (_) {}
    return undefined;
}

/**
 * @param {string} path
 * @param {string} kind onValue|get|query
 * @param {unknown} snapValOrSnap
 */
export function recordRtdbTelemetry(path, kind, snapValOrSnap) {
    if (!telemetryEnabled()) return;
    const snap = snapValOrSnap && typeof snapValOrSnap === 'object' && 'val' in snapValOrSnap ? snapValOrSnap : null;
    const val = snap ? snap.val() : snapValOrSnap;
    const keys = shallowObjectKeyCount(val);
    const bytes = snap ? approxSnapBytes(snap) : undefined;
    /** @type {RtdbTelemetryEvent} */
    const ev = { path, kind, keys, bytes, t: Date.now() };
    if (typeof window === 'undefined') return;
    window.__RTDB_TELEMETRY__ = window.__RTDB_TELEMETRY__ || { events: [], byPath: {} };
    const st = window.__RTDB_TELEMETRY__;
    st.events.push(ev);
    if (st.events.length > MAX_EVENTS) st.events.splice(0, st.events.length - MAX_EVENTS);
    const agg = st.byPath[path] || { count: 0, lastKeys: 0, lastBytes: undefined, lastKind: '' };
    agg.count += 1;
    agg.lastKeys = keys;
    agg.lastBytes = bytes;
    agg.lastKind = kind;
    agg.lastAt = ev.t;
    st.byPath[path] = agg;
    // eslint-disable-next-line no-console
    console.debug('[RTDB telemetry]', kind, path, keys, bytes != null ? `~${bytes}b` : '');
}

/** Call from console: window.dumpRtdbTelemetry() */
export function installRtdbTelemetryConsoleDump() {
    if (typeof window === 'undefined') return;
    window.dumpRtdbTelemetry = () => {
        const st = window.__RTDB_TELEMETRY__;
        if (!st) return 'no events';
        const rows = Object.entries(st.byPath)
            .map(([p, a]) => ({ path: p, ...a }))
            .sort((a, b) => b.count - a.count);
        // eslint-disable-next-line no-console
        console.table(rows);
        if (st.lifecycle && Object.keys(st.lifecycle).length) {
            const lifeRows = Object.entries(st.lifecycle).map(([m, v]) => ({ module: m, ...v }));
            // eslint-disable-next-line no-console
            console.table(lifeRows);
        }
        return rows;
    };
}

installRtdbTelemetryConsoleDump();
