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

describe("OAuthButton", (): void => {
  const defaultProps = {
    providerName: "Authentik",
    providerId: "authentik",
    onClick: vi.fn(),
  };

  it("should render with provider name", (): void => {
    render(<OAuthButton {...defaultProps} />);
    expect(screen.getByText("Continue with Authentik")).toBeInTheDocument();
  });

  it("should have full width styling", (): void => {
    render(<OAuthButton {...defaultProps} />);
    const button = screen.getByRole("button");
    expect(button.className).toContain("w-full");
  });

  it("should call onClick when clicked", async (): Promise<void> => {
    const user = userEvent.setup();
    const onClick = vi.fn();
    render(<OAuthButton {...defaultProps} onClick={onClick} />);

    const button = screen.getByRole("button");
    await user.click(button);

    expect(onClick).toHaveBeenCalledTimes(1);
  });

  it("should show loading state with spinner and Connecting text", (): void => {
    render(<OAuthButton {...defaultProps} isLoading={true} />);
    expect(screen.getByText("Connecting...")).toBeInTheDocument();
    expect(screen.queryByText("Continue with Authentik")).not.toBeInTheDocument();
  });

  it("should be disabled when isLoading is true", (): void => {
    render(<OAuthButton {...defaultProps} isLoading={true} />);
    const button = screen.getByRole("button");
    expect(button).toBeDisabled();
  });

  it("should be disabled when disabled prop is true", (): void => {
    render(<OAuthButton {...defaultProps} disabled={true} />);
    const button = screen.getByRole("button");
    expect(button).toBeDisabled();
  });

  it("should have reduced opacity when disabled", (): void => {
    render(<OAuthButton {...defaultProps} disabled={true} />);
    const button = screen.getByRole("button");
    expect(button.className).toContain("opacity-50");
    expect(button.className).toContain("pointer-events-none");
  });

  it("should have aria-label with provider name", (): void => {
    render(<OAuthButton {...defaultProps} />);
    const button = screen.getByRole("button");
    expect(button).toHaveAttribute("aria-label", "Continue with Authentik");
  });

  it("should have aria-label Connecting when loading", (): void => {
    render(<OAuthButton {...defaultProps} isLoading={true} />);
    const button = screen.getByRole("button");
    expect(button).toHaveAttribute("aria-label", "Connecting");
  });

  it("should render a spinner SVG when loading", (): void => {
    const { container } = render(<OAuthButton {...defaultProps} isLoading={true} />);
    const spinner = container.querySelector("svg");
    expect(spinner).toBeInTheDocument();
    expect(spinner?.getAttribute("class")).toContain("animate-spin");
  });

  it("should not call onClick when disabled", async (): Promise<void> => {
    const user = userEvent.setup();
    const onClick = vi.fn();
    render(<OAuthButton {...defaultProps} onClick={onClick} disabled={true} />);

    const button = screen.getByRole("button");
    await user.click(button);

    expect(onClick).not.toHaveBeenCalled();
  });
});
