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

import * as React from "react";
import {StyleSheet, css} from "aphrodite";
import Text from "./Text";
import Icon from "./Icon";

import colors from "./colors";

export type StatusIntent =
  | "pending"
  | "active"
  | "error"
  | "done"
  | "complete"
  | "due-soon";

export const STATUS_TO_COLOR = {
  pending: colors.grey20,
  active: colors.indigo30,
  error: colors.red40,
  done: colors.black,
  complete: colors.green40,
  "due-soon": colors.orange30,
};

export type Size = "xs" | "s" | "m" | "l";

type Props = {|
  /** The size of the Status */
  +size?: Size,
  /** The intent of the Status, affects the color, icon, and default content of the Status */
  +intent: StatusIntent,
  /** If "solid" show a background, if "bare" show no background, if "inline" show content with no padding */
  +kind?: "solid" | "bare" | "inline",
  /** If passed, override the default content in the Status */
  +children?: string,
  /** Use of icon is optional only when multiple statuses are displayed in the same row */
  +showIcon?: boolean,
|};

/**
 * @short A compact display component for labels and keywords
 * @status Beta
 * @category Data Display
 * @brandStatus V3
 *
 * Statuses indicate the progress of current state of an item. Comes with preset
 * text based on intent or can be modified.
 */
function Status({
  size = "m",
  intent,
  kind = "solid",
  children,
  showIcon = true,
}: Props) {
  const style =
    kind === "inline"
      ? null
      : {
          height: sizes[size],
          padding: `0 ${spacing[size]}px`,
          borderRadius: sizes[size] / 2,
        };

  const foregroundKind = kind === "inline" ? "bare" : kind;

  return (
    <span
      className={css(styles.status, kind === "solid" && fillStyles[intent])}
      style={style}
    >
      {showIcon && (
        <div className={css(styles.icon)}>
          <Icon
            size="xs"
            alignment="center"
            iconName={intentIcons[intent].iconName}
            color={intentIcons[intent].color[foregroundKind]}
          />
        </div>
      )}
      <Text
        scale={size === "xs" || size === "s" ? "subtext" : "base"}
        overflow="hidden"
        textOverflow="ellipsis"
        color={intentTextColors[intent][foregroundKind]}
        whiteSpace="nowrap"
      >
        {children != null ? children : sentenceCase(intent)}
      </Text>
    </span>
  );
}

function sentenceCase(str: string) {
  return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();
}

const sizes = {
  xs: 20,
  s: 24,
  m: 30,
  l: 40,
};

const spacing = {
  xs: 9,
  s: 10,
  m: 12,
  l: 15,
};

const styles = StyleSheet.create({
  status: {
    boxSizing: "border-box",
    display: "inline-flex",
    position: "relative",
    alignItems: "center",
    maxWidth: "100%",
    background: colors.white,
    overflow: "hidden",
  },
  icon: {
    position: "relative",
    display: "inline-flex",
    marginRight: "6px",
  },
});

const fillStyles = StyleSheet.create({
  // eslint not recognizing usage above
  // eslint-disable-next-line flexport/no-unused-aphrodite-styles
  pending: {
    border: `solid 1px ${colors.grey20}`,
  },
  // eslint-disable-next-line flexport/no-unused-aphrodite-styles
  active: {
    backgroundColor: colors.indigo30,
  },
  // eslint-disable-next-line flexport/no-unused-aphrodite-styles
  error: {
    backgroundColor: colors.red40,
  },
  // eslint-disable-next-line flexport/no-unused-aphrodite-styles
  done: {
    backgroundColor: colors.black,
  },
  // eslint-disable-next-line flexport/no-unused-aphrodite-styles
  complete: {
    backgroundColor: colors.green40,
  },
  "due-soon": {
    backgroundColor: colors.orange30,
  },
});

const intentTextColors = {
  pending: {
    solid: "grey40",
    bare: "grey40",
  },
  active: {
    solid: "white",
    bare: "indigo30",
  },
  error: {
    solid: "white",
    bare: "red40",
  },
  done: {
    solid: "white",
    bare: "black",
  },
  complete: {
    solid: "black",
    bare: "black",
  },
  "due-soon": {
    solid: "grey60",
    bare: "black",
  },
};

export const intentIcons = {
  pending: {
    color: {
      solid: "grey40",
      bare: "grey40",
    },
    iconName: "rejected",
  },
  active: {
    color: {
      solid: "white",
      bare: "indigo30",
    },
    iconName: "active",
  },
  error: {
    color: {
      solid: "white",
      bare: "red40",
    },
    iconName: "attention",
  },
  done: {
    color: {
      solid: "white",
      bare: "black",
    },
    iconName: "check",
  },
  complete: {
    color: {
      solid: "black",
      bare: "green40",
    },
    iconName: "check",
  },
  "due-soon": {
    color: {
      solid: "grey60",
      bare: "orange30",
    },
    iconName: "attention",
  },
};

export default (React.memo<Props>(Status): React.AbstractComponent<
  Props,
  mixed
>);
