import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Component } from "react";
import { LinkButton } from ".";

interface ErrorBoundaryProps {
  children?: React.ReactNode;
}

interface ErrorBoundaryState {
  hasError: boolean;
  error: Error | null;
}

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
  constructor(props: ErrorBoundaryProps) {
    super(props);

    this.state = {
      hasError: false,
      error: null,
    };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  render() {
    const { hasError, error } = this.state;
    const { children } = this.props;

    if (hasError && error) {
      // You can render any custom fallback UI
      return <div data-testid="error">{error.message}</div>;
    }

    return children;
  }
}

describe("Test for LinkButton", () => {
  it("renders without error", () => {
    const view = render(
      <LinkButton href="http://www.example.com/">Link</LinkButton>,
    );
    expect(view).toBeTruthy();
  });

  it("should call onClick callback if supplied", async () => {
    const onClick = vi.fn();
    render(
      <LinkButton href="#" onClick={onClick}>
        Link
      </LinkButton>,
    );
    await userEvent.click(screen.getByText("Link"));
    expect(onClick).toHaveBeenCalled();
  });

  it("throws when href is empty", () => {
    const spy = vi.spyOn(console, "error");
    spy.mockImplementation(() => {});

    render(
      <ErrorBoundary>
        <LinkButton href="">Link</LinkButton>
      </ErrorBoundary>,
    );
    expect(screen.getByTestId("error")).toHaveTextContent(
      "LinkButton requires a href prop",
    );

    spy.mockRestore();
  });

  it("uses the elementType prop", () => {
    function CustomComponent(props: any) {
      return <a data-testid="custom-component" {...props} />;
    }
    render(
      <LinkButton href="#test" elementType={CustomComponent}>
        Test
      </LinkButton>,
    );
    expect(screen.getByTestId("custom-component")).toBeInTheDocument();
  });

  describe("given elementType", () => {
    it("is not applied as element attribute", () => {
      const { container } = render(
        <LinkButton href="#test" elementType="span">
          Test
        </LinkButton>,
      );
      expect(container.firstChild).not.toHaveAttribute("elementtype", "span");
    });
  });
});
