// SPEC: PJ2026-0106050514 Workbench实时运行面 draft-2026-06-30-p0-1297-spec-first.
// Responsibility: Workbench runtime tunables consumed by store/runtime modules from the injected YAML-backed web config.

export interface WorkbenchRuntimePolicy {
  defaultCodeAgentTimeoutMs: number;
  defaultGatewayTimeoutMs: number;
  traceDetailPageLimit: number;
  traceDetailMaxPages: number;
  traceDetailMaxAttempts: number;
  traceDetailRetryDelayMs: number;
  traceDetailAutoQueueLimit: number;
  traceDetailBackgroundConcurrency: number;
  traceDetailBackgroundDelayMs: number;
  sessionListPageLimit: number;
  workbenchDetailReadConcurrency: number;
  workbenchReadFailureCooldownMs: number;
  workbenchTraceEventsMinRefreshMs: number;
  workbenchSessionDetailMinRefreshMs: number;
  workbenchSessionMessagesMinRefreshMs: number;
  workbenchSessionMessagesWindowLimit: number;
  workbenchRealtimeSessionMessagesMinRefreshMs: number;
  workbenchTraceEventsTimeoutMs: number;
  sessionListMinRefreshIntervalMs: number;
  workbenchRealtimeErrorSyncReplayMinMs: number;
  workbenchRealtimeFlushMaxItemsPerChunk: number;
  workbenchRealtimeFlushMaxChunkMs: number;
  workbenchRealtimeFlushYieldMs: number;
}

const DEFAULT_WORKBENCH_RUNTIME_POLICY: WorkbenchRuntimePolicy = Object.freeze({
  defaultCodeAgentTimeoutMs: 1_800_000,
  defaultGatewayTimeoutMs: 120_000,
  traceDetailPageLimit: 50,
  traceDetailMaxPages: 4,
  traceDetailMaxAttempts: 3,
  traceDetailRetryDelayMs: 700,
  traceDetailAutoQueueLimit: 4,
  traceDetailBackgroundConcurrency: 1,
  traceDetailBackgroundDelayMs: 400,
  sessionListPageLimit: 20,
  workbenchDetailReadConcurrency: 3,
  workbenchReadFailureCooldownMs: 5_000,
  workbenchTraceEventsMinRefreshMs: 4_000,
  workbenchSessionDetailMinRefreshMs: 5_000,
  workbenchSessionMessagesMinRefreshMs: 5_000,
  workbenchSessionMessagesWindowLimit: 20,
  workbenchRealtimeSessionMessagesMinRefreshMs: 1_000,
  workbenchTraceEventsTimeoutMs: 5_000,
  sessionListMinRefreshIntervalMs: 15_000,
  workbenchRealtimeErrorSyncReplayMinMs: 2_000,
  workbenchRealtimeFlushMaxItemsPerChunk: 4,
  workbenchRealtimeFlushMaxChunkMs: 8,
  workbenchRealtimeFlushYieldMs: 0
});

