/**
 * Integration tests for POST /api/po/import.
 * Tests authorization guards and end-to-end parsing of the Sample_PO.xlsx
 * fixture using the real route handler.
 */
import { vi, describe, it, expect, beforeAll, beforeEach } from "vitest";

vi.mock("@/auth", () => ({ auth: vi.fn() }));

import { auth } from "@/auth";
import { readFileSync } from "fs";
import { resolve } from "path";
import { NextRequest } from "next/server";
import { POST } from "@/app/api/po/import/route";
import { makeSession, getSeedUser } from "./helpers";
import type { ParsedImport } from "@/lib/po-import-parser";

const SAMPLE_XLSX = resolve(__dirname, "../fixtures/Sample_PO.xlsx");

let techId: string;
let managerId: string;
let accountsId: string;

beforeAll(async () => {
  const [tech, mgr, acct] = await Promise.all([
    getSeedUser("tech@pelagia.local"),
    getSeedUser("manager@pelagia.local"),
    getSeedUser("accounts@pelagia.local"),
  ]);
  techId = tech.id;
  managerId = mgr.id;
  accountsId = acct.id;
});

function makeFileRequest(filePath?: string) {
  const formData = new FormData();
  if (filePath) {
    const buffer = readFileSync(filePath);
    const file = new File(
      [buffer],
      "import.xlsx",
      { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }
    );
    formData.append("file", file);
  }
  return new NextRequest("http://localhost/api/po/import", { method: "POST", body: formData });
}

// ── Authorization ─────────────────────────────────────────────────────────────

describe("POST /api/po/import — authorization", () => {
  it("returns 401 for unauthenticated requests", async () => {
    vi.mocked(auth as unknown as () => Promise<unknown>).mockResolvedValue(null);
    const res = await POST(makeFileRequest(SAMPLE_XLSX));
    expect(res.status).toBe(401);
  });

  it("returns 403 for TECHNICAL role", async () => {
    vi.mocked(auth as unknown as () => Promise<unknown>).mockResolvedValue(makeSession(techId, "TECHNICAL"));
    const res = await POST(makeFileRequest(SAMPLE_XLSX));
    expect(res.status).toBe(403);
    const data = await res.json();
    expect(data.error).toMatch(/forbidden/i);
  });

  it("returns 403 for ACCOUNTS role", async () => {
    vi.mocked(auth as unknown as () => Promise<unknown>).mockResolvedValue(makeSession(accountsId, "ACCOUNTS"));
    const res = await POST(makeFileRequest(SAMPLE_XLSX));
    expect(res.status).toBe(403);
  });

  it("returns 200 for MANAGER role with valid file", async () => {
    vi.mocked(auth as unknown as () => Promise<unknown>).mockResolvedValue(makeSession(managerId, "MANAGER"));
    const res = await POST(makeFileRequest(SAMPLE_XLSX));
    expect(res.status).toBe(200);
  });
});

// ── Input validation ──────────────────────────────────────────────────────────

describe("POST /api/po/import — input validation", () => {
  beforeEach(() => {
    vi.mocked(auth as unknown as () => Promise<unknown>).mockResolvedValue(makeSession(managerId, "MANAGER"));
  });

  it("returns 400 when no file is provided", async () => {
    const res = await POST(makeFileRequest());
    expect(res.status).toBe(400);
    const data = await res.json();
    expect(data.error).toBeDefined();
  });

  it("returns 400 for a non-XLSX binary file", async () => {
    const formData = new FormData();
    const garbage = new File([Buffer.from("not-an-xlsx")], "bad.xlsx", { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
    formData.append("file", garbage);
    const req = new NextRequest("http://localhost/api/po/import", { method: "POST", body: formData });
    const res = await POST(req);
    expect(res.status).toBe(400);
  });
});

// ── Parsing results ───────────────────────────────────────────────────────────

describe("POST /api/po/import — parsing Sample_PO.xlsx", () => {
  let results: ParsedImport[];

  beforeAll(async () => {
    vi.mocked(auth as unknown as () => Promise<unknown>).mockResolvedValue(makeSession(managerId, "MANAGER"));
    const res = await POST(makeFileRequest(SAMPLE_XLSX));
    const data = await res.json();
    results = data.results;
  });

  it("returns exactly one result (one sheet with PO data)", () => {
    expect(results).toHaveLength(1);
  });

  it("extracted line items contain no T&C rows", () => {
    const items = results[0].lineItems;
    const hasTcText = items.some(
      (li) =>
        li.name.toLowerCase().includes("please quote") ||
        li.name.toLowerCase().includes("delivery :") ||
        li.name.toLowerCase().includes("payment terms")
    );
    expect(hasTcText).toBe(false);
  });

  it("extracted exactly one line item", () => {
    expect(results[0].lineItems).toHaveLength(1);
  });

  it("line item has correct description", () => {
    expect(results[0].lineItems[0].name).toBe("Eni EP 80W90 GEAR OIL");
  });

  it("line item has correct quantity (1050)", () => {
    expect(results[0].lineItems[0].quantity).toBe(1050);
  });

  it("line item has correct unit price (182)", () => {
    expect(results[0].lineItems[0].unitPrice).toBe(182);
  });

  it("line item has GST rate 0.18", () => {
    expect(results[0].lineItems[0].gstRate).toBeCloseTo(0.18);
  });

  it("vendor name extracted correctly", () => {
    expect(results[0].vendorName).toBe("Apar Industries Ltd");
  });

  it("PI quotation number extracted", () => {
    expect(results[0].piQuotationNo).toBe("Verbal");
  });

  it("delivery T&C stripped of prefix", () => {
    expect(results[0].tcDelivery).not.toMatch(/^DELIVERY\s*:/i);
    expect(results[0].tcDelivery).toMatch(/4 to 5 days/i);
  });
});
