import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";

const inputSchema = z.object({
  imageBase64: z.string().min(50).max(12_000_000),
  mimeType: z.string().min(3).max(100),
});

export type HasilBacaBukti = {
  ok: boolean;
  pesan?: string;
  nominal?: number | null;
  tanggal?: string | null;
  merchant?: string | null;
  jenis?: "pemasukan" | "pengeluaran" | null;
  catatan?: string | null;
};

export const bacaBukti = createServerFn({ method: "POST" })
  .inputValidator((data: unknown) => inputSchema.parse(data))
  .handler(async ({ data }): Promise<HasilBacaBukti> => {
    const apiKey = process.env["LOVABLE_API_KEY"];
    if (!apiKey) return { ok: false, pesan: "Layanan AI belum tersedia." };

    const res = await fetch("https://ai.gateway.lovable.dev/v1/chat/completions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "google/gemini-2.5-flash",
        messages: [
          {
            role: "system",
            content:
              "Kamu membaca struk, invoice, atau bukti transfer Indonesia. Balas HANYA JSON valid tanpa markdown, format: {\"terbaca\":boolean,\"nominal\":number|null,\"tanggal\":\"YYYY-MM-DD\"|null,\"merchant\":string|null,\"jenis\":\"pemasukan\"|\"pengeluaran\"|null,\"catatan\":string|null}. Nominal dalam angka rupiah tanpa titik. Jika gambar tidak terbaca atau bukan bukti transaksi, set terbaca=false.",
          },
          {
            role: "user",
            content: [
              { type: "text", text: "Ekstrak informasi transaksi dari gambar bukti ini." },
              { type: "image_url", image_url: { url: `data:${data.mimeType};base64,${data.imageBase64}` } },
            ],
          },
        ],
      }),
    });

    if (res.status === 429) return { ok: false, pesan: "Terlalu banyak permintaan, coba lagi sebentar lagi." };
    if (res.status === 402) return { ok: false, pesan: "Kuota AI habis. Silakan isi ulang kredit." };
    if (!res.ok) return { ok: false, pesan: "Gagal membaca bukti. Isi manual saja." };

    const json = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> };
    const raw = json.choices?.[0]?.message?.content ?? "";
    const match = raw.match(/\{[\s\S]*\}/);
    if (!match) return { ok: false, pesan: "Hasil tidak terbaca. Silakan isi manual." };

    let parsed: Record<string, unknown>;
    try {
      parsed = JSON.parse(match[0]) as Record<string, unknown>;
    } catch {
      return { ok: false, pesan: "Hasil tidak terbaca. Silakan isi manual." };
    }

    if (parsed["terbaca"] === false) {
      return { ok: false, pesan: "Bukti tidak terbaca jelas. Silakan isi manual." };
    }

    const nominalRaw = parsed["nominal"];
    const nominal =
      typeof nominalRaw === "number"
        ? Math.round(nominalRaw)
        : typeof nominalRaw === "string"
          ? Number(nominalRaw.replace(/[^\d]/g, "")) || null
          : null;
    const str = (v: unknown) => (typeof v === "string" && v.trim() ? v.trim().slice(0, 200) : null);
    const tanggal = str(parsed["tanggal"]);
    const jenisRaw = str(parsed["jenis"]);

    if (!nominal && !tanggal && !str(parsed["merchant"])) {
      return { ok: false, pesan: "Tidak ada informasi yang bisa diambil. Silakan isi manual." };
    }

    return {
      ok: true,
      nominal,
      tanggal: tanggal && /^\d{4}-\d{2}-\d{2}$/.test(tanggal) ? tanggal : null,
      merchant: str(parsed["merchant"]),
      jenis: jenisRaw === "pemasukan" || jenisRaw === "pengeluaran" ? jenisRaw : null,
      catatan: str(parsed["catatan"]),
    };
  });