export function workbenchRuntimePolicy(input: unknown = runtimePolicyConfig()): WorkbenchRuntimePolicy {
  const source = recordValue(input) ?? {};
  return {
    defaultCodeAgentTimeoutMs: positiveNumber(source.defaultCodeAgentTimeoutMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.defaultCodeAgentTimeoutMs),
    defaultGatewayTimeoutMs: positiveNumber(source.defaultGatewayTimeoutMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.defaultGatewayTimeoutMs),
    traceDetailPageLimit: positiveInteger(source.traceDetailPageLimit ?? source.traceHydrationPageLimit, DEFAULT_WORKBENCH_RUNTIME_POLICY.traceDetailPageLimit),
    traceDetailMaxPages: positiveInteger(source.traceDetailMaxPages ?? source.traceHydrationMaxPages, DEFAULT_WORKBENCH_RUNTIME_POLICY.traceDetailMaxPages),
    traceDetailMaxAttempts: positiveInteger(source.traceDetailMaxAttempts ?? source.traceHydrationMaxAttempts, DEFAULT_WORKBENCH_RUNTIME_POLICY.traceDetailMaxAttempts),
    traceDetailRetryDelayMs: positiveNumber(source.traceDetailRetryDelayMs ?? source.traceHydrationRetryDelayMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.traceDetailRetryDelayMs),
    traceDetailAutoQueueLimit: positiveInteger(source.traceDetailAutoQueueLimit ?? source.traceHydrationAutoQueueLimit, DEFAULT_WORKBENCH_RUNTIME_POLICY.traceDetailAutoQueueLimit),
    traceDetailBackgroundConcurrency: positiveInteger(source.traceDetailBackgroundConcurrency ?? source.traceHydrationBackgroundConcurrency, DEFAULT_WORKBENCH_RUNTIME_POLICY.traceDetailBackgroundConcurrency),
    traceDetailBackgroundDelayMs: nonNegativeNumber(source.traceDetailBackgroundDelayMs ?? source.traceHydrationBackgroundDelayMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.traceDetailBackgroundDelayMs),
    sessionListPageLimit: positiveInteger(source.sessionListPageLimit, DEFAULT_WORKBENCH_RUNTIME_POLICY.sessionListPageLimit),
    workbenchDetailReadConcurrency: positiveInteger(source.workbenchDetailReadConcurrency ?? source.workbenchReadHydrationConcurrency, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchDetailReadConcurrency),
    workbenchReadFailureCooldownMs: positiveNumber(source.workbenchReadFailureCooldownMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchReadFailureCooldownMs),
    workbenchTraceEventsMinRefreshMs: nonNegativeNumber(source.workbenchTraceEventsMinRefreshMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchTraceEventsMinRefreshMs),
    workbenchSessionDetailMinRefreshMs: nonNegativeNumber(source.workbenchSessionDetailMinRefreshMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchSessionDetailMinRefreshMs),
    workbenchSessionMessagesMinRefreshMs: nonNegativeNumber(source.workbenchSessionMessagesMinRefreshMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchSessionMessagesMinRefreshMs),
    workbenchSessionMessagesWindowLimit: positiveInteger(source.workbenchSessionMessagesWindowLimit, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchSessionMessagesWindowLimit),
    workbenchRealtimeSessionMessagesMinRefreshMs: nonNegativeNumber(source.workbenchRealtimeSessionMessagesMinRefreshMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchRealtimeSessionMessagesMinRefreshMs),
    workbenchTraceEventsTimeoutMs: positiveNumber(source.workbenchTraceEventsTimeoutMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchTraceEventsTimeoutMs),
    sessionListMinRefreshIntervalMs: nonNegativeNumber(source.sessionListMinRefreshIntervalMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.sessionListMinRefreshIntervalMs),
    workbenchRealtimeErrorSyncReplayMinMs: nonNegativeNumber(source.workbenchRealtimeErrorSyncReplayMinMs ?? source.workbenchRealtimeErrorGapFillMinMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchRealtimeErrorSyncReplayMinMs),
    workbenchRealtimeFlushMaxItemsPerChunk: positiveInteger(source.workbenchRealtimeFlushMaxItemsPerChunk, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchRealtimeFlushMaxItemsPerChunk),
    workbenchRealtimeFlushMaxChunkMs: nonNegativeNumber(source.workbenchRealtimeFlushMaxChunkMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchRealtimeFlushMaxChunkMs),
    workbenchRealtimeFlushYieldMs: nonNegativeNumber(source.workbenchRealtimeFlushYieldMs, DEFAULT_WORKBENCH_RUNTIME_POLICY.workbenchRealtimeFlushYieldMs)
  };
}

function runtimePolicyConfig(): unknown {
  if (typeof window === "undefined") return null;
  return window.HWLAB_CLOUD_WEB_CONFIG?.workbench?.runtimePolicy ?? null;
}

function recordValue(value: unknown): Record<string, unknown> | null {
  return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : null;
}

function positiveInteger(value: unknown, fallback: number): number {
  const number = positiveNumber(value, fallback);
  return Math.max(1, Math.trunc(number));
}

function positiveNumber(value: unknown, fallback: number): number {
  const number = Number(value);
  return Number.isFinite(number) && number > 0 ? number : fallback;
}

function nonNegativeNumber(value: unknown, fallback: number): number {
  const number = Number(value);
  return Number.isFinite(number) && number >= 0 ? number : fallback;
}
