import { act, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, expect, test, vi } from "vitest";
import { AuthProvider } from "@/app/auth/AuthProvider.jsx";
import * as authApi from "@/features/auth/api";
import { setAccessToken, setRefreshHandler, setUnauthorizedHandler } from "@/shared/api/request";
import { AuthenticatedOpsCenter } from "./OpsCenterEntry.jsx";

vi.mock("@/features/auth/api", () => ({
    getMe: vi.fn(),
    login: vi.fn(),
    logout: vi.fn(),
    refreshSession: vi.fn(),
}));

vi.mock("./OpsCenterApp.jsx", () => ({
    OpsCenterApp: ({ can }) => (
        <div data-can-credit={String(can("lucky-gift:pool-credit"))} data-testid="ops-center-app" />
    ),
}));

beforeEach(() => {
    vi.clearAllMocks();
    setAccessToken("");
    setRefreshHandler(null);
    setUnauthorizedHandler(null);
});

test("does not mount the dashboard without a session and redirects to login with the full ops path", async () => {
    authApi.refreshSession.mockRejectedValue(new Error("no session"));
    const targetWindow = fakeWindow("/ops-center/", "?view=configs", "#dynamic_v3");

    render(
        <AuthProvider>
            <AuthenticatedOpsCenter targetWindow={targetWindow} />
        </AuthProvider>,
    );

    // refresh 尚未结束以及确定无用户后的跳转窗口都只展示骨架，Dashboard 不会发出任何业务请求。
    expect(screen.queryByTestId("ops-center-app")).toBeNull();
    await waitFor(() => {
        expect(targetWindow.location.replace).toHaveBeenCalledWith(
            "/login?redirect=%2Fops-center%2F%3Fview%3Dconfigs%23dynamic_v3",
        );
    });
    expect(screen.queryByTestId("ops-center-app")).toBeNull();
});

test("waits for stale-token refresh fallback before mounting the dashboard", async () => {
    const refresh = deferred();
    const me = deferred();
    setAccessToken("stale-token");
    authApi.refreshSession.mockReturnValue(refresh.promise);
    authApi.getMe.mockReturnValue(me.promise);
    const targetWindow = fakeWindow("/ops-center/", "?view=overview", "");

    render(
        <AuthProvider>
            <AuthenticatedOpsCenter targetWindow={targetWindow} />
        </AuthProvider>,
    );

    expect(screen.queryByTestId("ops-center-app")).toBeNull();
    await act(async () => {
        refresh.reject(new Error("refresh cookie expired"));
    });
    await waitFor(() => expect(authApi.getMe).toHaveBeenCalledTimes(1));
    expect(screen.queryByTestId("ops-center-app")).toBeNull();

    await act(async () => {
        me.resolve({
            accessToken: "fresh-token",
            permissions: ["lucky-gift:pool-credit"],
            user: { id: 1, username: "ops" },
        });
    });

    expect(await screen.findByTestId("ops-center-app")).toHaveAttribute("data-can-credit", "true");
    expect(targetWindow.location.replace).not.toHaveBeenCalled();
});

function fakeWindow(pathname, search, hash) {
    return {
        location: {
            hash,
            pathname,
            replace: vi.fn(),
            search,
        },
    };
}

function deferred() {
    let resolve;
    let reject;
    const promise = new Promise((resolvePromise, rejectPromise) => {
        resolve = resolvePromise;
        reject = rejectPromise;
    });
    return { promise, reject, resolve };
}
