import { describe, it, expect, vi } from "vitest";
import { PDFDocument } from "pdf-lib";
import { pdfWatermarkPlugin, type PdfWatermarkOptions } from "./index";
import { runPdfWatermark } from "./run";
import { MAX_WATERMARK_CHARS } from "./watermark";
import type { ToolContext } from "../../core/plugins/plugin-types";

const mockContext: ToolContext = {
  signal: new AbortController().signal,
  reportProgress: vi.fn(),
  logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
};

const defaultOptions: PdfWatermarkOptions = {
  text: "CONFIDENTIAL",
  orientation: "diagonal",
  opacity: 30,
  color: "light-grey",
};

async function makePdfFile(): Promise<File> {
  const doc = await PDFDocument.create();
  doc.addPage([595, 842]);
  const bytes = await doc.save();
  return new File([bytes as unknown as BlobPart], "sample.pdf", {
    type: "application/pdf",
  });
}

describe("PDF Watermark Plugin", () => {
  it("should have correct manifest", () => {
    expect(pdfWatermarkPlugin.manifest.id).toBe("pdf-watermark");
    expect(pdfWatermarkPlugin.manifest.category).toBe("pdf");
    expect(pdfWatermarkPlugin.manifest.input.type).toBe("files");
    expect(pdfWatermarkPlugin.manifest.output.type).toBe("files");
  });

  it("should throw if no file provided", async () => {
    await expect(
      runPdfWatermark({ files: [] }, defaultOptions, mockContext)
    ).rejects.toThrow("No PDF file provided.");
  });

  it("should throw if watermark text is empty", async () => {
    const file = await makePdfFile();
    await expect(
      runPdfWatermark({ files: [file] }, { ...defaultOptions, text: "  " }, mockContext)
    ).rejects.toThrow("Watermark text is required.");
  });

  it("should produce a watermarked PDF", async () => {
    const file = await makePdfFile();
    const result = await runPdfWatermark(
      { files: [file] },
      defaultOptions,
      mockContext
    );

    expect(result.type).toBe("files");
    if (result.type !== "files") throw new Error("unexpected result");
    expect(result.files).toHaveLength(1);
    expect(result.files[0].name).toBe("sample_watermarked.pdf");
    expect(result.files[0].mimeType).toBe("application/pdf");
    expect(result.files[0].blob.size).toBeGreaterThan(0);

    // Output should still be a loadable PDF with the same page count.
    const out = await result.files[0].blob.arrayBuffer();
    const reloaded = await PDFDocument.load(new Uint8Array(out));
    expect(reloaded.getPageCount()).toBe(1);
  });

  it.each(["horizontal", "vertical", "diagonal"] as const)(
    "should handle %s orientation",
    async (orientation) => {
      const file = await makePdfFile();
      const result = await runPdfWatermark(
        { files: [file] },
        { ...defaultOptions, orientation },
        mockContext
      );
      expect(result.type).toBe("files");
    }
  );

  it("should truncate text beyond the max length", async () => {
    const file = await makePdfFile();
    const longText = "A".repeat(MAX_WATERMARK_CHARS + 50);
    const result = await runPdfWatermark(
      { files: [file] },
      { ...defaultOptions, text: longText },
      mockContext
    );
    expect(result.type).toBe("files");
  });
});
