// Copyright (c) 2026 Hellmai Ltd
// SPDX-License-Identifier: AGPL-3.0-only
/**
 * WU-2638 (INIT-057 Phase 2): emitter factories for the 14 kernel-event kinds.
 *
 * Every emission flowing to the control plane goes through `buildKernelEventV2`
 * (conductor variants) or `buildTaskCreatedLegacyEvent` (schema_version 1
 * legacy variants upgraded to carry event_id). The factories:
 *
 *   - return shapes that typecheck against the SDK tagged union
 *     (@lumenflow/control-plane-sdk WU-2637), never a parallel copy
 *   - populate `event_id` deterministically from (kind, payload, timestamp,
 *     idempotencyKey). Replay of a retried batch collapses into the same
 *     event_id so the cloud dedups duplicates idempotently (ADR-011 §3)
 *   - fall back to UUID v4 when no idempotency key is supplied so ad-hoc
 *     emissions still carry a unique id
 *
 * This module is the sole producer of `event_id` for @lumenflow/cli. Call
 * sites must not hand-roll envelopes — instead they build a payload and pass
 * it through one of these factories.
 *
 * @module kernel-event-sync/emitters
 */
import { createHash, randomUUID } from 'node:crypto';
import { KERNEL_EVENT_KINDS, SDK_KERNEL_EVENT_SCHEMA_VERSION_V1, SDK_KERNEL_EVENT_SCHEMA_VERSION_V2, } from '@lumenflow/control-plane-sdk';
/**
 * Accepts either a hex content-hash (>=32 chars) or a UUID shape. Widening
 * both shapes behind one pattern lets the cloud treat `event_id` uniformly
 * without caring which branch produced it.
 */
export const KERNEL_EVENT_ID_PATTERN = /^(?:[0-9a-f]{32,}|[0-9a-f-]{36})$/i;
export const WU_LIFECYCLE_EVENT_SCHEMA_VERSION_V2 = SDK_KERNEL_EVENT_SCHEMA_VERSION_V2;
const CONTENT_HASH_ALGORITHM = 'sha256';
const CONTENT_HASH_ENCODING = 'hex';
const CONTENT_HASH_PREFIX_LENGTH = 32;
/**
 * Shared primitive: resolve the envelope timestamp from options or `now()`.
 *
 * Exported so pack-level emitters (e.g. software-delivery, WU-2728) reuse the
 * same resolution instead of re-implementing the defaulting contract.
 */
export function resolveKernelEventTimestamp(options) {
    return options?.timestamp ?? new Date().toISOString();
}
function contentHashEventId(kind, payload, timestamp, idempotencyKey) {
    // Canonical key ordering so replay is deterministic across node versions.
    const canonicalPayload = JSON.stringify(payload, Object.keys(payload).sort());
    const hashInput = `${idempotencyKey}|${kind}|${timestamp}|${canonicalPayload}`;
    return createHash(CONTENT_HASH_ALGORITHM)
        .update(hashInput)
        .digest(CONTENT_HASH_ENCODING)
        .slice(0, CONTENT_HASH_PREFIX_LENGTH);
}
/**
 * Shared primitive: resolve an event_id from (kind, payload, timestamp,
 * idempotencyKey) or fall back to UUID v4. Exported so pack-level emitters
 * (WU-2728) produce ids that pass `KERNEL_EVENT_ID_PATTERN` without
 * re-deriving the hash shape.
 */
export function resolveKernelEventId(kind, payload, timestamp, options) {
    const key = options?.idempotencyKey;
    if (typeof key === 'string' && key.length > 0) {
        return contentHashEventId(kind, payload, timestamp, key);
    }
    return randomUUID();
}
/**
 * Build a v2 conductor-mode kernel event. The returned value typechecks
 * against the SDK tagged union; callers pass it straight to
 * `ControlPlaneSyncPort.pushKernelEvents`.
 */
export function buildKernelEventV2(payload, options) {
    const timestamp = resolveKernelEventTimestamp(options);
    const payloadRecord = payload;
    const event_id = resolveKernelEventId(payload.kind, payloadRecord, timestamp, options);
    // The SDK tagged union is exhaustive; spreading the payload onto the v2
    // envelope preserves the discriminant literally.
    return {
        ...payload,
        schema_version: SDK_KERNEL_EVENT_SCHEMA_VERSION_V2,
        timestamp,
        event_id,
    };
}
/**
 * Legacy task_created variant upgraded to carry event_id (schema_version 1).
 *
 * The three legacy task_* kinds keep schema_version 1 for backward compat
 * with v1 subscribers, but WU-2638 populates event_id on every emission so
 * the cloud dedup pipeline covers legacy traffic uniformly.
 */
export function buildTaskCreatedLegacyEvent(payload, options) {
    const timestamp = resolveKernelEventTimestamp(options);
    const kind = KERNEL_EVENT_KINDS.TASK_CREATED;
    const event_id = resolveKernelEventId(kind, payload, timestamp, options);
    return {
        schema_version: SDK_KERNEL_EVENT_SCHEMA_VERSION_V1,
        kind,
        timestamp,
        event_id,
        ...payload,
    };
}
//# sourceMappingURL=emitters.js.map