import clsx from 'clsx';
import React, { KeyboardEventHandler, useRef, useState } from 'react';
import { noop } from '../../../../helpers/utils';
import { FilterValidationResult, FilterValue } from '../../Filters.model';
import classes from './FreeTextFilter.scss';

export interface FreeTextFilterProps {
  value?: FilterValue;
  /** Callback triggered when a new filter value is selected */
  onSelect: (value: FilterValue) => void;

  /** Callback triggered when validation fails */
  onError?: () => void;

  /** Callback triggered for custom validations of the filter */
  onValidate?: (currentValue: FilterValue) => FilterValidationResult;

  /** CSS Class name for additional styles */
  className?: string;
  /** Select text on focus if true (default: true) */
  selectOnFocus?: boolean;
  /** Optional id for the input field */
  inputId?: string;
}

export const FreeTextFilter: React.FC<FreeTextFilterProps> = ({
  value,
  onSelect,
  onError = noop,
  onValidate: customValidate,
  className = '',
  selectOnFocus = true,
  inputId,
}) => {
  const [errorMsg, setErrorMsg] = useState<string>();
  const ENTER_KEY = 'Enter';

  const [valueLocal, setValue] = useState(value || '');
  const inputRef = useRef<HTMLInputElement>(null);

  const onFocusWrapper = (): void => {
    if (selectOnFocus && valueLocal) {
      // setTimeout ensures inputRef.current is available before selecting, as it may be null if the user hits enter and refocuses.
      setTimeout(() => {
        inputRef.current?.select();
      });
    }
  };

  const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (e) => {
    if (e.key === ENTER_KEY) {
      const value = e.currentTarget.value;

      const validationMessage = customValidate && customValidate(value);

      if (validationMessage) {
        setErrorMsg(validationMessage);
        onError();
      } else {
        onSelect(value ? value : undefined);
      }
    }
  };

  return (
    <div
      className={clsx(
        classes.container,
        'free-text-filter-container',
        className,
      )}
    >
      <input
        id={inputId}
        ref={inputRef}
        autoFocus
        className={clsx(classes.inputValue, errorMsg && classes.hasError)}
        onKeyDown={handleKeyDown}
        value={valueLocal as string}
        onChange={(e) => setValue(e.target.value)}
        onFocus={onFocusWrapper}
      />
      {errorMsg !== undefined && <small>{errorMsg}</small>}
    </div>
  );
};
