import { prisma } from '@/lib/prisma'
import { getTagsProvider } from '@/lib/ai/factory'
import { getSystemConfig } from '@/lib/config'
import type { Notebook } from '@/lib/types'

export class NotebookSuggestionService {
  /**
   * Suggest the most appropriate notebook for a note
   * @param noteContent - Content of the note
   * @param userId - User ID (for fetching user's notebooks)
   * @returns Suggested notebook or null (if no good match)
   */
  async suggestNotebook(noteContent: string, userId: string, language: string = 'en'): Promise<Notebook | null> {
    // 1. Get all notebooks for this user
    const notebooks = await prisma.notebook.findMany({
      where: { userId },
      include: {
        labels: true,
        _count: {
          select: { notes: true },
        },
      },
      orderBy: { order: 'asc' },
    })

    if (notebooks.length === 0) {
      return null // No notebooks to suggest
    }

    // 2. Build prompt for AI (always in French - interface language)
    const prompt = this.buildPrompt(noteContent, notebooks, language)

    // 3. Call AI
    try {
      const config = await getSystemConfig()
      const provider = getTagsProvider(config)

      const response = await provider.generateText(prompt)

      const suggestedName = response.trim().toUpperCase()

      // 5. Find matching notebook
      const suggestedNotebook = notebooks.find(nb =>
        nb.name.toUpperCase() === suggestedName
      )

      // If AI says "NONE" or no match, return null
      if (suggestedName === 'NONE' || !suggestedNotebook) {
        return null
      }

      return suggestedNotebook as Notebook
    } catch (error) {
      console.error('Failed to suggest notebook:', error)
      return null
    }
  }

