import { NextResponse } from "next/server";
import { GoogleGenerativeAI } from "@google/generative-ai";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { estimateHbA1c, statusFor, type Moment } from "@/lib/glycemia";
import { DIABETES_TYPE_LABELS, SEX_LABELS } from "@/lib/patient";
import { differenceInYears, format } from "date-fns";
import { fr } from "date-fns/locale";

const MAX_MESSAGES = 20;

type ChatMessage = { role: "user" | "model"; content: string };

function buildSystemPrompt(ctx: {
  patient: {
    firstName: string;
    lastName: string;
    sex: string | null;
    birthDate: Date | null;
    heightCm: number | null;
    weightKg: number | null;
    diabetesType: string | null;
    treatment: string | null;
  } | null;
  stats: {
    count7: number;
    avg7: number | null;
    count30: number;
    avg30: number | null;
    inRangePct30: number | null;
    hypo30: number;
    hyper30: number;
    hba1c: number | null;
    lastValue: number | null;
    lastMoment: string | null;
    lastDate: Date | null;
  };
}): string {
  const { patient, stats } = ctx;

  const patientSection = patient
    ? (() => {
        const age = patient.birthDate
          ? differenceInYears(new Date(), patient.birthDate)
          : null;
        const bmi =
          patient.heightCm && patient.weightKg
            ? patient.weightKg / Math.pow(patient.heightCm / 100, 2)
            : null;
        return `
## Fiche patient
- Nom : ${patient.firstName} ${patient.lastName}
- Sexe : ${patient.sex ? (SEX_LABELS[patient.sex] ?? patient.sex) : "non renseigné"}
- Âge : ${age !== null ? `${age} ans` : "non renseigné"}
- Taille : ${patient.heightCm ? `${patient.heightCm} cm` : "non renseignée"}
- Poids : ${patient.weightKg ? `${patient.weightKg} kg` : "non renseigné"}
- IMC : ${bmi ? `${bmi.toFixed(1)}` : "non calculable"}
- Type de diabète : ${patient.diabetesType ? (DIABETES_TYPE_LABELS[patient.diabetesType] ?? patient.diabetesType) : "non renseigné"}
- Traitement en cours : ${patient.treatment ?? "non renseigné"}`;
      })()
    : "## Fiche patient\nAucune fiche patient renseignée.";

  const statsSection = `
## Données glycémiques récentes
- Dernière mesure : ${stats.lastValue !== null ? `${stats.lastValue.toFixed(2).replace(".", ",")} g/L (${stats.lastMoment ?? ""})${stats.lastDate ? ` le ${format(stats.lastDate, "d MMMM yyyy", { locale: fr })}` : ""}` : "aucune"}
- Moyenne sur 7 jours : ${stats.avg7 !== null ? `${stats.avg7.toFixed(2).replace(".", ",")} g/L (${stats.count7} relevés)` : "aucune donnée"}
- Moyenne sur 30 jours : ${stats.avg30 !== null ? `${stats.avg30.toFixed(2).replace(".", ",")} g/L (${stats.count30} relevés)` : "aucune donnée"}
- % dans la cible sur 30 jours : ${stats.inRangePct30 !== null ? `${stats.inRangePct30.toFixed(0)} %` : "aucune donnée"}
- Épisodes d'hypoglycémie (30j) : ${stats.hypo30}
- Épisodes d'hyperglycémie (30j) : ${stats.hyper30}
- HbA1c estimée (indicatif) : ${stats.hba1c !== null ? `${stats.hba1c.toFixed(1)} %` : "aucune donnée"}`;

  return `Tu es Diablo, un coach diabète bienveillant et pédagogue intégré à l'application Diabetix. Tu aides les patients à comprendre leurs données glycémiques et à adopter de bonnes habitudes.

## Ton rôle
- Analyser les relevés glycémiques et donner des explications claires et encourageantes
- Donner des conseils pratiques sur l'alimentation, l'activité physique, le rythme des prises de mesures
- Expliquer les tendances : pourquoi une glycémie est élevée après un repas, l'impact du stress ou de l'exercice
- Encourager le patient sans le culpabiliser
- Poser des questions pour mieux comprendre le contexte (repas, activité, stress, sommeil)

## Tes limites (IMPORTANT)
- Tu n'es PAS un médecin et tu ne te substitues pas à l'équipe soignante
- Tu ne modifies JAMAIS un traitement médical, ne recommandes jamais d'ajuster les doses d'insuline ou de médicaments
- En cas d'urgence (hypoglycémie sévère, malaise), tu diriges immédiatement vers les secours (15, 112) ou le médecin
- Tu rappelles toujours de consulter le médecin pour toute décision médicale
- Tu gardes un ton positif, jamais alarmiste sauf urgence réelle

## Format de tes réponses
- Réponds en français, de façon concise et chaleureuse
- Utilise des emojis avec modération pour rendre la lecture agréable
- Structure avec des listes à points si la réponse est longue
- Commence souvent par reconnaître ce que le patient vit/ressent

${patientSection}
${statsSection}

Utilise ces données pour personnaliser tes conseils. Si une information manque, pose la question.`;
}

