/**
 * TEAM: frontend_infra
 * @flow strict
 */
/* eslint-disable react/forbid-elements */

import * as React from "react";
import {css, StyleSheet} from "aphrodite";

import {typeScale, fontWeights} from "./styles";
import linkStyles from "./styles/linkStyles";
import colors from "./colors";

import ThemeNameContext, {type Theme} from "./context/ThemeNameContext";
import TextLinkContext from "./TextLinkContext";
import DeprecatedRouterContext from "./context/DeprecatedRouterContext";
import Link from "./Link";

/* eslint-disable react/prefer-stateless-function */

type Props = {|
  /** TextLink tags can only wrap strings. If you find this restrictive, contact @theseus. The thought is we want to avoid the temptation for folks to wrap entire apps or components in TextLink tags, since that usually means a different component should be built. */
  +children: string,
  /** The url that the link component will direct to. */
  +href: string,
  /** Inverse styles for dark backgrounds. */
  +darkBackground: boolean,
  /** Should this link open in a new tab, i.e. target='_blank' */
  +openInNewTab: boolean,
  /** The size of the link which is is a subset of TypeScale's sizes. */
  +scale?: "base" | "subtext" | "title",
  /** The boldness of the link. */
  +weight?: $Keys<typeof fontWeights>,
  /** Select a custom display property depending on how you intend to use the link. */
  +display:
    | "inline"
    | "inline-block"
    | "flex"
    | "block"
    | "inline-flex"
    | "none",
  // determines if we download the target page content instead of navigation.
  /** download attribute will override the target (new tab) behaviour if set to true */
  +download: boolean,
  /**
   * our single page app routing (called spaMixin) hijacks all clicks on
   * anchor tags. You might not want this, most often for switching between
   * applications (you want a full page reload). Set this to true to disable that
   * behavior.
   */
  +disableSpaHijack: boolean,
  /**
   * Gets passed through to NextJS router. This prop is the directory structure
   * corresponding to the NextJS page being linked to, and is used when linking
   * to dynamic routes (e.g. href="/shipments/12345/order" corresponds to
   * nextRoute="/shipments/[identifier]/[tab]"). No effect in non-NextJS apps.
   * https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes
   */
  +nextRoute?: string,
|};

/**
 * @short A TextLink which we can pass in a href for webpage navigation. TextLinks are more accessible (hovering over them shows the link preview in the browser), and don't require JavaScript.
 * @brandStatus V2
 * @status Stable
 * @category Interaction
 * @extends React.Component */
class TextLink extends React.PureComponent<Props> {
  static defaultProps: {|
    darkBackground: boolean,
    disableSpaHijack: boolean,
    display: Props["display"],
    download: boolean,
    openInNewTab: boolean,
  |} = {
    darkBackground: false,
    openInNewTab: false,
    display: "inline-block",
    disableSpaHijack: false,
    download: false,
  };
  static contextType: React.Context<Theme> = ThemeNameContext;
  context: Theme;

  render(): React.Node {
    const {
      children,
      href,
      openInNewTab,
      download,
      display,
      disableSpaHijack,
      darkBackground,
    } = this.props;
    return (
      <TextLinkContext.Consumer>
        {parentStyles => (
          <DeprecatedRouterContext.Consumer>
            {router => {
              let {scale, weight} = this.props;
              // If we are not provided with a style prop and we will use the one from context
              scale = scale || parentStyles.scale;
              weight = weight || parentStyles.weight;
              const isActive = router.isActive(href, true);
              const linkStyle = linkStyles(this.context);
              return (
                <Link
                  download={download}
                  disableSpaHijack={disableSpaHijack}
                  openInNewTab={openInNewTab}
                  className={css(
                    styles.standardOverride,
                    darkBackground ? linkStyle.inverse : linkStyle.default,
                    isActive && styles.activeColor
                  )}
                  href={href}
                  style={{
                    display,
                    ...typeScale[scale],
                    fontWeight: fontWeights[weight],
                  }}
                  nextRoute={this.props.nextRoute}
                >
                  {children}
                </Link>
              );
            }}
          </DeprecatedRouterContext.Consumer>
        )}
      </TextLinkContext.Consumer>
    );
  }
}

export default TextLink;

const styles = StyleSheet.create({
  standardOverride: {
    // override for our questionable OOCSS bottom margins on all semantic type tags
    marginBottom: 0,
    marginTop: 0,
    cursor: "pointer",
  },
  // activeColor is only used in apps that support Found router
  activeColor: {
    color: colors.blue50,
  },
});
