/**
 * POST /api/lyra/memories/extract
 *
 * Extrahiert strukturierte Memories aus einem SOS/Coach-Gespräch via LLM (Claude Haiku).
 * Wird intern (fire-and-forget) nach SOS-Stream-Ende aufgerufen.
 *
 * Body: { sessionId: string, conversation: Array<{role, content}> }
 * Response: { extracted: number, skipped: number }
 *
 * Fehler: silent — User darf nichts merken. Logging via [lyra-memory].
 */
import { upsertMemory } from "../../../db/lyraMemory";
import type { LyraMemoryType } from "../../../db/lyraMemory";

const VALID_TYPES: LyraMemoryType[] = [
  "trigger",
  "habit",
  "strength",
  "relationship",
  "milestone",
  "pain_point",
  "goal",
  "preference",
];

const EXTRACTION_SYSTEM_PROMPT = `Du extrahierst aus einem Gespräch zwischen User und Lyra-Coach strukturierte Fakten über den User. Output strikt als JSON-Array:
[{"type":"trigger|habit|strength|relationship|milestone|pain_point|goal|preference", "content":"<kurzer Fakt, max 200 chars>", "confidence":0.0-1.0}]
Regeln:
- Nur Fakten die der USER explizit oder implizit über sich geteilt hat. Nichts erfinden.
- Keine Vermutungen über Diagnosen oder Pathologisierungen ("süchtig", "krank" etc).
- Nur Wesentliches. Wenn nichts Neues drin ist → leeres Array [].
- confidence: 0.9+ wenn User explizit gesagt, 0.5-0.7 wenn implizit, <0.5 garnicht extrahieren.
- content in der Sprache des Gesprächs (DE).
- Maximal 8 Einträge pro Extraktion.`;

export default defineEventHandler(async (event) => {
  const user = await requireUser(event);

  const body = await readBody(event);
  const {
    sessionId,
    conversation,
  }: {
    sessionId?: string;
    conversation: Array<{ role: string; content: string }>;
  } = body;

  if (!Array.isArray(conversation) || conversation.length === 0) {
    throw createError({ statusCode: 400, message: "conversation fehlt" });
  }

  const config = useRuntimeConfig();
  const key = config.openrouterApiKey as string | undefined;
  if (!key) {
    throw createError({ statusCode: 503, message: "OpenRouter Key fehlt" });
  }

  // Nur User-Nachrichten extrahieren (Lyra-Antworten sind Kontext, kein User-Fakt)
  const userMessages = conversation.filter((m) => m.role === "user");
  if (userMessages.length === 0) {
    return { extracted: 0, skipped: 0 };
  }

  // Konversation als lesbaren Text aufbereiten (max 4000 chars für Haiku)
  const conversationText = conversation
    .slice(-20) // letzte 20 Messages reichen für Kontext
    .map((m) => `${m.role === "user" ? "User" : "Lyra"}: ${m.content}`)
    .join("\n")
    .slice(0, 4000);

  let extracted = 0;
  let skipped = 0;

  try {
    const res = await $fetch<{
      choices: { message: { content: string } }[];
    }>("https://openrouter.ai/api/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${key}`,
        "Content-Type": "application/json",
        "HTTP-Referer": "https://rebreak.org",
        "X-Title": "ReBreak Memory Extraction",
      },
      body: {
        model: "anthropic/claude-haiku-4-5",
        max_tokens: 800,
        temperature: 0.1,
        messages: [
          { role: "system", content: EXTRACTION_SYSTEM_PROMPT },
          { role: "user", content: conversationText },
        ],
      },
      timeout: 20000,
    });

    const raw = res.choices?.[0]?.message?.content?.trim();
    if (!raw) {
      console.log("[lyra-memory] extract: empty response from LLM");
      return { extracted: 0, skipped: 0 };
    }

    // JSON-Array parsen (Haiku gibt manchmal Markdown-Fences zurück)
    const jsonStr = raw
      .replace(/^```(?:json)?\s*/i, "")
      .replace(/\s*```$/, "")
      .trim();

    let facts: Array<{
      type: string;
      content: string;
      confidence: number;
    }> = [];

    try {
      facts = JSON.parse(jsonStr);
    } catch {
      console.warn(
        "[lyra-memory] extract: JSON parse failed:",
        jsonStr.slice(0, 200),
      );
      return { extracted: 0, skipped: 0 };
    }

    if (!Array.isArray(facts)) {
      return { extracted: 0, skipped: 0 };
    }

    for (const fact of facts) {
      // Confidence < 0.5 → skip
      if (!fact.content || (fact.confidence ?? 0) < 0.5) {
        skipped++;
        continue;
      }

      // Typ validieren
      if (!VALID_TYPES.includes(fact.type as LyraMemoryType)) {
        console.warn("[lyra-memory] extract: invalid type:", fact.type);
        skipped++;
        continue;
      }

      try {
        await upsertMemory(
          user.id,
          fact.type as LyraMemoryType,
          fact.content,
          sessionId ?? "sos-session",
          Math.min(1, Math.max(0, fact.confidence ?? 0.7)),
        );
        extracted++;
      } catch (e) {
        console.error("[lyra-memory] upsert error:", e);
        skipped++;
      }
    }

    console.log(
      `[lyra-memory] extract done for ${user.id}: ${extracted} extracted, ${skipped} skipped`,
    );
  } catch (e) {
    // Silent fail — User darf nichts merken
    console.error("[lyra-memory] extract LLM error:", e);
    return { extracted: 0, skipped: 0 };
  }

  return { success: true, data: { extracted, skipped } };
});
