// @vitest-environment happy-dom
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook, act, waitFor } from "@testing-library/react";

vi.mock("./api", () => ({
  authApi: {
    me: vi.fn(),
    login: vi.fn(),
    logout: vi.fn(),
  },
}));

import { authApi } from "./api";
import { AuthProvider, useAuth } from "./AuthProvider";

const wrapper = ({ children }: { children: React.ReactNode }) => (
  <AuthProvider>{children}</AuthProvider>
);

describe("AuthProvider", () => {
  beforeEach(() => {
    vi.resetAllMocks();
  });

  it("loads user on mount", async () => {
    (authApi.me as unknown as ReturnType<typeof vi.fn>).mockResolvedValue({
      id: 1,
      username: "alice",
      role: "user",
    });
    const { result } = renderHook(() => useAuth(), { wrapper });
    await waitFor(() => expect(result.current.status).toBe("authenticated"));
    expect(result.current.user?.username).toBe("alice");
  });

  it("status is unauthenticated when /me fails", async () => {
    (authApi.me as unknown as ReturnType<typeof vi.fn>).mockRejectedValue(
      new Error("401")
    );
    const { result } = renderHook(() => useAuth(), { wrapper });
    await waitFor(() => expect(result.current.status).toBe("unauthenticated"));
    expect(result.current.user).toBeNull();
  });

  it("login() updates state on success", async () => {
    (authApi.me as unknown as ReturnType<typeof vi.fn>).mockRejectedValue(
      new Error("401")
    );
    (
      authApi.login as unknown as ReturnType<typeof vi.fn>
    ).mockResolvedValue({ id: 1, username: "alice", role: "admin" });
    const { result } = renderHook(() => useAuth(), { wrapper });
    await waitFor(() => expect(result.current.status).toBe("unauthenticated"));
    await act(async () => {
      await result.current.login("alice", "pw");
    });
    expect(result.current.user?.username).toBe("alice");
    expect(result.current.status).toBe("authenticated");
  });

  it("logout() clears state", async () => {
    (authApi.me as unknown as ReturnType<typeof vi.fn>).mockResolvedValue({
      id: 1,
      username: "alice",
      role: "user",
    });
    (
      authApi.logout as unknown as ReturnType<typeof vi.fn>
    ).mockResolvedValue(undefined);
    const { result } = renderHook(() => useAuth(), { wrapper });
    await waitFor(() => expect(result.current.status).toBe("authenticated"));
    await act(async () => {
      await result.current.logout();
    });
    expect(result.current.user).toBeNull();
    expect(result.current.status).toBe("unauthenticated");
  });
});
