import React, { useCallback, useEffect, useRef, useState } from 'react';
import { bem } from 'utils/bem';
import { Icon } from 'common/components/icon';
import { IconName } from 'common/components/icon/types';
import { SFlatInputWrapper } from './s-flat-input';
import { Tooltip } from 'common/components/tooltip';
import { H4, SmallText } from 'common/components/typography';
import { Widget } from 'common/constants';

interface Props {
  placeholder?: string;
  value?: string;
  defaultValue?: string;
  infoTooltipContent?: string;
  fieldTooltipContent?: string;
  resetTooltipContent?: string;
  className?: string;
  iconLeft?: IconName;
  iconRight?: IconName;
  disabled?: boolean;
  readonly?: boolean;
  dataSelector?: string;
  maxLength?: number;
  autoFocus?: boolean;
  placeholderPersistent?: boolean;
  onChange?(value: string): void;
  onInputChange?(event: React.ChangeEvent<HTMLInputElement>): void;
  onBlur?(value: string): void;
  onFocus?(): void;
  onResetClick?(): void;
  valueChangeValidator?(value: string): boolean;
}

const classes = bem('input');

export const FlatInput = React.memo(
  ({
    placeholder = '',
    value,
    defaultValue,
    infoTooltipContent,
    fieldTooltipContent,
    resetTooltipContent,
    className,
    iconLeft,
    iconRight,
    disabled = false,
    readonly = false,
    dataSelector,
    maxLength,
    onChange,
    onResetClick,
    onInputChange,
    onBlur,
    onFocus,
    autoFocus,
    placeholderPersistent = false,
    valueChangeValidator,
  }: Props) => {
    const inputRef = useRef<HTMLInputElement>(null);
    const [isFocused, setIsFocused] = useState(false);
    const [isHovered, setIsHovered] = useState(false);
    const [isResetFocused, setIsResetFocused] = useState(false);
    const [innerValue, setInnerValue] = useState(value || '');

    const rightIconName = isFocused ? 'enter' : iconRight;

    useEffect(() => {
      setInnerValue(value || '');
    }, [value]);

    const onChangeHandler = useCallback(
      (event: React.ChangeEvent<HTMLInputElement>) => {
        if (valueChangeValidator && !valueChangeValidator(event.target.value)) return;
        setInnerValue(event.target.value);
        onInputChange?.(event);
      },
      [onInputChange, valueChangeValidator]
    );

    const onFocusHandler = useCallback(() => {
      onFocus?.();
      setIsFocused(true);
    }, [onFocus]);

    const onBlurHandler = useCallback(() => {
      onChange?.(innerValue);
      onBlur?.(innerValue);
      setIsFocused(false);
    }, [onBlur, onChange, innerValue]);

    const onKeyUpHandler = useCallback((e: React.KeyboardEvent) => {
      if (e.key === 'Enter') {
        inputRef.current?.blur();
      }
    }, []);

    const onReset = useCallback(() => {
      setInnerValue(defaultValue || '');
      onChange?.(defaultValue || '');
      onResetClick?.();
      setIsResetFocused(false);
    }, [onChange, defaultValue, onResetClick]);

    useEffect(() => {
      const blurReset = (event: MouseEvent) => {
        // @ts-ignore: wrong event types
        if (event.target?.id !== 'reset-span') {
          setIsResetFocused(false);
        }
      };

      document.addEventListener('mouseup', blurReset);
      return () => document.removeEventListener('mouseup', blurReset);
    }, []);

    const shouldShowReset = defaultValue && defaultValue !== innerValue && (isFocused || isResetFocused);
    const shouldShowIconTooltip = infoTooltipContent && !isFocused && !isResetFocused;
    const shouldShowFieldTooltip = !!fieldTooltipContent && !isFocused && isHovered;
    const shouldShowResetTooltip = !!resetTooltipContent;
    const shouldUseValueForMeasure = (!placeholderPersistent || innerValue.length >= placeholder.length) && innerValue;
    return (
      <SFlatInputWrapper
        className={className}
        hasIconLeft={!!iconLeft}
        hasIconRight={!!iconRight}
        disabled={disabled}
        data-selector={dataSelector}
      >
        <Tooltip content={fieldTooltipContent} visible={shouldShowFieldTooltip}>
          <div
            className={classes('wrapper')}
            onMouseEnter={() => setIsHovered(true)}
            onMouseLeave={() => setIsHovered(false)}
          >
            {iconLeft && (
              <Icon
                size="glyph"
                name={iconLeft}
                data-selector={`${dataSelector}-left-icon`}
                className={classes('icon', 'left')}
              />
            )}
            <div className={classes('input-container')}>
              {placeholderPersistent && <H4 className={classes('placeholder')}>{placeholder}</H4>}
              <input
                autoFocus={autoFocus}
                ref={inputRef}
                type={Widget.Text}
                placeholder={placeholderPersistent ? undefined : placeholder}
                disabled={disabled}
                readOnly={readonly}
                data-selector={`${dataSelector}-input`}
                maxLength={maxLength}
                value={innerValue}
                onChange={onChangeHandler}
                onBlur={onBlurHandler}
                onKeyUp={onKeyUpHandler}
                onFocus={onFocusHandler}
                className={classes('input')}
              />
            </div>
            <span className={classes('input-sizer')}>{shouldUseValueForMeasure ? innerValue : placeholder}</span>
            {rightIconName && (
              <Icon
                size="glyph"
                name={rightIconName}
                data-selector={`${dataSelector}-right-icon`}
                className={classes('icon', 'right')}
              />
            )}
          </div>
        </Tooltip>
        {shouldShowIconTooltip && (
          <Tooltip content={infoTooltipContent}>
            <div data-selector={`${dataSelector}-info-icon`} className={classes('info')}>
              <Icon name="info" color="pink" size="general" />
            </div>
          </Tooltip>
        )}
        {shouldShowReset && (
          <Tooltip content={resetTooltipContent} enabled={shouldShowResetTooltip}>
            <SmallText
              onMouseDown={() => setIsResetFocused(true)}
              onClick={onReset}
              id="reset-span"
              data-selector={`${dataSelector}-reset`}
              className={classes('reset-text')}
            >
              Reset
            </SmallText>
          </Tooltip>
        )}
      </SFlatInputWrapper>
    );
  }
);
