import { describe, it, expect, beforeAll } from "vitest";
import { readFileSync } from "fs";
import { resolve } from "path";
import { queryRaw } from "../../lib/db";

/**
 * The HTTP path had no tests at all — which is how three defects reached the
 * branch through a suite of 105 green ones. These exercise the route handler
 * directly (no server needed) so the auth gate and the error taxonomy are
 * actually covered.
 */
const dir = resolve(__dirname, "../fixtures/orders/real");
const html = (f: string) => readFileSync(resolve(dir, `${f}.html`), "utf-8");

const TOKEN = "test-ingest-token";
let POST: any;

const req = (body: unknown, token: string | null = TOKEN) =>
  ({
    headers: { get: (h: string) => (h === "x-ingest-token" ? token : null) },
    json: async () => body,
  }) as any;

beforeAll(async () => {
  process.env.ORDER_INGEST_TOKEN = TOKEN;
  ({ POST } = await import("../../app/api/orders/ingest/route"));
});

describe("ingest API — auth", () => {
  it("rejects a missing token", async () => {
    const res = await POST(req({ html: "x", meta: {} }, null));
    expect(res.status).toBe(401);
  });

  it("rejects a wrong token", async () => {
    const res = await POST(req({ html: "x", meta: {} }, "nope"));
    expect(res.status).toBe(401);
  });

  it("rejects a malformed body", async () => {
    const res = await POST(req({ html: "only html" }));
    expect(res.status).toBe(400);
  });
});

describe("ingest API — error taxonomy", () => {
  const meta = (over = {}) => ({
    messageId: `api-${Math.random().toString(36).slice(2)}`,
    subject: "Order Confirmation for Siddharth from Mad Mex",
    receivedAt: "2026-07-16T03:34:00Z",
    sender: "DoorDash Order <no-reply@doordash.com>",
    ...over,
  });

  it("a non-receipt is 200 and silent — it must not alert", async () => {
    // A newsletter: real traffic, correctly ignored.
    const res = await POST(req({ html: html("dd-01"), meta: meta({ subject: "Newsletter", sender: "promo@example.com" }) }));
    expect(res.status).toBe(200);
    expect((await res.json()).kind).toBe("skipped");
  });

  it("an adjustment notice is 200 and silent", async () => {
    const res = await POST(req({
      html: html("dd-08"),
      meta: meta({ subject: "Order Confirmation for Siddharth from ALDI" }),
    }));
    expect(res.status).toBe(200);
    expect((await res.json()).kind).toBe("skipped");
  });

  it("a receipt that cannot be parsed is 422 so it ALERTS", async () => {
    // A DoorDash receipt with its totals stripped out — i.e. what a provider
    // template change looks like. Previously this returned 200 and vanished.
    const broken = html("dd-01")
      .replace(/Total Charged/g, "Gesamtbetrag")
      .replace(/Total:/g, "Summe:");
    const res = await POST(req({ html: broken, meta: meta() }));
    expect(res.status).toBe(422);
    const body = await res.json();
    expect(body.kind).toBe("parse_failed");
    expect(body.reason).toMatch(/total/i);
  });

  it("a refund is routed to the amendment path, not ingestion", async () => {
    const res = await POST(req({
      html: html("ue-05"),
      meta: meta({ subject: "Your Tuesday evening order with Uber Eats", sender: "uber.com" }),
      dryRun: true,
    }));
    expect(res.status).toBe(200);
    const body = await res.json();
    expect(body.kind).toBe("amendment");
    expect(body.amendment.new_total).toBeCloseTo(45.73, 2);
  });

  it("a good receipt ingests", async () => {
    await queryRaw(`DELETE FROM expense_metadata WHERE source = 'email'`);
    await queryRaw(`DELETE FROM transactions WHERE description LIKE 'Order - %'`);
    const res = await POST(req({ html: html("dd-01"), meta: meta({ messageId: "api-ok-1" }) }));
    expect(res.status).toBe(200);
    const body = await res.json();
    expect(body.kind).toBe("order");
    expect(body.total).toBe(14.64);
    expect(body.transactionId).not.toBeNull();
  });
});
