import { describe, it, expect, vi, beforeEach } from "vitest";
import { createPdfViewerManager } from "./pdf-viewer-manager";
import { pdfViwerEvents } from "./events";
import { registerPdfViewerNavItem } from "./handle-views";
import { showNavItemTooltip } from "../../UI/components/navigation-tooltip";

vi.mock("@primaria/plugins-core", () => ({
  generateId: () => "generated-id",
}));

vi.mock("./handle-views", () => ({
  registerPdfViewerNavItem: vi.fn(),
}));

vi.mock("../../locales", () => ({
  translate: (key: string) => key,
}));

vi.mock("../../UI/components/navigation-tooltip", () => ({
  showNavItemTooltip: vi.fn(),
}));

describe("PdfViewerManager", () => {
  let manager: ReturnType<typeof createPdfViewerManager>;
  let broker: any;
  let notificationService: any;

  beforeEach(() => {
    broker = {
      publish: vi.fn(),
    };

    notificationService = {
      error: vi.fn(),
      warning: vi.fn(),
      success: vi.fn(),
    };

    vi.clearAllMocks();

    manager = createPdfViewerManager(broker, notificationService);
  });

  it("should show error if neither url nor b64 is provided", () => {
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00" });
    expect(notificationService.error).toHaveBeenCalledWith("pdfManager.missingData");
    expect(manager.getPdfs()).toHaveLength(0);
  });

  it("should show error if both url and b64 are provided", () => {
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", url: "url", b64: "b64" });
    expect(notificationService.error).toHaveBeenCalledWith("pdfManager.duplicatedSource");
    expect(manager.getPdfs()).toHaveLength(0);
  });

  it("should add a valid pdf and publish event", () => {
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", url: "https://test.com/doc1.pdf" });

    expect(manager.getPdfs()).toHaveLength(1);
    expect(broker.publish).toHaveBeenCalledWith(pdfViwerEvents.added, {
      id: "doc-1",
      pdfName: "Doc1",
      data: { id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", url: "https://test.com/doc1.pdf" },
    });
  });

  it("should show tooltip when adding a valid pdf", async () => {
    vi.useFakeTimers();

    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", url: "https://test.com/doc1.pdf" });

    // Fast-forward the setTimeout(100ms)
    vi.advanceTimersByTime(100);

    expect(showNavItemTooltip).toHaveBeenCalledWith(
      "primaria-shell::pdf-viewer",
      "pdfManager.tooltipMessage"
    );

    vi.useRealTimers();
  });

  it("should warn if pdf with same name already exists", () => {
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", b64: "xxx" });
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", b64: "xxx" });

    expect(notificationService.warning).toHaveBeenCalledWith("pdfManager.alreadyUploaded");
    expect(manager.getPdfs()).toHaveLength(1); // solo el primero
  });

  it("should not show tooltip when pdf with same name already exists", () => {
    vi.useFakeTimers();

    // First add succeeds and shows tooltip
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", b64: "xxx" });
    vi.advanceTimersByTime(100);

    // Clear mocks after first add
    vi.clearAllMocks();

    // Second add with same name should show warning but NOT tooltip
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", b64: "xxx" });
    vi.advanceTimersByTime(100);

    expect(notificationService.warning).toHaveBeenCalledWith("pdfManager.alreadyUploaded");
    expect(showNavItemTooltip).not.toHaveBeenCalled();

    vi.useRealTimers();
  });

  it("should not show tooltip when pdf data is invalid", () => {
    vi.useFakeTimers();

    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00" });
    vi.advanceTimersByTime(100);

    expect(notificationService.error).toHaveBeenCalledWith("pdfManager.missingData");
    expect(showNavItemTooltip).not.toHaveBeenCalled();

    vi.useRealTimers();
  });

  it("should not call registerNavButton when adding PDFs", () => {
    // registerPdfViewerNavItem is now called from UI/internal-views, not from the manager
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", url: "u" });
    manager.add({ id: "doc-2", name: "Doc2", date: "2024-01-15 - 10:00", url: "u2" });

    expect(registerPdfViewerNavItem).not.toHaveBeenCalled();
  });

  it("should delete a pdf and publish deletion event", () => {
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", url: "u" });
    const pdfs = manager.getPdfs();
    expect(pdfs.length).toBeGreaterThan(0);
    const id = pdfs[0]!.id;

    manager.delete(id);

    expect(manager.getPdfs()).toHaveLength(0);
    expect(broker.publish).toHaveBeenCalledWith(pdfViwerEvents.deleted, { id });
  });

  it("should clear activePdf if deleted", () => {
    manager.add({ id: "doc-1", name: "Doc1", date: "2024-01-15 - 10:00", url: "u" });
    const pdfs = manager.getPdfs();
    expect(pdfs.length).toBeGreaterThan(0);
    const id = pdfs[0]!.id;

    // simula que esté activo
    (manager as any).activePdf = { id } as any;

    manager.delete(id);

    expect((manager as any).activePdf).toBeNull();
  });
});
