// SPEC: pikasTech/HWLAB#2345 Workbench Pinia Colada migration; PJ2026-010401080313 Workbench实时权威 draft-2026-07-08-p0-workbench-realtime-authority-v2.
// Responsibility: Stable Workbench semantic query and mutation keys for Pinia Colada cache authority.

import type { EntryKey } from "@pinia/colada";

export interface WorkbenchSessionsKeyInput {
  includeSessionId?: string | null;
  cursor?: string | null;
  limit?: number | null;
}

export interface WorkbenchSessionMessagesKeyInput {
  cursor?: string | null;
  limit?: number | null;
}

export interface WorkbenchTraceEventsKeyInput {
  afterProjectedSeq?: number | null;
  limit?: number | null;
}

export const workbenchColadaKeys = {
  root: (): EntryKey => ["workbench"],
  serverState: (): EntryKey => ["workbench", "projection", "server-state"],
  snapshotRoot: (): EntryKey => ["workbench", "snapshot"],
  snapshotSessionsRoot: (): EntryKey => ["workbench", "snapshot", "sessions"],
  snapshotSessions: (input: WorkbenchSessionsKeyInput = {}): EntryKey => ["workbench", "snapshot", "sessions", normalizeKeyObject({ includeSessionId: input.includeSessionId ?? null, cursor: input.cursor ?? null, limit: finiteNumber(input.limit) })],
  snapshotSessionRoot: (): EntryKey => ["workbench", "snapshot", "session"],
  snapshotSession: (sessionId: string): EntryKey => ["workbench", "snapshot", "session", sessionId],
  historyRoot: (): EntryKey => ["workbench", "history"],
  historySessionMessagesRoot: (): EntryKey => ["workbench", "history", "session-messages"],
  historySessionMessages: (sessionId: string, input: WorkbenchSessionMessagesKeyInput = {}): EntryKey => ["workbench", "history", "session-messages", sessionId, normalizeKeyObject({ cursor: input.cursor ?? null, limit: finiteNumber(input.limit) })],
  detailRoot: (): EntryKey => ["workbench", "detail"],
  detailTraceEventsRoot: (): EntryKey => ["workbench", "detail", "trace-events"],
  detailTraceEvents: (traceId: string, input: WorkbenchTraceEventsKeyInput = {}): EntryKey => ["workbench", "detail", "trace-events", traceId, normalizeKeyObject({ afterProjectedSeq: finiteNumber(input.afterProjectedSeq), limit: finiteNumber(input.limit) })],
  sessionsRoot: (): EntryKey => workbenchColadaKeys.snapshotSessionsRoot(),
  sessions: (input: WorkbenchSessionsKeyInput = {}): EntryKey => workbenchColadaKeys.snapshotSessions(input),
  sessionRoot: (): EntryKey => workbenchColadaKeys.snapshotSessionRoot(),
  session: (sessionId: string): EntryKey => workbenchColadaKeys.snapshotSession(sessionId),
  sessionMessagesRoot: (): EntryKey => workbenchColadaKeys.historySessionMessagesRoot(),
  sessionMessages: (sessionId: string, input: WorkbenchSessionMessagesKeyInput = {}): EntryKey => workbenchColadaKeys.historySessionMessages(sessionId, input),
  traceEventsRoot: (): EntryKey => workbenchColadaKeys.detailTraceEventsRoot(),
  traceEvents: (traceId: string, input: WorkbenchTraceEventsKeyInput = {}): EntryKey => workbenchColadaKeys.detailTraceEvents(traceId, input),
  providerProfiles: (): EntryKey => ["workbench", "provider-profiles"],
  mutationSubmit: (): EntryKey => ["workbench", "submit"],
  mutationSteer: (): EntryKey => ["workbench", "steer"],
  mutationCancel: (traceId: string | null | undefined): EntryKey => ["workbench", "cancel", traceId ?? "unknown"],
  mutationCreateSession: (): EntryKey => ["workbench", "create-session"],
  mutationDeleteSession: (sessionId: string | null | undefined): EntryKey => ["workbench", "delete-session", sessionId ?? "unknown"]
};

function normalizeKeyObject<T extends Record<string, string | number | boolean | null | undefined>>(input: T): T {
  return Object.fromEntries(Object.entries(input).sort(([left], [right]) => left.localeCompare(right))) as T;
}

function finiteNumber(value: number | null | undefined): number | null {
  const number = Number(value);
  return Number.isFinite(number) ? Math.trunc(number) : null;
}
