import { css, CSSProperties } from 'glamor';
import { observer } from 'mobx-react';
import { useApphouse } from '../context/useApphouse';
import {
  ThemeColors,
  TypographyStyles
} from '../styles/defaults/themes.interface';
import { StyleOverwrites } from './component.interfaces';
import React from 'react';
import { omit } from '../utils/obj/omit';
import { useLocalStyles } from '../styles/defaults/useLocalStyles';
import { merge } from '../utils/obj/merge';
import { truncateWithEllipsis } from '../styles/helpers';

const getTextAs = (variant: keyof TypographyStyles): TextAsType => {
  let textAs: TextAsType = 'p';
  switch (variant) {
    case 'large':
      textAs = 'h1';
      break;
    case 'header':
      textAs = 'h2';
      break;
    case 'subheader':
      textAs = 'h3';
      break;
    case 'title':
      textAs = 'h4';
      break;
    case 'standard':
      textAs = 'p';
      break;
    case 'caption':
      textAs = 'p';
      break;
    case 'emphasis':
      textAs = 'em';
      break;
    default:
      textAs = 'p';
      break;
  }
  return textAs;
};

export type TextAsType =
  | 'p'
  | 'span'
  | 'h1'
  | 'h2'
  | 'h3'
  | 'h4'
  | 'h5'
  | 'h6'
  | 'caption'
  | 'label'
  | 'em';
/**
 * Interface for styles to be applied to the text component
 */
export type TextStyles = CSSProperties;
/**
 * Interface for props to be passed to the text component
 */
export interface BaseTextProps extends StyleOverwrites<TextStyles> {
  /**
   * @default standard
   */
  variant?: keyof TypographyStyles;
  /**
   * @default decided based on variant
   */
  as?: TextAsType;
  /**
   * The content of the text
   */
  children?: React.ReactNode;
  /**
   * The color to be applied to the text
   * @default 'onPrimary'
   */
  color?: keyof ThemeColors;
  /**
   * For accessibility, sets the id of the element the text is describing
   */
  htmlFor?: string;
  /**
   * if true, the text will be bold and overwrite the variant styles
   * @default false
   */
  bold?: boolean;
  /**
   * if true, the text will be aligned to the center
   * @default false
   */
  centerAlign?: boolean;
}

export interface TruncatedTextProps extends BaseTextProps {
  /**
   * if true, the text will be truncated
   * @default false
   */
  truncate?: boolean;
  /**
   * The max width of the text that will show before it is truncated.
   * It will be ignored if truncate is false
   * @default false
   * @optional
   */
  width: number;
}

export interface TextWithoutTruncationProps extends BaseTextProps {
  /**
   * if true, the text will be truncated
   * @default false
   */
  truncate?: false;
  /**
   * The max width of the text that will show before it is truncated.
   * It will be ignored if truncate is false
   * @default false
   * @optional
   */
  width?: never;
}

export type TextProps = TextWithoutTruncationProps | TruncatedTextProps;
/**
 * A text component that renders typography html tags as
 */
export const Text = observer((props: TextProps) => {
  const {
    children,
    as,
    variant = 'standard',
    styleOverwrites = {},
    gutters,
    color,
    centerAlign,
    width,
    truncate = false
  } = props;

  const { theme } = useApphouse();
  const { styles, colors, tokens } = theme;
  const Component = as || getTextAs(variant);
  const defaultStyles = styles.typography[variant];
  const colorStyles = color
    ? {
        color: colors[color]
      }
    : {};

  const truncateStyles = width && truncate ? truncateWithEllipsis(width) : {};

  const boldStyles = props.bold ? { fontWeight: tokens.fontWeight.bolder } : {};
  const componentStyles = merge(
    {},
    defaultStyles,
    colorStyles,
    truncateStyles,
    boldStyles
  );
  const localStyles = useLocalStyles(componentStyles, styleOverwrites, gutters);

  return (
    <Component
      {...css(
        { marginBlockStart: 0, marginBlockEnd: 0 },
        centerAlign ? { textAlign: 'center' } : {},
        localStyles
      )}
      {...omit(props, [
        'alignCenter',
        'styleOverwrites',
        'gutters',
        'color',
        'as',
        'variant',
        'bold'
      ])}
      data-variant={variant}
      data-xray="Text"
    >
      {children}
    </Component>
  );
});
