/**
 * POST /api/chatbot-v2
 *
 * Chatbot V2 - Embedding-based search sur structures bifurcation
 * Coexiste avec /api/chatbot (keyword NocoDB) pendant la transition.
 *
 * SETUP AVANT DEPLOY :
 * cd nav-carte && MISTRAL_API_KEY=xxx node scripts/vectorize-v2.js
 * Coût estimé : ~0.10 EUR pour 120 fiches
 *
 * Flow :
 *   1. Rate limit (réutilise checkRateLimitJson, 10 req/IP/jour)
 *   2. Embed la query via Mistral Embed (mistral-embed)
 *   3. Top-5 cosine similarity sur embeddings-v2.json
 *   4. Si embeddings absents : réponse graceful (v2_ready: false)
 *   5. Construit contexte RAG depuis les fiches candidates
 *   6. Génère réponse Mistral Small (json_object)
 *   7. Retourne { reponse_texte, fiches_recommandees, sources, v2_ready }
 *
 * Variables d'env :
 *   MISTRAL_API_KEY       - Clé Mistral (partagée avec chatbot v1)
 *   RAG_V1_ENABLED        - true/false (défaut: true) - coexistence pendant transition
 *   RAG_V1_DEPRECATION_DATE - Date prévue deprecation v1 (ex: 2026-05-18)
 */

import { checkRateLimitJson } from '~/server/utils/rateLimitJson'
import { loadEmbeddingsV2, topKSearch } from '~/server/utils/vectorSearch'

// ── System prompt V2 ───────────────────────────────────────────────────────────

const SYSTEM_PROMPT_V2 = `Tu es un assistant pour la carte des réseaux de bifurcation en architecture (projet AEP).
Tu réponds aux questions sur les structures, les pratiques, les pensées écologiques.

Règles :
- Cite chaque structure par son nom exact et son fiche_id
- Indique la famille (1-5) entre parenthèses après chaque nom
- Reste sobre et descriptif - pas militant agressif
- Tirets longs interdits : utilise des - ou des ;
- Max 200 mots par réponse
- Si hors-scope (pas archi/habiter/écologie), redirige poliment vers la carte
- Retourne UNIQUEMENT un JSON valide, sans texte avant ou après

Familles :
1 - Réemploi et filières
2 - Frugalité et low-tech
3 - Architecture sociale et précarités
4 - Collectifs, écolieux et AMO
5 - Urbanisme de transition et territoires

FORMAT DE SORTIE :
{
  "reponse_texte": "Ta réponse en prose (max 200 mots)",
  "fiches_recommandees": [
    { "fiche_id": "f1-rotor", "nom": "Rotor", "explication": "1-2 phrases pourquoi cette fiche" }
  ]
}

CONTEXTE - Structures disponibles :
{{CONTEXTE_RAG}}`

// ── Handler ────────────────────────────────────────────────────────────────────

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()

  // 1. Rate limit
  const ip =
    getHeader(event, 'x-forwarded-for')?.split(',')[0].trim() ||
    event.node.req.socket?.remoteAddress ||
    '0.0.0.0'

  const allowed = checkRateLimitJson(ip, 'chatbot-v2', 10)
  if (!allowed) {
    throw createError({
      statusCode: 429,
      statusMessage: 'Limite de 10 questions par jour atteinte.'
    })
  }

  // 2. Validation body
  const body = await readBody(event)
  const question: string = (body?.question ?? '').trim()

  if (!question || question.length < 3) {
    throw createError({ statusCode: 400, statusMessage: 'Question trop courte.' })
  }

  const mistralApiKey = config.mistralApiKey as string
  if (!mistralApiKey) {
    throw createError({ statusCode: 500, statusMessage: 'Clé API Mistral manquante.' })
  }

  // 3. Charger embeddings V2 (lazy, cachés en mémoire)
  const embeddingsV2 = loadEmbeddingsV2()

  // Graceful fallback si le script vectorize-v2.js n'a pas encore été lancé
  if (embeddingsV2.length === 0) {
    return {
      reponse_texte: "La base vectorielle V2 est en cours de préparation. Merci d'utiliser le chatbot classique en attendant.",
      fiches_recommandees: [],
      sources: [],
      v2_ready: false
    }
  }

  // 4. Embed la query via Mistral Embed
  let queryEmbedding: number[]
  try {
    const embedRes = await $fetch<{ data: { embedding: number[] }[] }>(
      'https://api.mistral.ai/v1/embeddings',
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${mistralApiKey}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          model: 'mistral-embed',
          inputs: [question]
        })
      }
    )
    queryEmbedding = embedRes.data[0].embedding
  } catch (e: any) {
    console.error('[chatbot-v2] Erreur embedding Mistral :', e?.message ?? e)
    throw createError({ statusCode: 502, statusMessage: 'Erreur embedding Mistral.' })
  }

  // 5. Top-5 cosine similarity
  const v2Results = topKSearch(embeddingsV2, queryEmbedding, 5)

  // 6. Contexte RAG
  const candidatesContext = v2Results.map(r => ({
    fiche_id: r.fiche_id,
    nom: r.nom,
    famille: r.famille,
    hashtags: r.hashtags,
    score: r.score,
    preview: r.text_preview
  }))

  const contextStr = candidatesContext
    .map(c => `[${c.fiche_id}] ${c.nom} (famille ${c.famille}, score: ${c.score.toFixed(2)})\n${c.preview}`)
    .join('\n\n---\n\n')

  const systemPrompt = SYSTEM_PROMPT_V2.replace('{{CONTEXTE_RAG}}', contextStr)

  // 7. Mistral Small - génération réponse
  let mistralRaw: string
  try {
    const mistralRes = await $fetch<{
      choices: { message: { content: string } }[]
    }>('https://api.mistral.ai/v1/chat/completions', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${mistralApiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        model: 'mistral-small-latest',
        temperature: 0.3,
        max_tokens: 600,
        response_format: { type: 'json_object' },
        messages: [
          { role: 'system', content: systemPrompt },
          { role: 'user', content: question }
        ]
      })
    })
    mistralRaw = mistralRes.choices?.[0]?.message?.content ?? '{}'
  } catch (e: any) {
    console.error('[chatbot-v2] Erreur Mistral Small :', e?.message ?? e)
    throw createError({ statusCode: 502, statusMessage: 'Erreur appel Mistral Small.' })
  }

  // 8. Parse JSON
  let parsed: { reponse_texte: string; fiches_recommandees: any[] }
  try {
    parsed = JSON.parse(mistralRaw)
    if (!parsed.reponse_texte) throw new Error('reponse_texte absent')
  } catch {
    parsed = {
      reponse_texte: "Impossible d'analyser la réponse.",
      fiches_recommandees: []
    }
  }

  return {
    reponse_texte: parsed.reponse_texte,
    fiches_recommandees: parsed.fiches_recommandees ?? [],
    sources: candidatesContext,
    v2_ready: true
  }
})
