import { beforeEach, describe, expect, it, vi } from "vitest";

const { mockOptima, mockCheckPermissions, mockHandleApiError } = vi.hoisted(
  () => ({
    mockOptima: {
      sales: {
        fetchOne: vi.fn(),
        fetchWorkflowStatus: vi.fn(),
        fetchOpportunityTypes: vi.fn(),
      },
    },
    mockCheckPermissions: vi.fn(),
    mockHandleApiError: vi.fn(),
  }),
);

vi.mock("$lib", () => ({ optima: mockOptima }));
vi.mock("$lib/permissions", () => ({
  checkPermissions: mockCheckPermissions,
}));
vi.mock("$lib/optima-api/errorHandler", () => ({
  handleApiError: mockHandleApiError,
}));
// Mock fs/path so we don't write debug files
vi.mock("fs", () => ({
  writeFileSync: vi.fn(),
}));
vi.mock("path", () => ({
  resolve: vi.fn((...args: string[]) => args.join("/")),
}));

import { load } from "./+page.server";

describe("sales/opportunity/[id] +page.server.ts load", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.spyOn(console, "error").mockImplementation(() => {});
    mockOptima.sales.fetchOpportunityTypes.mockResolvedValue({ data: [] });
  });

  it("returns empty data when no token", async () => {
    const result = await load({
      locals: {},
      params: { id: "opp-1" },
    } as any);

    expect(result).toMatchObject({
      opportunity: null,
      notes: [],
      contacts: [],
      products: [],
      quotes: [],
      accessToken: null,
      workflowStatus: null,
    });
  });

  it("loads opportunity with all includes", async () => {
    mockOptima.sales.fetchOne.mockResolvedValueOnce({
      data: {
        id: "opp-1",
        name: "Big Deal",
        notes: [{ id: 1 }],
        contacts: [{ id: "c1" }],
        products: [{ id: "p1" }],
        quotes: [{ id: "q1" }],
      },
    });
    mockCheckPermissions.mockResolvedValueOnce({
      "sales.opportunity.fetch": true,
    });
    mockOptima.sales.fetchWorkflowStatus.mockResolvedValueOnce({
      data: { state: "draft" },
    });

    const result = await load({
      locals: { session: { accessToken: "tok" } },
      params: { id: "opp-1" },
    } as any);

    expect(mockOptima.sales.fetchOne).toHaveBeenCalledWith("tok", "opp-1", [
      "notes",
      "contacts",
      "products",
      "quotes",
    ]);
    expect(result).toMatchObject({
      opportunity: expect.objectContaining({ id: "opp-1" }),
      notes: [{ id: 1 }],
      contacts: [{ id: "c1" }],
      products: [{ id: "p1" }],
      quotes: [{ id: "q1" }],
      accessToken: "tok",
      workflowStatus: { state: "draft" },
    });
  });

  it("handles workflow status fetch failure gracefully", async () => {
    mockOptima.sales.fetchOne.mockResolvedValueOnce({
      data: { id: "opp-1" },
    });
    mockCheckPermissions.mockResolvedValueOnce({});
    mockOptima.sales.fetchWorkflowStatus.mockRejectedValueOnce(
      new Error("fail"),
    );

    const result = await load({
      locals: { session: { accessToken: "tok" } },
      params: { id: "opp-1" },
    } as any);

    expect(result).toMatchObject({
      workflowStatus: null,
    });
  });
});
