import { render, screen, waitFor } from "@testing-library/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { ApiError } from "./api";
import { RequireKind } from "./session";

const replace = vi.fn();
vi.mock("next/navigation", () => ({
    useRouter: () => ({ replace, push: vi.fn() }),
}));

const me = vi.fn();
vi.mock("./api", async () => {
    const actual = await vi.importActual<typeof import("./api")>("./api");
    return { ...actual, api: { ...actual.api, me: () => me() } };
});

function wrap(ui: React.ReactNode) {
    const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
    return render(<QueryClientProvider client={client}>{ui}</QueryClientProvider>);
}

describe("RequireKind", () => {
    beforeEach(() => replace.mockClear());

    it("renders staff screens for a staff session", async () => {
        me.mockResolvedValue({ kind: "staff", email: "s@example.com" });
        wrap(<RequireKind kind="staff">operations</RequireKind>);
        expect(await screen.findByText("operations")).toBeInTheDocument();
        expect(replace).not.toHaveBeenCalled();
    });

    it("sends a customer session away from staff screens without telling it anything", async () => {
        me.mockResolvedValue({ kind: "customer", email: "c@example.com", account_id: "a1" });
        wrap(<RequireKind kind="staff">operations</RequireKind>);
        await waitFor(() => expect(replace).toHaveBeenCalledWith("/"));
        expect(screen.queryByText("operations")).not.toBeInTheDocument();
    });

    it("sends an unauthenticated visitor to sign in", async () => {
        me.mockRejectedValue(new ApiError(401, "not signed in"));
        wrap(<RequireKind kind="customer">account</RequireKind>);
        await waitFor(() => expect(replace).toHaveBeenCalledWith("/login"));
    });
});
