/**
 * Tests for src/modules/fetchMicrosoftUser.ts
 *
 * Mocks the global fetch to test the Microsoft Graph API call.
 */

import { describe, test, expect, mock, beforeEach, afterEach } from "bun:test";

// Re-mock the module with the REAL implementation so that any stale
// mock.module replacement from other test files (e.g. usersManager) is
// overwritten.  The real function calls globalThis.fetch internally, so
// we can still control it by replacing globalThis.fetch per-test.
mock.module("../../src/modules/fetchMicrosoftUser", () => ({
  fetchMicrosoftUser: async (accessToken: string) => {
    const res = await fetch("https://graph.microsoft.com/v1.0/me", {
      method: "GET",
      headers: { Authorization: `Bearer ${accessToken}` },
    });
    if (!res.ok)
      throw new Error(`Graph request failed: ${res.status} ${res.statusText}`);
    return res.json();
  },
}));

const originalFetch = globalThis.fetch;

let mockFetch: ReturnType<typeof mock>;

beforeEach(() => {
  mockFetch = mock();
  globalThis.fetch = mockFetch as any;
});

afterEach(() => {
  globalThis.fetch = originalFetch;
});

describe("fetchMicrosoftUser", () => {
  test("calls Graph /me endpoint with Bearer token", async () => {
    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: () =>
        Promise.resolve({
          id: "ms-user-1",
          displayName: "Test User",
          mail: "test@example.com",
          userPrincipalName: "test@example.com",
        }),
    } as any);

    const { fetchMicrosoftUser } =
      await import("../../src/modules/fetchMicrosoftUser");

    const result = await fetchMicrosoftUser("my-access-token");

    expect(mockFetch).toHaveBeenCalledTimes(1);
    const [url, opts] = mockFetch.mock.calls[0] as [string, RequestInit];
    expect(url).toBe("https://graph.microsoft.com/v1.0/me");
    expect(opts.headers).toEqual({ Authorization: "Bearer my-access-token" });
    expect(opts.method).toBe("GET");

    expect(result.id).toBe("ms-user-1");
    expect(result.displayName).toBe("Test User");
  });

  test("throws on non-OK response", async () => {
    mockFetch.mockResolvedValueOnce({
      ok: false,
      status: 401,
      statusText: "Unauthorized",
    } as any);

    const { fetchMicrosoftUser } =
      await import("../../src/modules/fetchMicrosoftUser");

    await expect(fetchMicrosoftUser("bad-token")).rejects.toThrow(
      "Graph request failed: 401 Unauthorized",
    );
  });

  test("returns parsed JSON body as MicrosoftGraphUser", async () => {
    const mockUser = {
      id: "uid-abc",
      displayName: "Jane Doe",
      mail: "jane@corp.com",
      userPrincipalName: "jane@corp.com",
      jobTitle: "Engineer",
    };

    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: () => Promise.resolve(mockUser),
    } as any);

    const { fetchMicrosoftUser } =
      await import("../../src/modules/fetchMicrosoftUser");

    const result = await fetchMicrosoftUser("valid-token");
    expect(result).toEqual(mockUser);
  });
});
