/*
 * SPEC: pikasTech/HWLAB#2359 Workbench session detail metadata-only contract.
 * Responsibility: Build Workbench session detail payloads and parse detail payload mode flags.
 */

export function includeMessagesForSessionDetail(params: URLSearchParams): boolean {
  if (params.get("includeMessages") !== null) return truthyQueryFlag(params.get("includeMessages"));
  if (params.get("messages") !== null) return truthyQueryFlag(params.get("messages"));
  return false;
}

export function buildWorkbenchSessionDetail(input: {
  summary: Record<string, unknown>;
  session: Record<string, unknown> | null | undefined;
  sessionId: string | null | undefined;
  includeMessages: boolean;
  messages: unknown[];
}): Record<string, unknown> {
  const detail = {
    ...input.summary,
    metadata: {
      startedAt: input.session?.startedAt ?? input.session?.createdAt ?? null,
      endedAt: input.session?.endedAt ?? null,
      ownerUserId: input.session?.ownerUserId ?? null,
      launchContext: compactLaunchContext(sessionJson(input.session)?.launchContext)
    },
    messagePageUrl: input.sessionId ? `/v1/workbench/sessions/${encodeURIComponent(input.sessionId)}/messages` : null,
    valuesRedacted: true,
    secretMaterialStored: false
  };
  return input.includeMessages ? { ...detail, messages: input.messages } : detail;
}

export function compactLaunchContext(value: unknown): Record<string, unknown> | null {
  const record = objectRecord(value);
  if (!record) return null;
  const projectId = textValue(record.projectId) || null;
  const taskRef = textValue(record.taskRef) || null;
  if (!projectId && !taskRef) return null;
  const execution = compactLaunchExecutionContext(record.executionContext ?? record.execution ?? record);
  return {
    source: textValue(record.source) || "project-management",
    projectId,
    taskRef,
    sourceId: textValue(record.sourceId) || null,
    sourceKind: textValue(record.sourceKind) || execution?.sourceKind || null,
    fileRef: textValue(record.fileRef) || null,
    relativePath: textValue(record.relativePath) || execution?.relativePath || null,
    taskId: textValue(record.taskId) || null,
    title: textValue(record.title) || null,
    status: textValue(record.status) || null,
    hwpodId: (execution?.hwpodId ?? textValue(record.hwpodId)) || null,
    nodeId: (execution?.nodeId ?? textValue(record.nodeId)) || null,
    mdtodoRootRef: (execution?.mdtodoRootRef ?? textValue(record.mdtodoRootRef)) || null,
    workspaceRootHash: (execution?.workspaceRootHash ?? textValue(record.workspaceRootHash)) || null,
    workspaceRootLabel: (execution?.workspaceRootLabel ?? textValue(record.workspaceRootLabel)) || null,
    hwpodWorkspaceArgs: (execution?.hwpodWorkspaceArgs ?? textValue(record.hwpodWorkspaceArgs)) || null,
    contextFingerprint: (execution?.contextFingerprint ?? textValue(record.contextFingerprint)) || null,
    capabilities: compactPlainObject(record.capabilities),
    executionContext: execution,
    route: textValue(record.route) || "/projects/mdtodo",
    valuesRedacted: true
  };
}

function compactLaunchExecutionContext(value: unknown): Record<string, unknown> | null {
  const record = objectRecord(value);
  if (!record) return null;
  const sourceId = textValue(record.sourceId) || null;
  const taskRef = textValue(record.taskRef) || null;
  const hwpodId = textValue(record.hwpodId) || null;
  if (!sourceId && !taskRef && !hwpodId) return null;
  return {
    sourceId,
    sourceKind: textValue(record.sourceKind) || null,
    projectId: textValue(record.projectId) || null,
    taskRef,
    fileRef: textValue(record.fileRef) || null,
    relativePath: textValue(record.relativePath) || null,
    taskId: textValue(record.taskId) || null,
    hwpodId,
    nodeId: textValue(record.nodeId) || null,
    mdtodoRootRef: textValue(record.mdtodoRootRef) || null,
    workspaceRootRef: textValue(record.workspaceRootRef) || null,
    workspaceRootHash: textValue(record.workspaceRootHash) || null,
    workspaceRootLabel: textValue(record.workspaceRootLabel) || null,
    hwpodWorkspaceArgs: textValue(record.hwpodWorkspaceArgs) || null,
    contextFingerprint: textValue(record.contextFingerprint) || null,
    capabilities: compactPlainObject(record.capabilities),
    valuesRedacted: true
  };
}

function compactPlainObject(value: unknown): Record<string, unknown> {
  const record = objectRecord(value);
  if (!record) return {};
  const out: Record<string, unknown> = {};
  for (const [key, item] of Object.entries(record)) {
    if (!/^[A-Za-z0-9_.:-]{1,80}$/u.test(key)) continue;
    if (["string", "number", "boolean"].includes(typeof item) || item === null) out[key] = item;
  }
  return out;
}

function sessionJson(session: Record<string, unknown> | null | undefined): Record<string, unknown> | null {
  return objectRecord(session?.sessionJson);
}

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

function textValue(value: unknown): string {
  return typeof value === "string" && value.trim() ? value.trim() : "";
}

function truthyQueryFlag(value: string | null): boolean {
  const normalized = textValue(value).toLowerCase();
  return normalized === "1" || normalized === "true" || normalized === "yes";
}
