/**
 * POST /api/palmistry/vision
 *
 * Receives an uploaded palm image, asks GPT-4o vision to describe what it
 * sees, and returns structured JSON the form can pre-fill.
 *
 * Auth: required (uploads cost real money — gate behind login).
 * Quota: 3 vision calls / 24h (anonymous: 0). FREE 3, PREMIUM 20.
 *
 * Output schema (always JSON):
 *   {
 *     ok: true,
 *     fields: {
 *       shape: "earth" | "air" | "fire" | "water" | "unknown",
 *       heart: { length, quality },
 *       head: { length, quality },
 *       life: { length, quality },
 *       fate: { length, quality },
 *       confidence: 0-100,
 *       notes: string
 *     }
 *   }
 *
 * Image handling: accept multipart/form-data with field "image" or
 * application/json with { dataUrl: "data:image/...;base64,..." }.
 * Cap at 4MB to stay under OpenAI's per-message limit.
 */
import { NextRequest } from "next/server";
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { resolvePlan } from "@/lib/billing/plans";
import { prisma } from "@/lib/db";
import { checkScopedQuota } from "@/lib/rate-limit/anonymous";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

const MAX_BYTES = 4 * 1024 * 1024;

type Visioned = {
  shape: "earth" | "air" | "fire" | "water" | "unknown";
  heart: { length: string; quality: string };
  head: { length: string; quality: string };
  life: { length: string; quality: string };
  fate: { length: string; quality: string };
  confidence: number;
  notes: string;
};

const FALLBACK: Visioned = {
  shape: "unknown",
  heart: { length: "unknown", quality: "unknown" },
  head: { length: "unknown", quality: "unknown" },
  life: { length: "unknown", quality: "unknown" },
  fate: { length: "unknown", quality: "unknown" },
  confidence: 0,
  notes: "Không thể phân tích từ ảnh — vui lòng tự đánh giá qua form.",
};

const SYSTEM_PROMPT = `Bạn là một chuyên gia xem chỉ tay (palmistry) đã có 30 năm kinh nghiệm. Bạn nhận một ảnh bàn tay người dùng và phân tích.

Trả về CHỈ một JSON object hợp lệ, không thêm văn bản ngoài JSON, theo schema:
{
  "shape": "earth" | "air" | "fire" | "water" | "unknown",
  "heart": {"length": "long"|"medium"|"short"|"absent"|"unknown", "quality": "clear"|"broken"|"chained"|"forked"|"unknown"},
  "head":  {"length": ..., "quality": ...},
  "life":  {"length": ..., "quality": ...},
  "fate":  {"length": ..., "quality": ...},
  "confidence": 0-100,
  "notes": "1-2 câu mô tả ngắn về ảnh (chiếu sáng, góc chụp, độ rõ)"
}

Quy tắc:
- "shape": Earth = vuông + ngón ngắn (ngón ngắn hơn lòng); Air = vuông + ngón dài; Fire = lòng dài + ngón ngắn; Water = lòng dài + ngón dài.
- "heart": đường ngang trên cùng, gần các ngón nhất.
- "head": đường ngang giữa, dưới đường tim.
- "life": đường cong vòng quanh gốc ngón cái.
- "fate": đường dọc từ cổ tay lên ngón giữa (có thể không có).
- Nếu ảnh quá mờ / sai góc / không phải bàn tay → trả "shape": "unknown" và confidence thấp.
- Tiếng Việt cho "notes". Confidence < 40 nếu không chắc.`;

