import clsx from 'clsx';
import React, {
  ChangeEvent,
  InputHTMLAttributes,
  useEffect,
  useRef,
} from 'react';
import { executeIfRefAvailable } from '../../../helpers/utils';
import { BaseFormControl, BaseInputEvents } from '../Form.models';
import { FormElementContainer } from '../FormElementContainer';
import classes from './SingleLineText.scss';

export interface SingleLineTextProps extends BaseFormControl, BaseInputEvents {
  /** Input element type */
  type?: 'text' | 'password' | 'number';

  /**
   * This property is only used in combination with `type='password'`.
   *
   * Use this to signalize the textbox whether it should act like a value is already set, eventhough the actual `value` is empty.
   * This is useful if the backend just indicates that a password is set, but doesn't give out the actual value.
   */
  isSet?: boolean;
  /** Current value the form control has */
  value?: InputHTMLAttributes<HTMLInputElement>['value'];
  /** Default value for the form control */
  defaultValue?: InputHTMLAttributes<HTMLInputElement>['defaultValue'];
  /** Input placeholder */
  placeholder?: string;
  /** Whether or not the control should start focused (default: false) */
  autoFocus?: boolean;
  /** Whether or not the control supports auto complete */
  autoComplete?: 'on' | 'off';

  innerRef?: React.RefObject<HTMLInputElement>;

  /**
   * Additional props to be passed to the input element.
   */
  inputProps?: InputHTMLAttributes<HTMLInputElement>;
}

/**
 * This component can be used to display a text input inside a form.
 * If you run your form in a Formik context, consider using the `SingleLineTextField` component instead.
 */
export const SingleLineText: React.FC<SingleLineTextProps> = ({
  name,
  id,
  type,
  isSet,
  value,
  disabled = false,
  placeholder,
  error,
  autoFocus = false,
  autoComplete,
  innerRef: refFromParent,
  defaultValue,
  onChange,
  onBlur,
  onFocus,
  className = '',
  inputProps,
  ...rest
}) => {
  // Create a local ref if no ref is passed from the parent
  const localRef = useRef<HTMLInputElement>(null);
  const innerRef = refFromParent || localRef;

  const errorMsg: string | undefined = error;
  const DUMMY_PWD = '0000000000';
  const isPasswordField = type === 'password';

  useEffect(() => {
    if (innerRef.current) {
      const isTruthyValue = value === 0 || Boolean(value);
      innerRef.current.value = isTruthyValue ? String(value) : '';
    }
  }, [innerRef, value]);

  useEffect(() => {
    // Only set the dummy password if the field is a password field and the value is not set
    // and the field is not focused
    if (
      isPasswordField &&
      isSet &&
      !value &&
      document.activeElement !== innerRef.current
    ) {
      executeIfRefAvailable(innerRef, (input) => {
        input.value = DUMMY_PWD;
      });
    }
  }, [innerRef, isPasswordField, isSet, value]);

  const onFocusWrapper = (e: ChangeEvent<HTMLInputElement>): void => {
    if (isPasswordField && isSet && !value) {
      executeIfRefAvailable(innerRef, (input) => {
        input.value = '';
      });
    }
    onFocus?.(e);
  };
  const onBlurWrapper = (e: ChangeEvent<HTMLInputElement>): void => {
    if (isPasswordField && isSet && !value) {
      executeIfRefAvailable(innerRef, (input) => {
        input.value = DUMMY_PWD;
      });
    }
    onBlur?.(e);
  };

  return (
    <FormElementContainer
      {...rest}
      className={clsx(
        classes.container,
        'single-line-text-container',
        className,
      )}
      error={errorMsg}
      dataTestFieldType="SingleLineText"
      htmlFor={id ?? name}
    >
      <input
        {...inputProps}
        className={clsx({ [classes.hasError]: errorMsg !== undefined })}
        id={id ?? name}
        name={name}
        type={type}
        ref={innerRef}
        defaultValue={defaultValue}
        disabled={disabled}
        placeholder={disabled ? undefined : placeholder}
        autoFocus={autoFocus}
        autoComplete={autoComplete}
        onChange={onChange}
        onBlur={onBlurWrapper}
        onFocus={onFocusWrapper}
      />
    </FormElementContainer>
  );
};
