import PropTypes from 'prop-types';
import Color from 'color';
import styled, { css } from 'styled-components';
import {
  extractThemeOrDefault,
  getValueString,
  transition,
} from 'reactackle-core';

const propTypes = {
  disabled: PropTypes.bool,
  /**
   * Full-width TextField doesn't have borders
   */
  fullWidth: PropTypes.bool,
  /**
   * If textfield is dense it has smaller paddings
   */
  dense: PropTypes.bool,
  /**
   * If bordered = false, TextField will have only bottom border
   */
  bordered: PropTypes.bool,
  colorScheme: PropTypes.oneOf(['neutral', 'error', 'success']),
  /**
   * Define label position
   */
  labelPosition: PropTypes.oneOf(['top', 'side']),
  /**
   * If slidingLabel = true, label will float to top
   * when parent textfield is focused or filled
   */
  slidingLabel: PropTypes.bool,
  /**
   * Add icon behind textfield
   */
  iconOuter: PropTypes.element,
  /**
   * Define component theme config
   * See https://github.com/styled-components/styled-components/blob/master/docs/theming.md
   * for more information
   */
  theme: PropTypes.object,
};

const defaultProps = {
  disabled: false,
  fullWidth: false,
  dense: false,
  bordered: false,
  colorScheme: 'neutral',
  labelPosition: 'top',
  slidingLabel: false,
  iconOuter: null,
};

/** PROP RECEIVERS */
const labelBase = ({
  theme: themeFromProvider,
  bordered,
  focus,
  filled,
  dense,
  fullWidth,
}) => {
  const theme = extractThemeOrDefault(themeFromProvider);
  const textfieldKey = bordered ? 'bordered' : 'underlined';
  const textfieldPath = theme.reactackle.components.textfield.textfield;
  const labelPath = theme.reactackle.components.textfield.label.positionTop;

  let textfieldSource = null;
  if (dense && !fullWidth) textfieldSource = textfieldPath.size.dense;
  else if (dense && fullWidth)
    textfieldSource = textfieldPath.size.denseFullWidth;
  else if (!dense && fullWidth) textfieldSource = textfieldPath.size.fullWidth;
  else textfieldSource = textfieldPath.size;

  /**
   * When textfield isn't in focus or filled, label should look like TextField's
   * value
   */
  const { fontSize, lineHeight } =
    focus || filled ? labelPath : textfieldSource;

  const borderWidth = getValueString(textfieldPath[textfieldKey].borderWidth);
  const borderWidthSubstraction = bordered ? `${borderWidth} * 2` : borderWidth;

  const { paddingY } = textfieldSource;

  const { textTransform, fontWeight } = labelPath;

  const filledStyles = `
    height: auto;
    bottom: auto;
    cursor: text;
    white-space: nowrap;
    background-color: transparent;
    top: 0;
  `;

  const defaultStyles = css`
    height: calc(100% - ${borderWidthSubstraction});
    bottom: ${borderWidth};
    cursor: default;
    font-weight: ${fontWeight};
    text-transform: ${textTransform};
    align-items: flex-end;
    padding-bottom: ${getValueString(paddingY)};
    pointer-events: none;
  `;

  return css`
    font-size: ${getValueString(fontSize)};
    line-height: ${lineHeight};
    ${transition('color, font-size, height')};
    ${focus || filled ? filledStyles : defaultStyles};
  `;
};

const labelSpacing = ({
  bordered,
  labelPosition,
  dense,
  fullWidth,
  theme: themeFromProvider,
}) => {
  const theme = extractThemeOrDefault(themeFromProvider);
  const key = labelPosition === 'top' ? 'positionTop' : 'positionSide';
  const labelSizeType = bordered ? 'bordered' : 'underlined';
  const path =
    theme.reactackle.components.textfield.label[key].size[labelSizeType];
  let source = null;

  if (dense && !fullWidth) source = path.dense;
  else if (dense && fullWidth) source = path.denseFullWidth;
  else if (!dense && fullWidth) source = path.fullWidth;
  else source = path;

  const labelSpacing = getValueString(source.labelSpacing);

  return labelPosition === 'top'
    ? `margin-bottom: ${labelSpacing};`
    : `margin-right: ${labelSpacing};`;
};

const labelStyle = ({
  theme: themeFromProvider,
  disabled,
  colorScheme,
  labelPosition,
  focus,
  filled,
}) => {
  const theme = extractThemeOrDefault(themeFromProvider),
    key = labelPosition === 'top' ? 'positionTop' : 'positionSide',
    labelPath = theme.reactackle.components.textfield.label[key].style,
    textfieldPath = theme.reactackle.components.textfield.textfield.state,
    placeholderPath = theme.reactackle.components.textfield.placeholder;

  let labelSource = null,
    textfieldSource = null;

  if (!disabled) {
    if (colorScheme !== 'neutral') {
      labelSource = labelPath[colorScheme];
      textfieldSource = textfieldPath[colorScheme];
    } else if (focus) {
      labelSource = labelPath.focus;
      textfieldSource = textfieldPath.focus;
    } else {
      labelSource = labelPath;
      textfieldSource = textfieldPath;
    }
  } else {
    labelSource = labelPath.disabled;
    textfieldSource = textfieldPath.disabled;
  }

  const { fontColor } = focus || filled ? labelSource : placeholderPath;

  const textfieldBackgroundColor = Color(
    textfieldSource.backgroundColor,
  ).alpha()
    ? textfieldSource
    : 'white';

  const backgroundColor =
    focus || filled ? 'transparent' : textfieldBackgroundColor;

  return `
    background-color: ${backgroundColor};
    color: ${fontColor};
  `;
};

const offset = ({ theme: themeFromProvider, dense, fullWidth, iconOuter }) => {
  const theme = extractThemeOrDefault(themeFromProvider);
  const path = theme.reactackle.components.textfield.iconOuter;

  let source = null;
  if (dense && !fullWidth) source = path.size.dense;
  else if (dense && fullWidth) source = path.size.denseFullWidth;
  else if (!dense && fullWidth) source = path.size.fullWidth;
  else source = path.size;

  const iconSpacing = getValueString(path.iconSpacing);
  const boxSize = getValueString(source.boxSize);

  const iconOffset = iconOuter ? `calc(${boxSize} + ${iconSpacing})` : 0;

  return (
    iconOffset &&
    `
    left: ${iconOffset};
    max-width: calc(100% - ${iconOffset});
  `
  );
};

/** STYLES */
export const LabelSlidingStyled = styled.label`
  display: flex;
  user-select: none;
  width: 100%;
  position: absolute;
  z-index: 2;
  justify-content: flex-start;
  ${labelBase};
  ${labelStyle};
  ${labelSpacing};
  ${offset};
`;

LabelSlidingStyled.propTypes = propTypes;
LabelSlidingStyled.defaultProps = defaultProps;
LabelSlidingStyled.displayName = 'LabelSlidingStyled';