export async function POST(req: NextRequest) {
  const session = await auth.api.getSession({ headers: await headers() });
  const user = session?.user;
  if (!user) {
    return Response.json(
      { ok: false, error: "Bạn cần đăng nhập để dùng tính năng quét ảnh tay (chi phí AI cao)." },
      { status: 401 }
    );
  }

  // Quota — reuse the AI section anonymous module's logic but as a key prefix
  const userRow = await prisma.user.findUnique({
    where: { id: user.id },
    select: { plan: true },
  });
  const plan = resolvePlan(userRow?.plan);
  // For now: FREE 3/24h palmistry vision, PREMIUM 20/24h. Hardcoded — small budget.
  const dailyLimit = plan.key === "PREMIUM" ? 20 : 3;
  const quota = await checkScopedQuota(req, "palmistry-vision", dailyLimit, {
    userId: user.id,
  }).catch(() => ({ allowed: true, current: 0, limit: dailyLimit }));
  if (!quota.allowed) {
    return Response.json(
      {
        ok: false,
        error: `Bạn đã dùng hết ${dailyLimit} lượt quét ảnh tay trong 24h. Quay lại sau hoặc nâng cấp Premium.`,
      },
      { status: 402 }
    );
  }

  // Parse image
  let dataUrl: string | null = null;
  const contentType = req.headers.get("content-type") || "";
  try {
    if (contentType.includes("multipart/form-data")) {
      const form = await req.formData();
      const file = form.get("image");
      if (file instanceof File) {
        if (file.size > MAX_BYTES) {
          return Response.json(
            { ok: false, error: `Ảnh quá lớn (>${MAX_BYTES / 1024 / 1024}MB).` },
            { status: 413 }
          );
        }
        const buf = Buffer.from(await file.arrayBuffer());
        const mime = file.type || "image/jpeg";
        dataUrl = `data:${mime};base64,${buf.toString("base64")}`;
      }
    } else {
      const body = await req.json();
      if (typeof body?.dataUrl === "string" && body.dataUrl.startsWith("data:image/")) {
        // Soft size check on the base64 payload
        if (body.dataUrl.length > MAX_BYTES * 1.4) {
          return Response.json({ ok: false, error: "Ảnh quá lớn." }, { status: 413 });
        }
        dataUrl = body.dataUrl;
      }
    }
  } catch {
    return Response.json({ ok: false, error: "Không đọc được ảnh." }, { status: 400 });
  }

  if (!dataUrl) {
    return Response.json({ ok: false, error: "Vui lòng đính kèm ảnh bàn tay." }, { status: 400 });
  }

  // Call OpenAI vision (gpt-4o-mini supports vision)
  // Read API key from runtime settings, NOT env — prod uses Setting table.
  const { getSetting } = await import("@/lib/settings");
  const apiKey = (await getSetting("ai.openai_api_key")) || process.env.OPENAI_API_KEY;
  const baseURL = (await getSetting("ai.openai_base_url")) || "https://api.openai.com/v1";
  const visionModel = (await getSetting("ai.openai_model")) || "gpt-4o-mini";
  if (!apiKey || apiKey.startsWith("sk-mock")) {
    return Response.json(
      {
        ok: false,
        error: "Tính năng quét ảnh tay đang được cấu hình. Vui lòng tự điền form bên dưới.",
      },
      { status: 503 }
    );
  }

  try {
    const r = await fetch(`${baseURL}/chat/completions`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        model: visionModel,
        max_tokens: 500,
        temperature: 0.2,
        response_format: { type: "json_object" },
        messages: [
          { role: "system", content: SYSTEM_PROMPT },
          {
            role: "user",
            content: [
              { type: "text", text: "Phân tích bàn tay trong ảnh này. Trả JSON theo schema." },
              { type: "image_url", image_url: { url: dataUrl, detail: "low" } },
            ],
          },
        ],
      }),
    });

    if (!r.ok) {
      const err = await r.text();
      console.error("OpenAI vision error:", r.status, err.slice(0, 200));
      return Response.json(
        { ok: true, fields: FALLBACK, error: "AI không phản hồi — thử lại sau." },
        { status: 200 }
      );
    }

    const json = await r.json();
    const text = json.choices?.[0]?.message?.content;
    let parsed: Visioned;
    try {
      parsed = JSON.parse(text);
    } catch {
      parsed = FALLBACK;
    }

    // Sanitize: ensure all required keys, clamp confidence
    const fields: Visioned = {
      shape: parsed.shape ?? "unknown",
      heart: {
        length: parsed.heart?.length ?? "unknown",
        quality: parsed.heart?.quality ?? "unknown",
      },
      head: {
        length: parsed.head?.length ?? "unknown",
        quality: parsed.head?.quality ?? "unknown",
      },
      life: {
        length: parsed.life?.length ?? "unknown",
        quality: parsed.life?.quality ?? "unknown",
      },
      fate: {
        length: parsed.fate?.length ?? "unknown",
        quality: parsed.fate?.quality ?? "unknown",
      },
      confidence: Math.max(0, Math.min(100, parsed.confidence ?? 0)),
      notes: typeof parsed.notes === "string" ? parsed.notes.slice(0, 500) : "",
    };

    return Response.json({ ok: true, fields });
  } catch (err) {
    console.error("Vision call failed:", err);
    return Response.json(
      { ok: true, fields: FALLBACK, error: "Lỗi gọi AI — thử lại sau." },
      { status: 200 }
    );
  }
}
