import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono";
import { authMiddleware, requireAuth, type AuthVariables } from "../middleware/auth.middleware";
import { scanReceiptSchema } from "@haushaltsApp/shared/schemas/scanner.schema";

type Variables = AuthVariables;

type ClaudeResponse = {
  content: Array<{ type: string; text: string }>;
};

type ReceiptData = {
  amount: number | null;
  label: string | null;
  date: string | null;
};

const CLAUDE_API_URL = "https://api.anthropic.com/v1/messages";
const CLAUDE_MODEL = "claude-haiku-4-5-20251001";
const OCR_PROMPT =
  "Extract from this receipt: total amount, merchant/store name, and date.\n" +
  'Reply ONLY with valid JSON, no other text:\n{"amount": 12.50, "label": "Merchant Name", "date": "2026-03-15"}\n' +
  "Use null for any field you cannot determine with confidence. Date format: YYYY-MM-DD. Amount as decimal number (not string).";

export const scannerRoutes = new Hono<{ Variables: Variables }>();

scannerRoutes.use("/*", authMiddleware, requireAuth);

// POST /receipt — scan a receipt image via Claude Vision
scannerRoutes.post(
  "/receipt",
  zValidator("json", scanReceiptSchema),
  async (c) => {
    const apiKey = process.env.ANTHROPIC_API_KEY;
    if (!apiKey) {
      return c.json({ error: "OCR service not configured" }, 503);
    }

    const { imageBase64, mimeType } = c.req.valid("json");

    const claudeRes = await fetch(CLAUDE_API_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": apiKey,
        "anthropic-version": "2023-06-01",
      },
      body: JSON.stringify({
        model: CLAUDE_MODEL,
        max_tokens: 256,
        messages: [
          {
            role: "user",
            content: [
              {
                type: "image",
                source: {
                  type: "base64",
                  media_type: mimeType,
                  data: imageBase64,
                },
              },
              {
                type: "text",
                text: OCR_PROMPT,
              },
            ],
          },
        ],
      }),
    });

    if (!claudeRes.ok) {
      return c.json({ error: "OCR service error" }, 502);
    }

    const claudeData = (await claudeRes.json()) as ClaudeResponse;
    const textBlock = claudeData.content.find((block) => block.type === "text");
    const rawText = textBlock?.text ?? "";

    // Extract JSON from response — Claude sometimes wraps it in markdown or adds extra text
    const jsonMatch = rawText.match(/\{[\s\S]*\}/);
    if (!jsonMatch) {
      return c.json({ error: "Could not parse receipt" }, 422);
    }

    let parsed: ReceiptData;
    try {
      parsed = JSON.parse(jsonMatch[0]) as ReceiptData;
    } catch {
      return c.json({ error: "Could not parse receipt" }, 422);
    }

    const amount = typeof parsed.amount === "number" ? parsed.amount : null;
    const label = typeof parsed.label === "string" ? parsed.label : null;
    const date = typeof parsed.date === "string" ? parsed.date : null;

    const confidence = [amount, label, date].filter((v) => v !== null).length / 3;

    return c.json({ amount, label, date, confidence });
  },
);