export async function POST(request: Request) {
  const session = await auth();
  if (!session?.user?.id) return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
  const userId = session.user.id;

  const plan = (session.user as { plan?: string }).plan ?? "FREE";
  if (plan !== "PREMIUM") {
    return NextResponse.json(
      { error: "Le chatbot Diablo est réservé aux membres Premium. Passez à Premium pour en bénéficier." },
      { status: 403 }
    );
  }

  const apiKey = process.env.GEMINI_API_KEY;
  if (!apiKey || apiKey === "your_gemini_api_key_here") {
    return NextResponse.json(
      { error: "Clé API Gemini non configurée. Ajoutez GEMINI_API_KEY dans .env.local." },
      { status: 503 }
    );
  }

  const body = await request.json().catch(() => null);
  if (!body?.message || typeof body.message !== "string") {
    return NextResponse.json({ error: "Message requis" }, { status: 400 });
  }
  const userMessage = body.message.trim().slice(0, 2000);
  const history: ChatMessage[] = Array.isArray(body.history) ? body.history.slice(-MAX_MESSAGES) : [];

  const now = new Date();
  const ago7 = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
  const ago30 = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);

  const [patient, last, readings7, readings30] = await Promise.all([
    prisma.patient.findUnique({ where: { userId } }),
    prisma.reading.findFirst({ where: { userId }, orderBy: { measuredAt: "desc" } }),
    prisma.reading.findMany({ where: { userId, measuredAt: { gte: ago7 } } }),
    prisma.reading.findMany({ where: { userId, measuredAt: { gte: ago30 } } }),
  ]);

  const avg7 = readings7.length ? readings7.reduce((s, r) => s + r.value, 0) / readings7.length : null;
  const avg30 = readings30.length ? readings30.reduce((s, r) => s + r.value, 0) / readings30.length : null;

  let inRange30 = 0, hypo30 = 0, hyper30 = 0;
  for (const r of readings30) {
    const s = statusFor(r.value, r.moment as Moment);
    if (s === "in-range") inRange30++;
    else if (s === "hypo") hypo30++;
    else hyper30++;
  }

  const systemPrompt = buildSystemPrompt({
    patient,
    stats: {
      count7: readings7.length,
      avg7,
      count30: readings30.length,
      avg30,
      inRangePct30: readings30.length ? (inRange30 / readings30.length) * 100 : null,
      hypo30,
      hyper30,
      hba1c: avg30 ? estimateHbA1c(avg30) : null,
      lastValue: last?.value ?? null,
      lastMoment: last?.moment ?? null,
      lastDate: last ? new Date(last.measuredAt) : null,
    },
  });

  const genAI = new GoogleGenerativeAI(apiKey);
  const modelName = process.env.GEMINI_MODEL ?? "gemini-2.5-flash";
  const model = genAI.getGenerativeModel({ model: modelName, systemInstruction: systemPrompt });

  const geminiHistory = history.map((m) => ({ role: m.role, parts: [{ text: m.content }] }));
  const chat = model.startChat({ history: geminiHistory });

  const stream = new ReadableStream({
    async start(controller) {
      try {
        const result = await chat.sendMessageStream(userMessage);
        for await (const chunk of result.stream) {
          const text = chunk.text();
          if (text) controller.enqueue(new TextEncoder().encode(text));
        }
      } catch (err) {
        const raw = err instanceof Error ? err.message : "Erreur Gemini";
        let friendly = raw;
        if (raw.includes("429") || raw.includes("quota") || raw.includes("Quota")) {
          friendly = "Quota Gemini dépassé. Vérifiez votre plan sur https://ai.dev/rate-limit ou attendez quelques minutes.";
        } else if (raw.includes("403") || raw.includes("API_KEY")) {
          friendly = "Clé API Gemini invalide. Vérifiez GEMINI_API_KEY dans .env.local.";
        } else if (raw.includes("404")) {
          friendly = "Modèle Gemini introuvable. Vérifiez GEMINI_MODEL dans .env.local.";
        }
        controller.enqueue(new TextEncoder().encode(`⚠️ ${friendly}`));
      } finally {
        controller.close();
      }
    },
  });

  return new Response(stream, {
    headers: {
      "Content-Type": "text/plain; charset=utf-8",
      "X-Content-Type-Options": "nosniff",
      "Cache-Control": "no-cache",
    },
  });
}
