import { render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";

const { checkKillSwitchMock, logoutMock, refreshStoredAuthSessionMock, replaceMock, useAuthMock } = vi.hoisted(() => ({
  checkKillSwitchMock: vi.fn(async () => ({ disabled: false, message: "" })),
  logoutMock: vi.fn(),
  refreshStoredAuthSessionMock: vi.fn(async () => true),
  replaceMock: vi.fn(),
  useAuthMock: vi.fn(() => ({ isAuthenticated: true, isLoading: false, logout: logoutMock })),
}));

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

vi.mock("@/lib/auth", () => ({
  useAuth: useAuthMock,
}));

vi.mock("@/lib/auth-session", () => ({
  refreshStoredAuthSession: refreshStoredAuthSessionMock,
}));

vi.mock("@/lib/kill-switch", () => ({
  checkKillSwitch: checkKillSwitchMock,
}));

import { AuthGuard } from "./AuthGuard";

describe("AuthGuard", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    useAuthMock.mockReturnValue({ isAuthenticated: true, isLoading: false, logout: logoutMock });
    refreshStoredAuthSessionMock.mockResolvedValue(true);
    checkKillSwitchMock.mockResolvedValue({ disabled: false, message: "" });
  });

  it("redirects unauthenticated users to login", async () => {
    useAuthMock.mockReturnValue({ isAuthenticated: false, isLoading: false, logout: logoutMock });

    render(<AuthGuard><div>Private app</div></AuthGuard>);

    await waitFor(() => expect(replaceMock).toHaveBeenCalledWith("/login"));
    expect(screen.queryByText("Private app")).not.toBeInTheDocument();
  });

  it("refreshes an expired stored session before showing protected content", async () => {
    render(<AuthGuard><div>Private app</div></AuthGuard>);

    await waitFor(() => expect(refreshStoredAuthSessionMock).toHaveBeenCalledOnce());
    expect(await screen.findByText("Private app")).toBeInTheDocument();
    expect(logoutMock).not.toHaveBeenCalled();
  });

  it("logs out and redirects when session refresh fails", async () => {
    refreshStoredAuthSessionMock.mockResolvedValue(false);

    render(<AuthGuard><div>Private app</div></AuthGuard>);

    await waitFor(() => expect(logoutMock).toHaveBeenCalledOnce());
    expect(replaceMock).toHaveBeenCalledWith("/login");
    expect(screen.queryByText("Private app")).not.toBeInTheDocument();
  });

  it("keeps protected content hidden when the kill switch is active", async () => {
    checkKillSwitchMock.mockResolvedValue({ disabled: true, message: "Maintenance window" });

    render(<AuthGuard><div>Private app</div></AuthGuard>);

    expect(await screen.findByText("Maintenance window")).toBeInTheDocument();
    expect(screen.queryByText("Private app")).not.toBeInTheDocument();
  });

  it("shows a platform-down state when readiness cannot be checked", async () => {
    checkKillSwitchMock.mockRejectedValue(new Error("HTTP 503 Service Unavailable"));

    render(<AuthGuard><div>Private app</div></AuthGuard>);

    expect(await screen.findByText("Platform services are unavailable")).toBeInTheDocument();
    expect(screen.queryByText("Private app")).not.toBeInTheDocument();
  });
});