  /**
   * Build the AI prompt for notebook suggestion (localized)
   */
  private buildPrompt(noteContent: string, notebooks: any[], language: string = 'en'): string {
    const notebookList = notebooks
      .map(nb => {
        const labels = nb.labels.map((l: any) => l.name).join(', ')
        const count = nb._count?.notes || 0
        return `- ${nb.name} (${count} notes)${labels ? ` [labels: ${labels}]` : ''}`
      })
      .join('\n')

    const instructions: Record<string, string> = {
      fr: `
Tu es un assistant qui suggère à quel carnet une note devrait appartenir.

CONTENU DE LA NOTE :
${noteContent.substring(0, 500)}

CARNETS DISPONIBLES :
${notebookList}

TÂCHE :
Analyse le contenu de la note (peu importe la langue) et suggère le carnet le PLUS approprié pour cette note.
Considère :
1. Le sujet/thème de la note (LE PLUS IMPORTANT)
2. Les labels existants dans chaque carnet
3. Le nombre de notes (préfère les carnets avec du contenu connexe)

GUIDES DE CLASSIFICATION :
- SPORT/EXERCICE/ACHATS/COURSSES → Carnet Personnel
- LOISIRS/PASSIONS/SORTIES → Carnet Personnel
- SANTÉ/FITNESS/MÉDECIN → Carnet Personnel ou Santé
- FAMILLE/AMIS → Carnet Personnel
- TRAVAIL/RÉUNIONS/PROJETS/CLIENTS → Carnet Travail
- CODING/TECH/DÉVELOPPEMENT → Carnet Travail ou Code
- FINANCES/FACTURES/BANQUE → Carnet Personnel ou Finances

RÈGLES :
- Retourne SEULEMENT le nom du carnet, EXACTEMENT comme indiqué ci-dessus (insensible à la casse)
- Si aucune bonne correspondance n'existe, retourne "NONE"
- Si la note est trop générique/vague, retourne "NONE"
- N'inclus pas d'explications ou de texte supplémentaire

Exemples :
- "Réunion avec Jean sur le planning du projet" → carnet "Travail"
- "Liste de courses ou achat de vêtements" → carnet "Personnel"
- "Script Python pour analyse de données" → carnet "Code"
- "Séance de sport ou fitness" → carnet "Personnel"
- "Achat d'une chemise et d'un jean" → carnet "Personnel"

Ta suggestion :
`.trim(),
      en: `
You are an assistant that suggests which notebook a note should belong to.

NOTE CONTENT:
${noteContent.substring(0, 500)}

AVAILABLE NOTEBOOKS:
${notebookList}

TASK:
Analyze the note content (regardless of language) and suggest the MOST appropriate notebook for this note.
Consider:
1. The subject/theme of the note (MOST IMPORTANT)
2. Existing labels in each notebook
3. The number of notes (prefer notebooks with related content)

CLASSIFICATION GUIDE:
- SPORT/EXERCISE/SHOPPING/GROCERIES → Personal Notebook
- HOBBIES/PASSIONS/OUTINGS → Personal Notebook
- HEALTH/FITNESS/DOCTOR → Personal Notebook or Health
- FAMILY/FRIENDS → Personal Notebook
- WORK/MEETINGS/PROJECTS/CLIENTS → Work Notebook
- CODING/TECH/DEVELOPMENT → Work Notebook or Code
- FINANCE/BILLS/BANKING → Personal Notebook or Finance

RULES:
- Return ONLY the notebook name, EXACTLY as listed above (case insensitive)
- If no good match exists, return "NONE"
- If the note is too generic/vague, return "NONE"
- Do not include explanations or extra text

Examples:
- "Meeting with John about project planning" → notebook "Work"
- "Grocery list or buying clothes" → notebook "Personal"
- "Python script for data analysis" → notebook "Code"
- "Gym session or fitness" → notebook "Personal"

Your suggestion:
`.trim(),
      fa: `
شما یک دستیار هستید که پیشنهاد می‌دهد یک یادداشت به کدام دفترچه تعلق داشته باشد.

محتوای یادداشت:
${noteContent.substring(0, 500)}

دفترچه‌های موجود:
${notebookList}

وظیفه:
محتوای یادداشت را تحلیل کنید (صرف نظر از زبان) و مناسب‌ترین دفترچه را برای این یادداشت پیشنهاد دهید.
در نظر بگیرید:
1. موضوع/تم یادداشت (مهم‌ترین)
2. برچسب‌های موجود در هر دفترچه
3. تعداد یادداشت‌ها (دفترچه‌های با محتوای مرتبط را ترجیح دهید)

راهنمای طبقه‌بندی:
- ورزش/تمرین/خرید → دفترچه شخصی
- سرگرمی‌ها/علایق/گردش → دفترچه شخصی
- سلامت/تناسب اندام/پزشک → دفترچه شخصی یا سلامت
- خانواده/دوستان → دفترچه شخصی
- کار/جلسات/پروژه‌ها/مشتریان → دفترچه کار
- کدنویسی/تکنولوژی/توسعه → دفترچه کار یا کد
- مالی/قبض‌ها/بانک → دفترچه شخصی یا مالی

قوانین:
- فقط نام دفترچه را برگردانید، دقیقاً همانطور که در بالا ذکر شده است (بدون حساسیت به حروف بزرگ و کوچک)
- اگر تطابق خوبی وجود ندارد، "NONE" را برگردانید
- اگر یادداشت خیلی کلی/مبهم است، "NONE" را برگردانید
- توضیحات یا متن اضافی را شامل نکنید

پیشناد شما:
`.trim(),
      es: `
Eres un asistente que sugiere a qué cuaderno debería pertenecer una nota.

CONTENIDO DE LA NOTA:
${noteContent.substring(0, 500)}

CUADERNOS DISPONIBLES:
${notebookList}

TAREA:
Analiza el contenido de la nota (independientemente del idioma) y sugiere el cuaderno MÁS apropiado para esta nota.
Considera:
1. El tema/asunto de la nota (LO MÁS IMPORTANTE)
2. Etiquetas existentes en cada cuaderno
3. El número de notas (prefiere cuadernos con contenido relacionado)

GUÍA DE CLASIFICACIÓN:
- DEPORTE/EJERCICIO/COMPRAS → Cuaderno Personal
- HOBBIES/PASIONES/SALIDAS → Cuaderno Personal
- SALUD/FITNESS/DOCTOR → Cuaderno Personal o Salud
- FAMILIA/AMIGOS → Cuaderno Personal
- TRABAJO/REUNIONES/PROYECTOS → Cuaderno Trabajo
- CODING/TECH/DESARROLLO → Cuaderno Trabajo o Código
- FINANZAS/FACTURAS/BANCO → Cuaderno Personal o Finanzas

REGLAS:
- Devuelve SOLO el nombre del cuaderno, EXACTAMENTE como se lista arriba (insensible a mayúsculas/minúsculas)
- Si no existe una buena coincidencia, devuelve "NONE"
- Si la nota es demasiado genérica/vaga, devuelve "NONE"
- No incluyas explicaciones o texto extra

Tu sugerencia:
`.trim(),
      de: `
Du bist ein Assistent, der vorschlägt, zu welchem Notizbuch eine Notiz gehören sollte.

NOTIZINHALT:
${noteContent.substring(0, 500)}

VERFÜGBARE NOTIZBÜCHER:
${notebookList}

AUFGABE:
Analysiere den Notizinhalt (unabhängig von der Sprache) und schlage das AM BESTEN geeignete Notizbuch für diese Notiz vor.
Berücksichtige:
1. Das Thema/den Inhalt der Notiz (AM WICHTIGSTEN)
2. Vorhandene Labels in jedem Notizbuch
3. Die Anzahl der Notizen (bevorzuge Notizbücher mit verwandtem Inhalt)

KLASSIFIZIERUNGSLEITFADEN:
- SPORT/ÜBUNG/EINKAUFEN → Persönliches Notizbuch
- HOBBYS/LEIDENSCHAFTEN → Persönliches Notizbuch
- GESUNDHEIT/FITNESS/ARZT → Persönliches Notizbuch oder Gesundheit
- FAMILIE/FREUNDE → Persönliches Notizbuch
- ARBEIT/MEETINGS/PROJEKTE → Arbeitsnotizbuch
- CODING/TECH/ENTWICKLUNG → Arbeitsnotizbuch oder Code
- FINANZEN/RECHNUNGEN/BANK → Persönliches Notizbuch oder Finanzen

REGELN:
- Gib NUR den Namen des Notizbuchs zurück, GENAU wie oben aufgeführt (Groß-/Kleinschreibung egal)
- Wenn keine gute Übereinstimmung existiert, gib "NONE" zurück
- Wenn die Notiz zu allgemein/vage ist, gib "NONE" zurück
- Füge keine Erklärungen oder zusätzlichen Text hinzu

Dein Vorschlag:
`.trim()
    }

    return instructions[language] || instructions['en'] || instructions['fr']
  }

