import React from 'react'
import { Box, PolymorphicComponentProps } from 'react-polymorphic-box'
import { isInternal, isAnchorOnly, extractAnchor } from '@walltowall/helpers'

const defaultElement = 'a'

export type LinkPropsBase = {
  /** URL that the component links to. */
  href: string
  /** Component to render if `href` is internal. */
  routerLinkComponent?: React.ElementType
}

export type LinkProps<E extends React.ElementType> = PolymorphicComponentProps<
  E,
  LinkPropsBase
>

/**
 * `<View>` that dynamically changes from an `<a>` to a router-specific
 * component depending on if `href` is external or internal.
 *
 * If `href` is external, `target` is automatically set to `_target` and `rel`
 * is automatically set to `nofollow noopener noreferrer`. Both can be
 * overridden by passing their respective props.
 *
 * This component should be used a base for a project-specific Link component
 * that adds a default `routerLinkComponent`.
 *
 * @example
 * With an internal `href`:
 * <Link href="/example">Example</Link>
 *
 * @example
 * With an external `href` rendered with Gatsby's Link:
 * <Link href="https://example.com" routerLinkComponent={GatsbyLink}>
 *   Example
 * </Link>
 */
export const Link = React.forwardRef(
  <E extends React.ElementType = typeof defaultElement>(
    {
      ref,
      href: rawHref,
      routerLinkComponent: RouterLinkComponent = 'a',
      ...props
    }: LinkProps<E>,
    innerRef: typeof ref,
  ) => {
    const href = isAnchorOnly(rawHref) ? extractAnchor(rawHref) ?? '' : rawHref

    const isInternalHref = isInternal(href)
    // E.g. tel: or mailto:
    const isSpecialLink = !isInternalHref && !href.startsWith('http')

    return (
      <Box
        ref={innerRef}
        as={isInternalHref ? RouterLinkComponent : defaultElement}
        href={href}
        target={isInternalHref || isSpecialLink ? undefined : '_blank'}
        rel={
          isInternalHref || isSpecialLink
            ? undefined
            : 'nofollow noopener noreferrer'
        }
        {...props}
      />
    )
  },
) as <E extends React.ElementType = typeof defaultElement>(
  props: LinkProps<E>,
) => React.ReactElement

// @ts-ignore: Component type does not currently include displayName
Link.displayName = 'Link'
