import { describe, expect, it, vi } from "vitest";
import { analyzePdf } from "@/lib/pdf/analyzePdf";
import { PdfUnreadableError } from "@/lib/pdf/errors";

describe("analyzePdf", () => {
  it("returns direct method for PDFs with enough extracted text", async () => {
    const extractMock = vi.fn(async () => ({ text: "texto ".repeat(50), numPages: 2 }));
    const ocrMock = vi.fn(async () => undefined);

    const result = await analyzePdf(Buffer.from("pdf"), {
      deps: {
        extractTextFromPdfBuffer: extractMock,
        ocrPdfToSearchablePdf: ocrMock,
      },
    });

    expect(result.methodUsed).toBe("direct");
    expect(result.text.length).toBeGreaterThan(0);
    expect(ocrMock).not.toHaveBeenCalled();
  });

  it("uses OCR fallback when direct extraction is too short", async () => {
    const extractMock = vi
      .fn()
      .mockResolvedValueOnce({ text: "", numPages: 1 })
      .mockResolvedValueOnce({ text: "texto recuperado por ocr ".repeat(16), numPages: 1 });

    const ocrMock = vi.fn(async () => undefined);
    const readFileMock = vi.fn(async () => Buffer.from("pdf-ocr"));
    const unlinkMock = vi.fn(async () => undefined);

    const result = await analyzePdf(Buffer.from("pdf"), {
      deps: {
        extractTextFromPdfBuffer: extractMock,
        ocrPdfToSearchablePdf: ocrMock,
        writePdfBufferToTempFile: async () => "/tmp/input.pdf",
        createTempPdfPath: () => "/tmp/output.ocr.pdf",
        readFile: readFileMock,
        unlink: unlinkMock,
      },
    });

    expect(result.methodUsed).toBe("ocr");
    expect(result.text.length).toBeGreaterThan(0);
    expect(ocrMock).toHaveBeenCalledWith("/tmp/input.pdf", "/tmp/output.ocr.pdf", "spa+eng");
    expect(readFileMock).toHaveBeenCalledWith("/tmp/output.ocr.pdf");
    expect(unlinkMock).toHaveBeenCalledTimes(2);
  });

  it("uses OCR fallback when direct extraction throws", async () => {
    const extractMock = vi
      .fn()
      .mockRejectedValueOnce(new Error("direct parse failed"))
      .mockResolvedValueOnce({ text: "texto recuperado por ocr ".repeat(16), numPages: 1 });

    const ocrMock = vi.fn(async () => undefined);

    const result = await analyzePdf(Buffer.from("pdf"), {
      deps: {
        extractTextFromPdfBuffer: extractMock,
        ocrPdfToSearchablePdf: ocrMock,
        writePdfBufferToTempFile: async () => "/tmp/input.pdf",
        createTempPdfPath: () => "/tmp/output.ocr.pdf",
        readFile: async () => Buffer.from("pdf-ocr"),
        unlink: async () => undefined,
      },
    });

    expect(result.methodUsed).toBe("ocr");
    expect(result.warnings.some((warning) => warning.includes("extraccion directa fallo"))).toBe(true);
    expect(ocrMock).toHaveBeenCalledTimes(1);
  });

  it("uses pdftotext fallback when OCR output is unreadable for pdf parser", async () => {
    const extractMock = vi
      .fn()
      .mockResolvedValueOnce({ text: "", numPages: 1 })
      .mockRejectedValueOnce(new PdfUnreadableError("cannot parse ocr pdf"));

    const result = await analyzePdf(Buffer.from("pdf"), {
      deps: {
        extractTextFromPdfBuffer: extractMock,
        ocrPdfToSearchablePdf: async () => undefined,
        writePdfBufferToTempFile: async () => "/tmp/input.pdf",
        createTempPdfPath: () => "/tmp/output.ocr.pdf",
        readFile: async () => Buffer.from("pdf-ocr"),
        unlink: async () => undefined,
        extractTextWithPdftotext: async () => "texto recuperado via pdftotext ".repeat(12),
        getPdfPageCountWithPdfinfo: async () => 1,
      },
    });

    expect(result.methodUsed).toBe("ocr");
    expect(result.warnings.some((warning) => warning.includes("pdftotext"))).toBe(true);
  });
});
