/**
 * TEAM: frontend_infra
 *
 * @flow
 */

import * as React from "react";
import {StyleSheet, css} from "aphrodite";
import {match} from "path-to-regexp"; // Used by Found to match paths
import Link from "../Link";
import Icon, {type IconNames} from "../Icon";
import Text from "../Text";
import Badge from "../Badge";
import colors from "../colors";
import whitespace from "../styles/whitespace";
import SideNavContext from "./SideNavContext";

const AUTOICON_SIZE = 16;
const VALID_AUTOICON_COLORS = [
  colors.grey20,
  colors.red20,
  colors.orange20,
  colors.blue20,
  colors.green20,
  colors.purple20,
  colors.indigo20,
];

type Props = {|
  /** the url that should be navigated to upon click */
  +href: string,
  /** the name of the icon you intend to use. */
  +iconName?: IconNames,
  /** number of notifications to show next to the item, if greater than 0, a badge not is rendered */
  +notificationCount?: number,
  /** regex string you also want highlighting for this link to match on */
  +matchPath?: string,
  +children: React.Node,
|};

export const ITEM_SIZE: number = whitespace.xxl;

/**
 * @short SideNavItem is used with SideNav to represent a clickable nav link within in
 * @category Navigation
 * @status Stable
 * @brandStatus V3
 */
export default function SideNavItem({
  href,
  iconName,
  notificationCount,
  children,
  matchPath,
}: Props): React.Element<"div"> {
  const {areIconsEnabled, setHighlightedElement, pathname} =
    React.useContext(SideNavContext);
  const isActive = isWithinRoute(href, matchPath, pathname);

  return (
    <div
      className={css(styles.item)}
      ref={isActive ? setHighlightedElement : undefined}
    >
      <Link
        href={href}
        className={css(styles.link, !isActive && styles.linkInactive)}
      >
        {areIconsEnabled ? (
          <div className={css(styles.icon)}>
            <Badge
              value={
                notificationCount != null ? notificationCount > 0 : undefined
              }
              intent="complete"
            >
              {iconName ? (
                <Icon
                  iconName={iconName}
                  color="white"
                  deprecatedAllowColorInheritance={false}
                />
              ) : (
                <AutoIcon colorSource={href} />
              )}
            </Badge>
          </div>
        ) : (
          <div className={css(styles.noIconPadding)} />
        )}
        <div className={css(styles.label)}>
          <Text
            color="white"
            display="block"
            overflow="hidden"
            textOverflow="ellipsis"
            whiteSpace="nowrap"
          >
            {children}
          </Text>
        </div>
        <div className={css(styles.notificationCount)}>
          <Text color="white">{notificationCount}</Text>
        </div>
      </Link>
    </div>
  );
}

const AutoIcon = React.memo<{|+colorSource: string|}>(function AutoIcon({
  colorSource,
}: {|
  +colorSource: string,
|}) {
  return (
    <div
      className={css(styles.autoIcon)}
      style={{backgroundColor: generateColorFromString(colorSource)}}
    />
  );
});

// Based on answer by haykam & Thymine, see: https://stackoverflow.com/questions/3426404/create-a-hexadecimal-colour-based-on-a-string-with-javascript
function generateColorFromString(source: string) {
  let hash = 0;

  if (source.length !== 0) {
    for (let i = 0; i < source.length; i += 1) {
      // eslint-disable-next-line no-bitwise
      hash = source.charCodeAt(i) + ((hash << 5) - hash);
      // eslint-disable-next-line no-bitwise
      hash &= hash; // Convert to 32bit integer
    }
  }

  return VALID_AUTOICON_COLORS[Math.abs(hash) % VALID_AUTOICON_COLORS.length];

  // return `hsl(${hash % 360},90%,90%)`; // Alternatively generate colors in anywhere in the color wheel
}

function isWithinRoute(route: string, matchPath: ?string, pathname: string) {
  if (matchPath) {
    if (match(matchPath, {decode: decodeURIComponent})(pathname)) {
      return true;
    }
  }
  return pathname === route;
}

const styles = StyleSheet.create({
  item: {
    position: "relative",
    width: "100%",
    listStyle: "none",
    margin: 0,
    height: ITEM_SIZE,
  },
  icon: {
    display: "flex",
    alignItems: "center",
    flex: "0 0 auto",
    justifyContent: "center",
    height: "100%",
    width: ITEM_SIZE,
  },
  noIconPadding: {
    width: whitespace.m,
    flex: "0 0 auto",
    position: "relative",
  },
  autoIcon: {
    width: AUTOICON_SIZE,
    height: AUTOICON_SIZE,
    position: "relative",
  },
  label: {
    marginRight: "auto",
    overflow: "hidden",
  },
  notificationCount: {
    marginLeft: whitespace.m,
    marginRight: whitespace.m,
  },
  link: {
    display: "flex",
    alignItems: "center",
    width: "100%",
    height: "100%",
    backgroundColor: "none",
    transition: `background-color 300ms ease-out`,
  },
  linkInactive: {
    ":focus": {
      backgroundColor: colors.grey50,
    },

    ":hover": {
      backgroundColor: colors.grey50,
    },

    ":active": {
      backgroundColor: colors.grey50,
    },
  },
});
