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

const mockPush = vi.fn();
const mockGetStatus = vi.fn();
const mockCreateBreakglass = vi.fn();
const mockConfigureOidc = vi.fn();
const mockTestProvider = vi.fn();
const mockAddProvider = vi.fn();
const mockCompleteOnboarding = vi.fn();

vi.mock("next/navigation", () => ({
  useRouter: (): { push: typeof mockPush } => ({
    push: mockPush,
  }),
}));

vi.mock("@/lib/api/onboarding", () => ({
  fetchOnboardingStatus: (): ReturnType<typeof mockGetStatus> => mockGetStatus(),
  createBreakglassAdmin: (...args: unknown[]): ReturnType<typeof mockCreateBreakglass> =>
    mockCreateBreakglass(...args),
  configureOidcProvider: (...args: unknown[]): ReturnType<typeof mockConfigureOidc> =>
    mockConfigureOidc(...args),
  testOnboardingProvider: (...args: unknown[]): ReturnType<typeof mockTestProvider> =>
    mockTestProvider(...args),
  addOnboardingProvider: (...args: unknown[]): ReturnType<typeof mockAddProvider> =>
    mockAddProvider(...args),
  completeOnboarding: (): ReturnType<typeof mockCompleteOnboarding> => mockCompleteOnboarding(),
}));

describe("OnboardingWizard", () => {
  beforeEach(() => {
    mockPush.mockReset();
    mockGetStatus.mockReset();
    mockCreateBreakglass.mockReset();
    mockConfigureOidc.mockReset();
    mockTestProvider.mockReset();
    mockAddProvider.mockReset();
    mockCompleteOnboarding.mockReset();

    mockGetStatus.mockResolvedValue({ completed: false });
    mockCreateBreakglass.mockResolvedValue({ id: "bg-1", username: "admin" });
    mockConfigureOidc.mockResolvedValue(undefined);
    mockTestProvider.mockResolvedValue({ success: true });
    mockAddProvider.mockResolvedValue({ id: "provider-1" });
    mockCompleteOnboarding.mockResolvedValue(undefined);
  });

  it("renders the first step with admin setup fields", async () => {
    render(<OnboardingWizard />);

    expect(
      await screen.findByText("Welcome to Mosaic Stack. Let's get you set up.")
    ).toBeInTheDocument();
    expect(screen.getByLabelText("Username")).toBeInTheDocument();
    expect(screen.getByLabelText("Password")).toBeInTheDocument();
    expect(screen.getByLabelText("Confirm Password")).toBeInTheDocument();
    expect(screen.getByText("1. Admin")).toBeInTheDocument();
  });

  it("validates admin form fields before submit", async () => {
    const user = userEvent.setup();
    render(<OnboardingWizard />);

    await screen.findByText("Welcome to Mosaic Stack. Let's get you set up.");
    await user.click(screen.getByRole("button", { name: "Create Admin" }));

    expect(screen.getByText("Username must be at least 3 characters.")).toBeInTheDocument();
    expect(mockCreateBreakglass).not.toHaveBeenCalled();
  });

  it("supports happy path with OIDC skipped", async () => {
    const user = userEvent.setup();
    render(<OnboardingWizard />);

    await screen.findByText("Welcome to Mosaic Stack. Let's get you set up.");

    await user.type(screen.getByLabelText("Username"), "admin");
    await user.type(screen.getByLabelText("Password"), "verysecurepassword");
    await user.type(screen.getByLabelText("Confirm Password"), "verysecurepassword");
    await user.click(screen.getByRole("button", { name: "Create Admin" }));

    await screen.findByText("Configure OIDC Provider (Optional)");
    await user.click(screen.getByRole("button", { name: "Skip" }));

    await screen.findByText("Add Your First LLM Provider");
    await user.type(screen.getByLabelText("Display Name"), "My OpenAI");
    await user.type(screen.getByLabelText("API Key"), "sk-test-key");

    await user.click(screen.getByRole("button", { name: "Test Connection" }));
    await screen.findByText("Connection successful.");

    const addProviderButton = screen.getByRole("button", { name: "Add Provider" });
    expect(addProviderButton).toBeEnabled();
    await user.click(addProviderButton);

    await screen.findByText("You're all set");
    await user.click(screen.getByRole("button", { name: "Launch Mosaic Stack" }));

    await waitFor(() => {
      expect(mockPush).toHaveBeenCalledWith("/");
    });
  });
});
