// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-24-p1-opencode-message-part-authority.
// Responsibility: AgentRun prompt evidence, message-authority text normalization, and prompt hash/preview DTO fields.

import { createHash } from "node:crypto";

import { safeTraceId } from "./server-http-utils.ts";

export function agentRunPromptMetadataFromParams(params = {}, traceId = null) {
  return agentRunPromptMetadataFromText(firstNonEmpty(params.message, params.prompt, params.text), traceId, "hwlab-code-agent-request", { fullText: true });
}

export function agentRunPromptMetadataFromSession(session = null, traceId = null) {
  const snapshot = session?.session && typeof session.session === "object" ? session.session : null;
  const fromTraceResult = agentRunPromptMetadataFromPayload(snapshot?.traceResults?.[traceId], traceId);
  if (fromTraceResult) return fromTraceResult;
  const messageText = agentRunPromptTextFromMessages(snapshot?.messages, traceId);
  if (messageText) return agentRunPromptMetadataFromText(messageText, traceId, "agent-session-owner-message", { fullText: true });
  const preview = firstNonEmpty(snapshot?.firstUserMessagePreview);
  return preview ? agentRunPromptMetadataFromText(preview, traceId, "agent-session-first-user-preview", { fullText: false }) : null;
}

export function agentRunPromptMetadataFromText(value, traceId = null, source = "hwlab-code-agent-request", options = {}) {
  const promptText = promptTextValue(value);
  if (!promptText) return null;
  return agentRunPromptMetadataFromParts({
    traceId,
    source,
    promptSha256: options.fullText === true ? sha256Text(promptText) : undefined,
    promptSummary: promptText,
    promptPreview: promptText,
    textChars: options.fullText === true ? promptText.length : undefined
  });
}

export function agentRunPromptFields(metadata = null) {
  if (!metadata) return {};
  return compactObject({
    promptId: metadata.promptId,
    promptSha256: metadata.promptSha256,
    promptSummary: metadata.promptSummary,
    promptPreview: metadata.promptPreview,
    prompt: metadata.prompt
  }) ?? {};
}

export function agentRunPromptEventFields(metadata = null) {
  if (!metadata) return {};
  return compactObject({
    promptId: metadata.promptId,
    promptSha256: metadata.promptSha256,
    promptSummary: metadata.promptSummary,
    promptPreview: metadata.promptPreview
  }) ?? {};
}

export function messageAuthorityTextValue(value) {
  const extracted = promptTextRaw(value).replace(/\r\n?/gu, "\n");
  if (!extracted.trim() || extracted.trim() === "[object Object]") return "";
  return extracted;
}

function agentRunPromptMetadataFromPayload(payload = null, traceId = null) {
  if (!payload || typeof payload !== "object") return null;
  const prompt = payload.prompt && typeof payload.prompt === "object" ? payload.prompt : null;
  const textValue = firstNonEmpty(prompt?.text, prompt?.summary, prompt?.preview, payload.promptSummary, payload.promptPreview);
  const fromText = agentRunPromptMetadataFromText(textValue, traceId, prompt?.source ?? payload.promptSource ?? "agentrun-prompt-metadata", { fullText: Boolean(prompt?.text) });
  return agentRunPromptMetadataFromParts({
    traceId,
    source: prompt?.source ?? payload.promptSource ?? fromText?.prompt?.source ?? "agentrun-prompt-metadata",
    promptId: firstNonEmpty(payload.promptId, prompt?.id, fromText?.promptId),
    promptSha256: firstNonEmpty(payload.promptSha256, prompt?.sha256, fromText?.promptSha256),
    promptSummary: firstNonEmpty(payload.promptSummary, prompt?.summary, fromText?.promptSummary),
    promptPreview: firstNonEmpty(payload.promptPreview, prompt?.preview, fromText?.promptPreview),
    textChars: Number.isInteger(prompt?.textChars) ? prompt.textChars : fromText?.prompt?.textChars
  });
}

function agentRunPromptTextFromMessages(messages = [], traceId = null) {
  const list = Array.isArray(messages) ? messages : [];
  const resolvedTraceId = safeTraceId(traceId);
  const exact = list.find((message) => String(message?.role ?? "").toLowerCase() === "user" && (!resolvedTraceId || safeTraceId(message?.traceId) === resolvedTraceId));
  const fallback = list.find((message) => String(message?.role ?? "").toLowerCase() === "user");
  return firstNonEmpty(exact?.text, exact?.content, fallback?.text, fallback?.content);
}

function agentRunPromptMetadataFromParts({ traceId = null, source = "hwlab-code-agent-request", promptId = null, promptSha256 = null, promptSummary = null, promptPreview = null, textChars = undefined } = {}) {
  const digest = firstNonEmpty(promptSha256);
  const summary = clippedPromptText(firstNonEmpty(promptSummary, promptPreview), 240);
  const preview = clippedPromptText(firstNonEmpty(promptPreview, promptSummary), 500);
  const explicitId = firstNonEmpty(promptId);
  if (!explicitId && !digest && !summary && !preview) return null;
  const id = explicitId || agentRunPromptId(traceId, digest);
  const prompt = compactObject({
    id,
    sha256: digest || undefined,
    summary,
    preview,
    textChars: Number.isInteger(textChars) ? textChars : undefined,
    source,
    valuesPrinted: false
  });
  return compactObject({
    promptId: id,
    promptSha256: digest || undefined,
    promptSummary: summary,
    promptPreview: preview,
    prompt,
    valuesPrinted: false
  }) ?? null;
}

function agentRunPromptId(traceId = null, digest = null) {
  const traceSuffix = safeTraceId(traceId)?.slice(4).replace(/[^A-Za-z0-9_.:-]/gu, "_");
  const digestSuffix = firstNonEmpty(digest)?.slice(0, 16);
  const suffix = firstNonEmpty(traceSuffix, digestSuffix);
  return suffix ? `prm_${suffix}` : undefined;
}

function clippedPromptText(value, limit) {
  const promptText = promptTextValue(value);
  if (!promptText) return undefined;
  return promptText.length > limit ? `${promptText.slice(0, limit)}...` : promptText;
}

function promptTextValue(value) {
  const extracted = promptTextRaw(value).replace(/\s+/gu, " ").trim();
  if (!extracted || extracted === "[object Object]") return "";
  return extracted;
}

function promptTextRaw(value) {
  if (value === undefined || value === null) return "";
  if (typeof value === "string") return value;
  if (typeof value === "number" || typeof value === "boolean") return String(value);
  if (Array.isArray(value)) return value.map(promptTextRaw).filter(Boolean).join("\n");
  if (typeof value === "object") {
    for (const key of ["text", "content", "message", "prompt", "value", "summary", "preview", "title"]) {
      const text = promptTextRaw(value[key]);
      if (text) return text;
    }
  }
  return "";
}

function sha256Text(value) {
  return createHash("sha256").update(String(value)).digest("hex");
}

function compactObject(value) {
  if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
  const result = {};
  for (const [key, item] of Object.entries(value)) {
    if (item === undefined || item === null) continue;
    if (Array.isArray(item) && item.length === 0) continue;
    if (typeof item === "object" && !Array.isArray(item) && Object.keys(item).length === 0) continue;
    result[key] = item;
  }
  return Object.keys(result).length > 0 ? result : undefined;
}

function firstNonEmpty(...values) {
  for (const value of values) {
    const text = String(value ?? "").trim();
    if (text) return text;
  }
  return null;
}
