import type { ThemeSettings } from "@domainops/shared-types";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi, beforeEach } from "vitest";
import { AuthProvider } from "@/lib/auth/AuthProvider";
import { BrandingProvider } from "@/lib/branding/BrandingProvider";
import { ThemeProvider } from "@/lib/theme/ThemeProvider";
import { ApiError } from "@/lib/api/client";
import * as authApi from "@/lib/api/auth";
import LoginPage from "./page";

const push = vi.fn();
const replace = vi.fn();

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

vi.mock("@/lib/api/auth");

const THEME: ThemeSettings = {
  id: 1,
  mode: "light",
  allow_user_override: true,
  preset: null,
  light_primary_color: "#1677ff",
  light_success_color: null,
  light_warning_color: null,
  light_error_color: null,
  light_info_color: null,
  dark_primary_color: "#1677ff",
  dark_success_color: null,
  dark_warning_color: null,
  dark_error_color: null,
  dark_info_color: null,
  border_radius: 6,
  spacing_scale: "comfortable",
  card_style: "bordered",
  button_style: "solid",
  background_style: "solid",
  login_layout: "centered-card",
  nav_layout: "top",
  light_login_background_color: null,
  dark_login_background_color: null,
  login_image_url: null,
};

function renderLoginPage() {
  return render(
    <ThemeProvider theme={THEME}>
      <BrandingProvider branding={{ site_title: "Domain/Ops", site_logo: null }}>
        <AuthProvider>
          <LoginPage />
        </AuthProvider>
      </BrandingProvider>
    </ThemeProvider>,
  );
}

describe("LoginPage", () => {
  beforeEach(() => {
    vi.mocked(authApi.fetchCurrentUser).mockResolvedValue(null);
    push.mockClear();
    replace.mockClear();
  });

  it("renders the sign-in form once the session check resolves", async () => {
    renderLoginPage();

    expect(await screen.findByRole("heading", { name: "Sign in" })).toBeInTheDocument();
    expect(screen.getByLabelText("Username")).toBeInTheDocument();
    expect(screen.getByLabelText("Password")).toBeInTheDocument();
    expect(screen.getByRole("button", { name: "Sign in" })).toBeInTheDocument();
  });

  it("shows the required-field errors when submitted empty", async () => {
    const user = userEvent.setup();
    renderLoginPage();
    await screen.findByRole("heading", { name: "Sign in" });

    await user.click(screen.getByRole("button", { name: "Sign in" }));

    expect(await screen.findByText("Enter your username")).toBeInTheDocument();
    expect(screen.getByText("Enter your password")).toBeInTheDocument();
    expect(authApi.login).not.toHaveBeenCalled();
  });

  it("shows the server's error message when login fails", async () => {
    vi.mocked(authApi.login).mockRejectedValue(new ApiError("These credentials do not match our records.", 422, null));
    const user = userEvent.setup();
    renderLoginPage();
    await screen.findByRole("heading", { name: "Sign in" });

    await user.type(screen.getByLabelText("Username"), "wrong-user");
    await user.type(screen.getByLabelText("Password"), "wrong-pass");
    await user.click(screen.getByRole("button", { name: "Sign in" }));

    expect(await screen.findByText("These credentials do not match our records.")).toBeInTheDocument();
    expect(push).not.toHaveBeenCalled();
  });

  it("redirects to the dashboard on a successful login with no 2FA", async () => {
    vi.mocked(authApi.login).mockResolvedValue({
      id: 1,
      name: "Super Admin",
      username: "super-admin",
      email: "super-admin@example.com",
      role_id: 1,
      is_admin: true,
      is_crowned_or_above: true,
      tab_permissions: null,
      action_permissions: null,
      two_factor_enabled: false,
      theme_mode: null,
      two_factor_setup_required: false,
    });
    const user = userEvent.setup();
    renderLoginPage();
    await screen.findByRole("heading", { name: "Sign in" });

    await user.type(screen.getByLabelText("Username"), "super-admin");
    await user.type(screen.getByLabelText("Password"), "Admin@1234");
    await user.click(screen.getByRole("button", { name: "Sign in" }));

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

  it("switches to the 2FA code form when the account requires it", async () => {
    vi.mocked(authApi.login).mockResolvedValue({ requires_2fa: true });
    const user = userEvent.setup();
    renderLoginPage();
    await screen.findByRole("heading", { name: "Sign in" });

    await user.type(screen.getByLabelText("Username"), "2fa-user");
    await user.type(screen.getByLabelText("Password"), "correct-password");
    await user.click(screen.getByRole("button", { name: "Sign in" }));

    expect(await screen.findByRole("heading", { name: "Verify it's you" })).toBeInTheDocument();
    expect(document.querySelectorAll(".dms_login_2fa_code_otp input")).toHaveLength(6);
    expect(push).not.toHaveBeenCalled();
  });
});
