// @flow
import React, { useEffect, useCallback, useRef, useState } from 'react';
import styled from 'styled-components';
import { UnstyledButton } from '../../../behaviors/unstyled-button';
import { Box } from '../../../../primitives';
import type { FormInputProps } from './form-input.proptypes';
import {
  getInputBorder,
  getInputLeftPadding,
  getPlaceholderColor,
  getIconDataUri,
  getInputIconPosition,
  getTextColor,
  getStyledButtonPadding,
  getInputVerticalPadding,
  getInputFontSize,
  getDisabledBackgroundColor,
} from './form-input.css-rules';
import { getPaletteColor } from '../../../../mixins/branding';
import {
  getFontSize,
  getFontFamily,
  getFontWeight,
} from '../../../../mixins/typography';
import { RevealTextShow, RevealTextHide } from '../../../icon';
import { FloatingLabelInput } from '../floating-label-input/floating-label-input.component';

const StyledBox = styled(Box)`
  padding-bottom: ${getInputVerticalPadding};
  padding-top: ${getInputVerticalPadding};
  border-radius: 6px;
  border: ${getInputBorder};
  border-color: ${getPaletteColor('greyscale-light')};
  max-width: 100%;
  background-color: white;

  :focus-within {
    border-color: ${getPaletteColor('greyscale-dark')};
  }
  &:not([disabled]):hover {
    border-color: ${getPaletteColor('greyscale-medium')};
  }
`;

const StyledInput = styled.input.attrs(({ fontSize, large }) => ({
  fontSize: getInputFontSize({ fontSize, large }),
  bold: large ? 'true' : undefined,
}))`
  color: ${getTextColor};
  font-family: ${getFontFamily};
  font-size: ${getFontSize};
  font-weight: ${getFontWeight};
  padding-bottom: 2px;
  padding-left: ${getInputLeftPadding};
  border: none;
  background-image: ${getIconDataUri};
  background-repeat: no-repeat;
  background-position: ${getInputIconPosition};
  margin-top: 5px;
  margin-bottom: 5px;
  flex-grow: 2;

  :disabled {
    background-color: ${getDisabledBackgroundColor};
  }

  &&::placeholder {
    /* Chrome, Firefox, Opera, Safari 10.1+ */
    color: ${getPlaceholderColor};
    font-style: italic;
    opacity: 1; /* Firefox */
  }

  &&::-ms-input-placeholder {
    /* Microsoft Edge */
    font-style: italic;
    color: ${getPlaceholderColor};
  }

  &&:-ms-input-placeholder {
    /* Internet Explorer 10-11 */
    font-style: italic;
    color: ${getPlaceholderColor};
  }
`;

const StyledButton = styled(UnstyledButton)`
  font-family: ${getFontFamily};
  color: ${getPaletteColor('greyscale-dark')};
  width: auto;
  margin: 5px 10px 5px 0;
  padding: ${getStyledButtonPadding};
`;

export const FormInput = ({
  focusOnMount,
  onRef,
  onChange,
  id,
  floatLabel,
  label,
  hideBorder = false,
  type,
  ...props
}: FormInputProps<string>) => {
  const inputRef = useRef();

  // TODO: we should just let the component pass a ref in instead of
  // an onRef function. https://github.com/wealthsimple/patchwork/issues/771
  useEffect(() => {
    if (onRef && inputRef.current) {
      onRef(inputRef.current);
    }
  }, [onRef, inputRef]);

  const handleChange = useCallback(
    (event) => {
      onChange(event.target.value, event);
    },
    [onChange],
  );

  const [passwordTextVisible, setPasswordTextVisible] = useState(false);
  let inputType = type || 'text';
  if (type === 'password' && !props.disabled && passwordTextVisible) {
    inputType = 'text';
  }

  const button = (
    <>
      {props.buttonText != null ? (
        <StyledButton type="button" onClick={props.buttonPress}>
          {props.buttonText}
        </StyledButton>
      ) : null}
      {type === 'password' && !props.disabled && (
        <StyledButton
          type="button"
          onClick={() => setPasswordTextVisible((oldValue) => !oldValue)}
          large={props.large}
          aria-label={
            passwordTextVisible
              ? props.hideValueButtonLabel
              : props.revealValueButtonLabel
          }
        >
          {passwordTextVisible ? (
            <RevealTextShow colorName="greyscale-dark" />
          ) : (
            <RevealTextHide colorName="greyscale-dark" />
          )}
        </StyledButton>
      )}
    </>
  );

  if (floatLabel) {
    return (
      <FloatingLabelInput
        id={id}
        onRef={(ref) => {
          inputRef.current = ref;
        }}
        type={inputType}
        disabled={props.disabled}
        value={props.value || ''}
        error={!!props.error}
        onChange={handleChange}
        onFocus={props.onFocus}
        onBlur={props.onBlur}
        iconType={props.iconType}
        iconPosition={props.iconPosition}
        inputMode={props.inputMode}
        hideBorder={hideBorder}
        label={label}
      >
        {button}
      </FloatingLabelInput>
    );
  }

  return (
    <StyledBox
      {...props}
      stacked="row"
      large={props.large}
      hideBorder={hideBorder}
      colorName={props.disabled && !hideBorder ? 'background' : undefined}
    >
      <StyledInput
        {...props}
        id={id}
        ref={inputRef}
        type={inputType}
        placeholder={props.placeholder || ''}
        disabled={props.disabled}
        value={props.value || ''}
        error={!!props.error}
        onChange={handleChange}
        onFocus={props.onFocus}
        onBlur={props.onBlur}
        large={props.large}
        iconType={props.iconType}
        iconPosition={props.iconPosition}
        autoFocus={focusOnMount}
        inputMode={props.inputMode}
        hideBorder={hideBorder}
        spellCheck={type === 'email' || type === 'password' ? false : undefined}
      />
      {button}
    </StyledBox>
  );
};

FormInput.displayName = 'FormInput';
