import { ParsedUrlQueryInput, stringify } from "querystring"
import { sanitizeUrl } from "@braintree/sanitize-url"
import React, { ComponentPropsWithoutRef, forwardRef } from "react"
import {
  disabledVariants,
  DisabledVariantProps,
} from "../../styles/utils/disabled"
import { LinkVariantProps, linkVariants } from "../../styles/utils/link"
import { classNames } from "../../utils/classNames"

export type Url = string | { pathname: string; query?: ParsedUrlQueryInput }

export type LinkProps = Omit<ComponentPropsWithoutRef<"a">, "href"> &
  LinkVariantProps &
  DisabledVariantProps & {
    href?: Url
  }

/**
 * A standard `a` tag with reasonable defaults.
 */
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(
  { className, href, variant = "default", disabled, rel, target, ...rest },
  ref,
) {
  if (href && isExternalLink(href)) {
    target = target ?? "_blank"
    rel = rel ?? "nofollow noopener"
  }

  return (
    <a
      aria-disabled={disabled ?? undefined}
      className={classNames(
        linkVariants({ variant }),
        disabledVariants({ disabled }),
        className,
      )}
      href={href ? sanitizeUrl(formatHref(href)) : undefined}
      ref={ref}
      rel={rel}
      tabIndex={disabled ? -1 : undefined}
      target={target}
      {...rest}
    />
  )
})

export const isExternalLink = (href: Url): boolean => {
  if (typeof href === "string") {
    return !href.startsWith("/")
  }

  return !href.pathname.startsWith("/")
}

export const formatHref = (href: Url): string => {
  if (typeof href === "string") {
    return href
  }
  const querystring = stringify(href.query)
  if (!querystring) {
    return href.pathname
  }
  return `${href.pathname}?${querystring}`
}

export const NonAnchorLink = forwardRef<HTMLAnchorElement, LinkProps>(
  function NonAnchorLink(
    { href, className, disabled, variant = "default", ...rest },
    ref,
  ) {
    function navigate() {
      if (href) {
        if (isExternalLink(href)) {
          window.open(sanitizeUrl(formatHref(href)), "_blank")
        } else {
          window.location.href = sanitizeUrl(formatHref(href))
        }
      }
    }

    return (
      <span
        {...rest}
        className={classNames(
          linkVariants({ variant }),
          disabledVariants({ disabled }),
          className,
        )}
        ref={ref}
        role="link"
        tabIndex={disabled ? -1 : 0}
        onClick={event => {
          rest.onClick?.(
            event as React.MouseEvent<HTMLAnchorElement, MouseEvent>,
          )
          event.preventDefault()
          navigate()
        }}
        onKeyDown={event => {
          rest.onKeyDown?.(event as React.KeyboardEvent<HTMLAnchorElement>)
          if (event.keyCode === 13) {
            navigate()
          }
        }}
      />
    )
  },
)
