/**
 * POST /api/charts/[chartId]/qa
 *
 * Q&A theo lá số đã lưu — streaming SSE, persist conversation + messages vào DB.
 *
 * Auth: chỉ owner (chart.userId == session.user.id) mới chat được.
 * Quota: FREE 20 messages / 24h, PREMIUM unlimited (per existing billing config).
 *
 * Body: {
 *   question: string,
 *   conversationId?: string  // resume existing thread, omit để tạo mới
 * }
 *
 * SSE events:
 *   data: {"type":"meta","conversationId":"...","plan":"FREE|PREMIUM"}
 *   data: {"type":"token","content":"..."}
 *   data: {"type":"done","tokensUsed":N}
 *   data: {"type":"error","message":"..."}
 */

import { NextRequest } from "next/server";
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/db";
import { renderStoredChart } from "@/lib/charts";
import { getProvider } from "@/lib/ai/provider";
import { resolvePlan, withinLimit } from "@/lib/billing/plans";
import { countAiChatMessagesLast24h } from "@/lib/billing/usage";

export const runtime = "nodejs";

function sseEvent(payload: Record<string, unknown>): string {
  return `data: ${JSON.stringify(payload)}\n\n`;
}

type Body = {
  question?: string;
  conversationId?: string;
};

export async function POST(req: NextRequest, { params }: { params: Promise<{ chartId: string }> }) {
  const { chartId } = await params;

  // 1. Auth
  const session = await auth.api.getSession({ headers: await headers() });
  if (!session) {
    return new Response(JSON.stringify({ error: "Bạn cần đăng nhập để hỏi AI." }), {
      status: 401,
      headers: { "Content-Type": "application/json" },
    });
  }
  const userId = session.user.id;

  // 2. Parse + validate body
  let body: Body;
  try {
    body = (await req.json()) as Body;
  } catch {
    return new Response(JSON.stringify({ error: "JSON không hợp lệ" }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  const question = body.question?.trim() ?? "";
  if (question.length < 2 || question.length > 500) {
    return new Response(JSON.stringify({ error: "Câu hỏi phải dài 2-500 ký tự." }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  // 3. Load chart + verify ownership
  const stored = await prisma.chart.findFirst({
    where: { id: chartId, userId },
    select: {
      id: true,
      label: true,
      fullName: true,
      birthDate: true,
      birthTime: true,
      gender: true,
      isLunar: true,
      shareToken: true,
      isDefault: true,
      createdAt: true,
      updatedAt: true,
    },
  });
  if (!stored) {
    return new Response(
      JSON.stringify({ error: "Lá số không tồn tại hoặc bạn không có quyền truy cập." }),
      { status: 404, headers: { "Content-Type": "application/json" } }
    );
  }

  // 4. Quota
  const userRow = await prisma.user.findUnique({
    where: { id: userId },
    select: { plan: true },
  });
  const plan = resolvePlan(userRow?.plan);
  const usageCount = await countAiChatMessagesLast24h(userId);
  if (!withinLimit(usageCount, plan.limits.aiChatMessagesPerDay)) {
    return new Response(
      JSON.stringify({
        error: `Bạn đã đạt giới hạn ${plan.limits.aiChatMessagesPerDay} tin nhắn AI / 24h cho gói ${plan.key}. Nâng cấp Premium để hỏi không giới hạn.`,
        upgrade: true,
      }),
      { status: 402, headers: { "Content-Type": "application/json" } }
    );
  }

  // 5. Build chart for AI context
  let chart;
  try {
    chart = renderStoredChart(stored);
  } catch (e) {
    return new Response(
      JSON.stringify({ error: e instanceof Error ? e.message : "Không an được lá số." }),
      { status: 500, headers: { "Content-Type": "application/json" } }
    );
  }

  // 6. Resolve or create conversation
  let conversationId = body.conversationId;
  if (conversationId) {
    const existing = await prisma.aIConversation.findFirst({
      where: { id: conversationId, userId, chartId },
      select: { id: true },
    });
    if (!existing) conversationId = undefined;
  }

  if (!conversationId) {
    const titleSeed = question.length > 60 ? question.slice(0, 57) + "..." : question;
    const created = await prisma.aIConversation.create({
      data: {
        userId,
        chartId,
        toolKey: "tu-vi-qa",
        title: titleSeed,
      },
      select: { id: true },
    });
    conversationId = created.id;
  }

  // 7. Load conversation history (last 10 messages)
  const priorMessages = await prisma.aIMessage.findMany({
    where: { conversationId },
    orderBy: { createdAt: "asc" },
    take: 20,
    select: { role: true, content: true },
  });

  const history = priorMessages.map((m) => ({
    role: m.role as "system" | "user" | "assistant",
    content: m.content,
  }));

  // 8. Persist user message
  await prisma.aIMessage.create({
    data: {
      conversationId,
      role: "user",
      content: question,
    },
  });

  // 9. Stream AI response + persist when done
  const provider = await getProvider();
  const encoder = new TextEncoder();

  const stream = new ReadableStream<Uint8Array>({
    async start(controller) {
      controller.enqueue(
        encoder.encode(
          sseEvent({
            type: "meta",
            conversationId,
            plan: plan.key,
            provider: provider.name,
          })
        )
      );

      let fullText = "";
      try {
        for await (const chunk of provider.stream({
          chart,
          question,
          history,
        })) {
          fullText += chunk;
          controller.enqueue(encoder.encode(sseEvent({ type: "token", content: chunk })));
        }

        // Persist assistant message + bump conversation timestamp
        await prisma.aIMessage.create({
          data: {
            conversationId: conversationId!,
            role: "assistant",
            content: fullText,
          },
        });
        await prisma.aIConversation.update({
          where: { id: conversationId! },
          data: { updatedAt: new Date() },
        });

        controller.enqueue(encoder.encode(sseEvent({ type: "done", tokens: fullText.length })));
      } catch (e) {
        const msg = e instanceof Error ? e.message : "AI provider failed";
        controller.enqueue(encoder.encode(sseEvent({ type: "error", message: msg })));
      } finally {
        controller.close();
      }
    },
  });

  return new Response(stream, {
    headers: {
      "Content-Type": "text/event-stream; charset=utf-8",
      "Cache-Control": "no-cache, no-transform",
      Connection: "keep-alive",
      "X-Accel-Buffering": "no",
    },
  });
}
