import { beforeEach, describe, expect, mock, test } from "bun:test";
import { buildMockCompany } from "../../setup";

const getMock: any = mock(() => Promise.resolve({ data: [] as any[] }));

mock.module("../../../src/constants", () => ({
  prisma: new Proxy(
    {},
    {
      get() {
        return mock(() => Promise.resolve([]));
      },
    },
  ),
  connectWiseApi: {
    get: getMock,
    post: mock(() => Promise.resolve({ data: {} })),
    put: mock(() => Promise.resolve({ data: {} })),
    patch: mock(() => Promise.resolve({ data: {} })),
    delete: mock(() => Promise.resolve({ data: {} })),
  },
}));

function buildConfig(id: number) {
  return {
    id,
    name: `Config ${id}`,
    activeFlag: true,
    serialNumber: `SN-${id}`,
    type: { id: 9, name: "Firewall" },
    notes: "test notes",
    status: { id: 2, name: "Active" },
    questions: [
      {
        questionId: 11,
        question: "Hostname",
        answer: `host-${id}`,
        fieldType: "Text",
      },
    ],
    _info: { lastUpdated: "2026-03-31T00:00:00Z" },
  };
}

describe("CompanyController.fetchConfigurations", () => {
  beforeEach(() => {
    getMock.mockReset();
  });

  test("fetches and transforms company configurations from ConnectWise", async () => {
    const { CompanyController } = await import(
      "../../../src/controllers/CompanyController"
    );

    getMock.mockImplementation(() => Promise.resolve({ data: [buildConfig(1)] }));

    const controller = new CompanyController(buildMockCompany({ id: 123 }) as any);
    const result = await controller.fetchConfigurations();

    expect(getMock).toHaveBeenCalledTimes(1);
    const requestUrl = String((getMock.mock.calls[0] as any[])?.[0] ?? "");
    expect(requestUrl).toContain(
      "/company/configurations?page=1&pageSize=1000&conditions=company%2Fid%3D123",
    );

    expect(result).toHaveLength(1);
    const first = result[0] as any;
    expect(first.id).toBe(1);
    expect(first.name).toBe("Config 1");
    expect(first.active).toBe(true);
    expect(first.serialNumber).toBe("SN-1");
    expect(first.type?.id).toBe(9);
    expect(first.status?.name).toBe("Active");
    expect(first.questions?.[0]?.question).toBe("Hostname");
  });

  test("paginates when page is full", async () => {
    const { CompanyController } = await import(
      "../../../src/controllers/CompanyController"
    );

    const firstPage = Array.from({ length: 1000 }, (_, i) => buildConfig(i + 1));
    const secondPage = [buildConfig(1001)];

    getMock
      .mockImplementationOnce(() => Promise.resolve({ data: firstPage }))
      .mockImplementationOnce(() => Promise.resolve({ data: secondPage }));

    const controller = new CompanyController(buildMockCompany({ id: 456 }) as any);
    const result = await controller.fetchConfigurations();

    expect(getMock).toHaveBeenCalledTimes(2);
    const firstUrl = String((getMock.mock.calls[0] as any[])?.[0] ?? "");
    const secondUrl = String((getMock.mock.calls[1] as any[])?.[0] ?? "");
    expect(firstUrl).toContain("page=1");
    expect(secondUrl).toContain("page=2");
    expect(result).toHaveLength(1001);
  });

  test("throws GenericError when CW request fails", async () => {
    const { CompanyController } = await import(
      "../../../src/controllers/CompanyController"
    );

    const err: any = new Error("Unauthorized");
    err.isAxiosError = true;
    err.response = {
      status: 401,
      data: { message: "Unauthorized" },
      statusText: "Unauthorized",
    };

    getMock.mockImplementation(() => Promise.reject(err));

    const controller = new CompanyController(buildMockCompany({ id: 321 }) as any);

    try {
      await controller.fetchConfigurations();
      expect(true).toBe(false);
    } catch (error: any) {
      expect(error.name).toBe("ConnectWiseFetchFailed");
      expect(error.status).toBe(401);
      expect(error.message).toBe(
        "Failed to fetch company configurations from ConnectWise",
      );
      expect(error.cause).toBe("Unauthorized");
    }
  });
});
