// @flow
import React, { useCallback, useEffect, useRef, useState } from 'react';
import MaskedInput from 'cleave.js/react';
import 'cleave.js/dist/addons/cleave-phone.ca';
import 'cleave.js/dist/addons/cleave-phone.gb';
import 'cleave.js/dist/addons/cleave-phone.us';
import styled from 'styled-components';
import { UnstyledButton } from '../../../behaviors/unstyled-button';
import type { MaskedTextInputProps } from './masked-text-input.proptypes';
import {
  getInputBorder,
  getInputLeftPadding,
  getPlaceholderColor,
  getIconDataUri,
  getInputIconPosition,
  getTextColor,
  getInputVerticalPadding,
  getInputFontSize,
  getStyledButtonPadding,
  getBackgroundColor,
} from './masked-text-input.css-rules';
import { RevealTextShow, RevealTextHide } from '../../../icon';
import { getPaletteColor } from '../../../../mixins/branding';
import {
  getFontSize,
  getFontFamily,
  getFontWeight,
} from '../../../../mixins/typography';
import { Box } from '../../../../primitives';
import { getBaseFocusState } from '../../../../mixins/focus';
import { FloatingLabelInput } from '../floating-label-input/floating-label-input.component';
import { useDisableAutofill } from '../../../../utils';

const StyledWrapper = styled(Box)`
  background-color: ${getBackgroundColor};
  border-radius: 6px;
  border: ${getInputBorder};
  padding-bottom: ${getInputVerticalPadding};
  padding-top: ${getInputVerticalPadding};

  &&& {
    border-color: ${getPaletteColor('greyscale-light')};
  }

  &&:focus-within {
    border-color: ${getPaletteColor('greyscale-dark')};
  }

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

  > input {
    background-image: ${getIconDataUri};
    background-position: ${getInputIconPosition};
    background-color: transparent;
    background-repeat: no-repeat;
    border: none;
    color: ${getTextColor};
    font-family: ${getFontFamily};
    font-size: ${getFontSize};
    font-weight: ${getFontWeight};
    margin-bottom: 5px;
    margin-top: 5px;
    outline: none;
    padding-bottom: 2px;
    padding-left: ${getInputLeftPadding};
    width: 100%;

    &::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};
    }

    ${getBaseFocusState({
      hoverTransition: false,
      activeTransition: false,
      pointerCursor: false,
    })}
  }
`;

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

export const MaskedTextInput = (props: MaskedTextInputProps<string>) => {
  const {
    onRef,
    focusOnMount,
    fontSize,
    onChange,
    large,
    iconType,
    iconPosition,
    error,
    className,
    hideBorder = false,
    'data-qa': dataQa,
    'data-cy': dataCy,
    floatLabel,
    label,
    name,
    type,
    autocomplete,
  } = props;
  const textRef = useRef<HTMLInputElement | null>(null);
  const registerChild = useCallback(
    (ref) => {
      if (onRef != null) {
        onRef(ref);
      }
      textRef.current = ref;
    },
    [onRef, textRef],
  );
  const focusChild = useCallback(() => {
    if (textRef.current != null) {
      textRef.current.focus();
    }
  }, [textRef]);
  useEffect(() => {
    if (focusOnMount) {
      focusChild();
    }
  });
  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 disableAutofillProps = useDisableAutofill(autocomplete);

  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
        label={label}
        options={props.options}
        id={props.id}
        data-qa={dataQa}
        data-cy={dataCy}
        type={inputType || 'text'}
        disabled={props.disabled}
        value={props.value || ''}
        onFocus={props.onFocus}
        onBlur={props.onBlur}
        onChange={handleChange}
        error={error}
        name={name}
        autocomplete={autocomplete}
      >
        {button}
      </FloatingLabelInput>
    );
  }
  return (
    <StyledWrapper
      className={className}
      fontSize={getInputFontSize({ fontSize, large })}
      bold={large}
      iconType={iconType}
      iconPosition={iconPosition}
      error={error}
      large={large}
      onFocus={props.onFocus}
      onBlur={props.onBlur}
      hideBorder={hideBorder}
      disabled={props.disabled}
      name={name}
    >
      <MaskedInput
        id={props.id}
        options={props.options}
        htmlRef={registerChild}
        type={inputType || 'text'}
        placeholder={props.placeholder || ''}
        disabled={props.disabled}
        value={props.value || ''}
        onFocus={props.onFocus}
        onBlur={props.onBlur}
        onChange={handleChange}
        inputMode={props.inputMode}
        data-qa={dataQa}
        data-cy={dataCy}
        name={name}
        spellCheck={type === 'email' || type === 'password' ? false : undefined}
        {...disableAutofillProps}
      />
    </StyledWrapper>
  );
};

MaskedTextInput.displayName = 'MaskedTextInput';
