/**
 * voice-record-feedback — capture an operator's edit on an agent draft
 * as feedback for the next distillation.
 *
 * Task 424: the Haiku diff-intent summarisation moved into the calling
 * agent's turn. The agent compares `originalText` to `editedText` itself
 * and passes the resulting `intent` string as a required parameter. The
 * tool now does the graph writes only.
 *
 * Task 462: `format` is required. `:VoiceEdit` carries the format; the
 * `FEEDBACK_FOR` edge targets the per-format `:VoiceProfile`.
 *
 * Side effects:
 *   1. Write `(:VoiceEdit)-[:FEEDBACK_FOR]->(:VoiceProfile {format})` if the
 *      per-format profile exists; otherwise write the :VoiceEdit alone so the
 *      next distillation back-fills the edge.
 */
import { randomUUID } from "node:crypto";
import { getSession } from "../lib/neo4j.js";
import type { VoiceFormat } from "../lib/voice-corpus.js";

export interface VoiceRecordFeedbackParams {
  accountId: string;
  userId: string;
  originalText: string;
  editedText: string;
  /**
   * Writing format of the draft being edited. Routes feedback to the
   * matching per-format :VoiceProfile.
   */
  format: VoiceFormat;
  /**
   * One sentence describing what changed and what voice preference it reveals.
   * The calling agent summarises this from `originalText` vs `editedText` in
   * its own turn before invoking the tool (Task 424). Examples: "shorter and
   * dropped the apology", "switched to first person", "removed corporate
   * sign-off", "added a specific date".
   */
  intent: string;
  context?: {
    skill?: string;
    brief?: string;
  };
}

export interface VoiceRecordFeedbackResult {
  editId: string;
  intent: string;
  occurredAt: string;
  hadProfile: boolean;
}

export async function voiceRecordFeedback(
  params: VoiceRecordFeedbackParams,
): Promise<VoiceRecordFeedbackResult> {
  const { accountId, userId, originalText, editedText, format, intent: rawIntent, context } = params;
  if (!accountId || !userId) {
    throw new Error("voice-record-feedback: accountId and userId required");
  }
  if (!originalText || !editedText) {
    throw new Error("voice-record-feedback: originalText and editedText required");
  }
  if (!format) {
    throw new Error("voice-record-feedback: format is required");
  }
  const intent = (rawIntent ?? "").trim();
  if (!intent) {
    throw new Error(
      "voice-record-feedback: intent is required — summarise what the operator changed in-turn before calling this tool (Task 424).",
    );
  }

  const editId = randomUUID();
  const occurredAt = new Date().toISOString();
  const cappedIntent = intent.slice(0, 500);

  const session = getSession();
  try {
    const result = await session.run(
      `MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
       CREATE (e:VoiceEdit {
         editId: $editId,
         accountId: $accountId,
         userId: $userId,
         format: $format,
         originalText: $originalText,
         editedText: $editedText,
         intent: $intent,
         occurredAt: $occurredAt,
         skill: $skill,
         brief: $brief
       })
       CREATE (a)-[:AUTHORED]->(e)
       WITH e
       OPTIONAL MATCH (:AdminUser {accountId: $accountId, userId: $userId})-[:HAS_VOICE_PROFILE]->(p:VoiceProfile {accountId: $accountId, userId: $userId, format: $format})
       FOREACH (_ IN CASE WHEN p IS NULL THEN [] ELSE [1] END |
         MERGE (e)-[:FEEDBACK_FOR]->(p)
       )
       RETURN elementId(e) AS editId, (p IS NOT NULL) AS hadProfile`,
      {
        accountId,
        userId,
        format,
        editId,
        originalText,
        editedText,
        intent: cappedIntent,
        occurredAt,
        skill: context?.skill ?? null,
        brief: context?.brief ?? null,
      },
    );
    if (result.records.length === 0) {
      throw new Error(
        `voice-mirror: :AdminUser {accountId='${accountId}', userId='${userId}'} not found. Onboarding must promote the operator to :AdminUser before feedback can be recorded.`,
      );
    }
    const hadProfile = result.records[0].get("hadProfile") === true;

    process.stderr.write(
      `[voice-record-feedback] adminUser=${userId} format=${format} intent="${cappedIntent.replace(/"/g, "'")}" diffBytes=${editedText.length - originalText.length}\n`,
    );

    return { editId, intent: cappedIntent, occurredAt, hadProfile };
  } finally {
    await session.close();
  }
}
