import * as React from 'react';
import { ResponsiveValue } from 'styled-system';
import { keyframes } from '@emotion/core';
import Text from '../text';
import View from '../view';
import TextInput from './text';
import TextArea from './textarea';

export const fadeIn: any = keyframes({
  '0%': {
    opacity: 0,
  },
  '100%': {
    opacity: 1,
  },
});

const XCircle = (props: any) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
    {...props}
  >
    <circle cx="12" cy="12" r="10" />
    <line x1="15" y1="9" x2="9" y2="15" />
    <line x1="9" y1="9" x2="15" y2="15" />
  </svg>
);

const CheckCircle = (props: any) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
    {...props}
  >
    <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
    <polyline points="22 4 12 14.01 9 11.01" />
  </svg>
);

type InputVariant = 'onWhite' | 'onBlack' | 'onGray';

export type InputProps = React.AllHTMLAttributes<HTMLInputElement> & {
  variant?: ResponsiveValue<InputVariant>;
  adorned?: 'before' | 'after';
} & (
    | { valid?: true; invalid?: false | undefined }
    | { invalid?: true; valid?: false | undefined }
  ) &
  (
    | { type: 'textarea'; pattern: undefined }
    | { type?: string; pattern?: string }
  );

const Input = (
  {
    type = 'text',
    placeholder = ' ',
    label,
    variant = 'onWhite',
    error,
    success,
    ...props
  }: InputProps & {
    label?: React.ReactNode;
    error?: React.ReactNode;
    success?: React.ReactNode;
  },
  ref: any,
) => {
  const [value, setValue] = React.useState('');
  const inputEl = React.useRef<HTMLInputElement>(ref);
  const validity =
    inputEl.current &&
    // @ts-ignore
    inputEl.current.validity &&
    // @ts-ignore
    inputEl.current.validity.valid;

  const valueMissing =
    inputEl.current &&
    // @ts-ignore
    inputEl.current.validity &&
    // @ts-ignore
    inputEl.current.validity.valueMissing;

  const inputValid = React.useMemo(() => {
    if (props.valid) {
      return 'valid';
    }
    if (props.invalid) {
      return 'invalid';
    }
    if (inputEl && inputEl.current) {
      if (validity && value !== '') {
        return 'valid';
      }
      if (!validity && value !== '') {
        return 'invalid';
      }
    }
    return 'pending';
  }, [
    inputEl.current,
    value,
    validity,
    valueMissing,
    props.invalid,
    props.valid,
  ]);

  const validationMessage = React.useMemo(() => {
    if (inputValid == 'valid') {
      return (
        <Text color="success.0" variant="-1r">
          {success}
        </Text>
      );
    }
    if (inputValid === 'invalid') {
      return (
        <Text color="error.0" variant="-1r">
          {error}
        </Text>
      );
    }
    return null;
  }, [inputValid, success, error]);

  const icon = React.useMemo(() => {
    if (type !== 'textarea') {
      if (inputValid == 'valid') {
        return <View as={CheckCircle} sx={{ color: 'success.0' }} />;
      }
      if (inputValid === 'invalid') {
        return <View as={XCircle} sx={{ color: 'error.0' }} />;
      }
      return null;
    }
    return null;
  }, [inputValid]);

  const handleChange = React.useCallback(
    evt => {
      setValue(evt.target.value);
      if (typeof props.onChange === 'function') {
        props.onChange(evt);
      }
    },
    [props.onChange, setValue],
  );

  const input = React.useMemo(() => {
    switch (type) {
      case 'textarea':
        return () => (
          <TextArea
            ref={inputEl}
            onChange={handleChange}
            placeholder={placeholder}
            variant={variant}
            {...props}
          />
        );
      case 'text':
        return () => (
          <TextInput
            ref={inputEl}
            adorned={Boolean(icon) ? 'after' : null}
            onChange={handleChange}
            type={type}
            placeholder={placeholder}
            variant={variant}
            {...props}
          />
        );
      default:
        return () => (
          <TextInput
            ref={inputEl}
            adorned={Boolean(icon) ? 'after' : null}
            type={type}
            placeholder={placeholder}
            variant={variant}
            {...props}
          />
        );
    }
  }, [variant, props]);

  return type === 'hidden' ? (
    input()
  ) : (
    <View
      as="label"
      sx={{
        position: 'relative',
        alignSelf: 'stretch',
        ...(type === 'textarea' && { width: '100%' }),
        marginBottom: 4, // space for a validation message, uniform spacing otherwise
      }}
    >
      <View sx={{ marginBottom: 2 }}>
        <Text variant="1r" color={variant === 'onBlack' ? 'white' : 'gray.0'}>
          {label}
        </Text>
      </View>
      <View sx={{ alignSelf: 'stretch' }}>
        {input()}
        {Boolean(icon) && (
          <View
            sx={{
              position: 'absolute',
              right: 0,
              top: 10,
              bottom: 4,
              width: 10,
              animation: `${fadeIn} .1s linear`,
            }}
          >
            {icon}
          </View>
        )}
      </View>
      {(error || success) && (
        <View
          sx={{
            top: '100%',
            paddingTop: 2,
            left: 0,
            right: 0,
            position: 'absolute',
          }}
        >
          {validationMessage}
        </View>
      )}
    </View>
  );
};

Input.displayName = 'Monterey(Input)';

export default React.forwardRef<HTMLInputElement, InputProps>(Input);
