/**
 * Server-saved diagnostics (GENC-1351 §5.8) — the forward-only stream that lets
 * the debug log persist across a whole session lifetime, not just the current
 * page load. This module owns the *pure* pieces: the entry type and the
 * reassembly back into the `{ readme, timeline, meta }` debug-log shape. The
 * element owns capture/cadence; the provider owns storage layout.
 *
 * @packageDocumentation
 */
/**
 * Stable identity for a message diagnostic entry — `timestamp::role::subAgentOf::category`.
 * Used by the forward-capture delta (skip already-emitted messages) and by the
 * restore watermark (skip messages already present in a prior load's stream).
 * `null` when the entry has no timestamp → treat as always-new. Shared so the
 * element's diagnostics capture and the `SessionPersister`'s restore watermark
 * compute identity identically (GENC-1351 §5.8/§5.10).
 *
 * `category` is part of the key because the reasoning/narration/answer split (GENC-1411) emits
 * SEVERAL messages from one model response — the thought summary, any interstitial narration, and
 * the answer/tool-call message — which share `timestamp` + `role` + `subAgentOf`. Keying on those
 * alone collapsed them to one, so the forward-capture dropped all but the first: a server
 * generation's answer message vanished from the persisted debug log while its reasoning survived
 * (GENC-1461). `category` is stable across a message's in-place annotation (only `toolCalls` change,
 * which is deliberately excluded), so a genuine re-append of the same message still dedups.
 *
 * @internal
 */
export function diagnosticsMessageKey(entry) {
    var _a, _b, _c;
    return typeof entry.timestamp === 'string'
        ? `${entry.timestamp}::${(_a = entry.role) !== null && _a !== void 0 ? _a : ''}::${(_b = entry.subAgentOf) !== null && _b !== void 0 ? _b : ''}::${(_c = entry.category) !== null && _c !== void 0 ? _c : ''}`
        : null;
}
// Tie-break co-timestamped entries by cause → call → output (event, turn, message),
// matching the original in-place `getDebugLog` sort.
const KIND_RANK = { event: 0, turn: 1, message: 2 };
// Any non-{event,turn,message} kind (shouldn't reach the timeline — meta-snapshots
// are filtered out first) sorts last.
const UNKNOWN_KIND_RANK = 99;
/**
 * Reassemble diagnostic entries into the `{ readme, timeline, meta }` debug-log
 * shape (GENC-1351 §5.8). `timeline` = the `message`/`turn`/`event` entries sorted
 * by ISO `timestamp` (kind-rank tie-break). `meta` = the **newest** `meta-snapshot`'s
 * block only — a "state at export" photo, matching the single-page log. The older
 * snapshots are intentionally dropped: the per-turn evolution they would show is
 * already in the timeline (`turn.agentSnapshot` + `context.updated` events), so
 * keeping them would just repeat the bulky, near-static `agentSummary`. `readme` =
 * the passed (current) constant. Pure — reused for both the live current-page log
 * and the reassembled lifetime log stitched from the persisted stream, so both
 * come out shape-identical.
 */
export function assembleDebugLog(entries, readme) {
    var _a, _b;
    // Safety net for exact-duplicate entries: two element instances sharing one
    // session (bubble + popped-out panel) can each append the same entry, and a
    // reload's second instance can re-append restored history. Such copies are
    // byte-identical, so collapse by serialized identity — genuinely-distinct entries
    // (e.g. two real `assistant.connected` from two instances) differ in index /
    // placement and are kept. (The shared cursor store prevents most of this at
    // write time; this guards the read path regardless of what's in the stream.)
    const seen = new Set();
    let latestMeta;
    const timeline = [];
    for (const entry of entries) {
        const id = JSON.stringify(entry);
        if (seen.has(id))
            continue;
        seen.add(id);
        if (entry.kind === 'meta-snapshot') {
            if (!latestMeta || ((_a = entry.timestamp) !== null && _a !== void 0 ? _a : '') >= ((_b = latestMeta.timestamp) !== null && _b !== void 0 ? _b : '')) {
                latestMeta = entry;
            }
        }
        else {
            timeline.push(entry);
        }
    }
    timeline.sort((a, b) => {
        var _a, _b, _c, _d;
        const ta = (_a = a.timestamp) !== null && _a !== void 0 ? _a : '';
        const tb = (_b = b.timestamp) !== null && _b !== void 0 ? _b : '';
        if (ta < tb)
            return -1;
        if (ta > tb)
            return 1;
        return ((_c = KIND_RANK[a.kind]) !== null && _c !== void 0 ? _c : UNKNOWN_KIND_RANK) - ((_d = KIND_RANK[b.kind]) !== null && _d !== void 0 ? _d : UNKNOWN_KIND_RANK);
    });
    return { readme, timeline, meta: latestMeta === null || latestMeta === void 0 ? void 0 : latestMeta.meta };
}