  /**
   * Batch suggest notebooks for multiple notes (IA3)
   * @param noteContents - Array of note contents
   * @param userId - User ID
   * @returns Map of note index -> suggested notebook
   */
  async suggestNotebooksBatch(
    noteContents: string[],
    userId: string,
    language: string = 'en'
  ): Promise<Map<number, Notebook | null>> {
    const results = new Map<number, Notebook | null>()

    // For efficiency, we could batch this into a single AI call
    // For now, process sequentially (could be parallelized)
    for (let i = 0; i < noteContents.length; i++) {
      const suggestion = await this.suggestNotebook(noteContents[i], userId, language)
      results.set(i, suggestion)
    }

    return results
  }

  /**
   * Get notebook suggestion confidence score
   * (For future UI enhancement: show confidence level)
   */
  async suggestNotebookWithConfidence(
    noteContent: string,
    userId: string
  ): Promise<{ notebook: Notebook | null; confidence: number }> {
    // This could use logprobs from OpenAI API to calculate confidence
    // For now, return binary confidence
    const notebook = await this.suggestNotebook(noteContent, userId)
    return {
      notebook,
      confidence: notebook ? 0.8 : 0, // Fixed confidence for now
    }
  }
}

// Export singleton instance
export const notebookSuggestionService = new NotebookSuggestionService()
