import { describe, it, expect, vi, beforeEach } from "vitest";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { MemoryRouter, Routes, Route } from "react-router-dom";
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
import { SetupGuard } from "../SetupGuard";

// Mock the shared setup status hook
vi.mock("../../hooks/useSharedSetupStatus", () => ({
  useSharedSetupStatus: vi.fn(),
  invalidateSetupStatus: vi.fn(),
}));

import { useSharedSetupStatus } from "../../hooks/useSharedSetupStatus";

const mockedUseSharedSetupStatus = vi.mocked(useSharedSetupStatus);

function renderGuard() {
  return render(
    <FluentProvider theme={webLightTheme}>
      <MemoryRouter initialEntries={["/dashboard"]}>
        <Routes>
          <Route
            path="/dashboard"
            element={
              <SetupGuard>
                <div data-testid="protected-content">Protected</div>
              </SetupGuard>
            }
          />
          <Route
            path="/setup"
            element={<div data-testid="setup-page">Setup Page</div>}
          />
        </Routes>
      </MemoryRouter>
    </FluentProvider>,
  );
}

describe("SetupGuard", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("shows a spinner while the setup status is loading", () => {
    mockedUseSharedSetupStatus.mockReturnValue({
      status: null,
      loading: true,
      error: null,
      refresh: vi.fn(),
    });
    renderGuard();
    expect(screen.getByRole("progressbar")).toBeInTheDocument();
  });

  it("renders children when setup is complete", async () => {
    mockedUseSharedSetupStatus.mockReturnValue({
      status: { completed: true },
      loading: false,
      error: null,
      refresh: vi.fn(),
    });
    renderGuard();
    await waitFor(() => {
      expect(screen.getByTestId("protected-content")).toBeInTheDocument();
    });
  });

  it("redirects to /setup when setup is not complete", async () => {
    mockedUseSharedSetupStatus.mockReturnValue({
      status: { completed: false },
      loading: false,
      error: null,
      refresh: vi.fn(),
    });
    renderGuard();
    await waitFor(() => {
      expect(screen.getByTestId("setup-page")).toBeInTheDocument();
    });
    expect(screen.queryByTestId("protected-content")).not.toBeInTheDocument();
  });

  it("renders an error card when the setup status check fails", async () => {
    mockedUseSharedSetupStatus.mockReturnValue({
      status: null,
      loading: false,
      error: "Network error",
      refresh: vi.fn(),
    });
    renderGuard();

    await waitFor(() => {
      expect(screen.getByRole("button", { name: /retry/i })).toBeInTheDocument();
    });
    expect(screen.getByText(/network error/i)).toBeInTheDocument();
    expect(screen.queryByTestId("protected-content")).not.toBeInTheDocument();
    expect(screen.queryByTestId("setup-page")).not.toBeInTheDocument();
  });

  it("retries setup status fetch when Retry is clicked", async () => {
    const refreshMock = vi.fn();
    mockedUseSharedSetupStatus.mockReturnValue({
      status: null,
      loading: false,
      error: "Network error",
      refresh: refreshMock,
    });

    renderGuard();

    await waitFor(() => {
      expect(screen.getByRole("button", { name: /retry/i })).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: /retry/i }));

    expect(refreshMock).toHaveBeenCalled();
  });
});
