// SPEC: PJ2026-0106050514 Workbench实时运行面 draft-2026-06-30-p0-1297-spec-first; PJ2026-0104010803 唯一投影 draft-2026-06-18-p0-unique-projection; PJ2026-010401080313 Workbench实时权威 draft-2026-07-08-p0-workbench-realtime-authority-v2.
// Responsibility: OpenCode-style Workbench realtime event reducer; store code consumes actions instead of branching on raw SSE events.
// Mechanical source: /root/opencode/packages/app/src/context/global-sync/event-reducer.ts:21-48 global event classification, :93-270 session/message reducer action boundary.
// Mechanical source: /root/opencode/packages/opencode/src/cli/cmd/run/session-data.ts:1-17 reducer side-effect boundary and replay notes.

import type { WorkbenchRealtimeEvent } from "../api/workbench-events";
import { firstNonEmptyString } from "../utils";
export type WorkbenchRealtimeAction =
  | { type: "trace.event"; traceId: string | null; event: WorkbenchRealtimeEvent["event"]; snapshot: WorkbenchRealtimeEvent["snapshot"]; realtimeEvent: WorkbenchRealtimeEvent }
  | { type: "projection.error"; realtimeEvent: WorkbenchRealtimeEvent }
  | { type: "trace.unavailable"; traceId: string | null; reason: string }
  | { type: "ignore"; reason: string };

export interface WorkbenchRealtimeReducerOutput {
  activityLabel: string;
  action: WorkbenchRealtimeAction;
  diagnostic: {
    module: "workbench-event-reducer";
    eventName: string;
    eventType: string | null;
    actionType: WorkbenchRealtimeAction["type"];
    traceId: string | null;
    sessionId: string | null;
    valuesRedacted: true;
  };
}

export function reduceWorkbenchRealtimeEvent(event: WorkbenchRealtimeEvent, eventName: string): WorkbenchRealtimeReducerOutput {
  const eventType = firstNonEmptyString(event.type);
  const action = reduceRealtimeAction(event, eventName);
  return {
    activityLabel: eventType ? `realtime:${eventType}` : `realtime:${eventName}`,
    action,
    diagnostic: {
      module: "workbench-event-reducer",
      eventName,
      eventType: eventType ?? null,
      actionType: action.type,
      traceId: realtimeTraceId(event),
      sessionId: realtimeSessionId(event),
      valuesRedacted: true
    }
  };
}

export function workbenchRealtimeEventIsBusinessActivity(event: WorkbenchRealtimeEvent, eventName: string, liveKafkaSse: boolean): boolean {
  if (!liveKafkaSse) return true;
  return eventName === "hwlab.event.v1" || event.schema === "hwlab.event.v1";
}

function reduceRealtimeAction(event: WorkbenchRealtimeEvent, eventName: string): WorkbenchRealtimeAction {
  if (event.schema === "hwlab.event.v1" && event.event) {
    return { type: "trace.event", traceId: realtimeTraceId(event), event: event.event, snapshot: null, realtimeEvent: event };
  }
  switch (event.type) {
    case "trace.event":
    case "message.snapshot":
    case "turn.snapshot":
    case "trace.snapshot":
      return { type: "ignore", reason: "non-kafka-business-projection-removed" };
    case "trace.unavailable":
      return { type: "trace.unavailable", traceId: realtimeTraceId(event), reason: firstNonEmptyString(event.reason, "realtime-trace-unavailable") ?? "realtime-trace-unavailable" };
    case "error":
      return { type: "projection.error", realtimeEvent: event };
  }
  if (eventName === "workbench.error") return { type: "projection.error", realtimeEvent: event };
  return { type: "ignore", reason: firstNonEmptyString(event.type, eventName, "unsupported") ?? "unsupported" };
}

function realtimeTraceId(event: WorkbenchRealtimeEvent): string | null {
  return firstNonEmptyString(event.traceId, event.snapshot?.traceId, event.event?.traceId, event.message?.traceId) ?? null;
}

function realtimeSessionId(event: WorkbenchRealtimeEvent): string | null {
  return firstNonEmptyString(event.hwlabSessionId, event.sessionId, event.message?.sessionId, event.snapshot?.sessionId, event.event?.sessionId) ?? null;
}
