import { forwardRef } from "react";
import clsx from "clsx";
import Link from "next/link";

import Icon, { type IconVariant } from "@/components/icon";
import { isExternalUrl } from "@/helpers/link";
import { extractTextFromReactNode } from "@/helpers/string";

import styles from "./styles.module.scss";

// TODO: Refactor

enum CallToActionStyles {
  Link = "link",
  LinkPrimary = "linkPrimary",
  LinkInline = "linkInline",
  Button = "button",
  ButtonPrimary = "buttonPrimary",
  ButtonSecondary = "buttonSecondary",
  ButtonPill = "buttonPill",
}

export type CallToActionVariant = `${CallToActionStyles}`;

export interface CallToActionProps {
  href?: string;
  target?: string;
  variant?: CallToActionVariant;
  icon?: IconVariant;
  label?: string;
  ariaLabel?: string;
  onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
  onPointerEnter?: React.PointerEventHandler<
    HTMLButtonElement | HTMLAnchorElement
  >;
  onPointerLeave?: React.PointerEventHandler<
    HTMLButtonElement | HTMLAnchorElement
  >;
  onFocus?: React.FocusEventHandler<HTMLButtonElement | HTMLAnchorElement>;
  children?: React.ReactNode;
  className?: string;
  style?: React.CSSProperties;
}

const CallToAction = forwardRef<
  HTMLAnchorElement | HTMLButtonElement,
  CallToActionProps
>(
  (
    {
      href,
      onClick,
      variant,
      target,
      icon,
      label,
      ariaLabel,
      children,
      className,
      ...props
    },
    ref,
  ) => {
    const isExternalLink = href && isExternalUrl(href);
    const isInternalLink = href && !isExternalUrl(href);
    const isMailtoLink = href && href.startsWith("mailto:");
    const isButton = !isExternalLink && !isInternalLink;
    const inferredVariant = variant
      ? variant
      : isExternalLink || isInternalLink
        ? CallToActionStyles.Link
        : CallToActionStyles.Button;

    let ariaLabelWithFallback =
      ariaLabel ?? label ?? extractTextFromReactNode(children);

    if (href === "/") {
      ariaLabelWithFallback += "Go to the homepage";
    } else if (isExternalLink) {
      ariaLabelWithFallback += " (opens in a new window)";
    } else if (isMailtoLink) {
      ariaLabelWithFallback = `Send an email to ${href.replace("mailto:", "")}`;
    }

    const ctaClasses = clsx(
      styles.callToAction,
      styles[inferredVariant],
      className,
      {
        [styles.hasIcon]: icon,
      },
    );

    const inner = (
      <span className={styles.inner}>
        {children}
        {icon && (
          <Icon
            className={styles.icon}
            variant={icon}
            aria-label={ariaLabelWithFallback}
            {...props}
          />
        )}
        {label}
      </span>
    );

    const handleClick = (event: any) => {
      event.stopPropagation();
      if (onClick && typeof onClick === "function") onClick(event);
    };

    if (isExternalLink) {
      return (
        <a
          ref={ref as React.Ref<HTMLAnchorElement>}
          className={ctaClasses}
          href={href}
          target="_blank"
          rel="noopener noreferrer"
          onClick={handleClick}
          aria-label={ariaLabel}
          {...props}
        >
          {inner}
        </a>
      );
    }

    if (isInternalLink) {
      return (
        <Link
          ref={ref as React.Ref<HTMLAnchorElement>}
          className={ctaClasses}
          href={href}
          aria-label={ariaLabelWithFallback}
          onClick={handleClick}
          {...props}
        >
          {inner}
        </Link>
      );
    }

    if (isButton) {
      return (
        <button
          ref={ref as React.Ref<HTMLButtonElement>}
          className={ctaClasses}
          onClick={handleClick}
          aria-label={ariaLabelWithFallback}
          {...props}
        >
          {inner}
        </button>
      );
    }

    return null;
  },
);
CallToAction.displayName = "CallToAction";

export default CallToAction;
