import type { DetailedHTMLProps } from 'react';
import React, {
  forwardRef,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';

export interface AutoSizingInputProps
  extends DetailedHTMLProps<
    React.InputHTMLAttributes<HTMLInputElement>,
    HTMLInputElement
  > {
  value?: string;
  onChangeValue?: (value: string) => void;
  onChange?: React.ChangeEventHandler<HTMLInputElement>;
}

export const AutoSizingInput = forwardRef<
  HTMLInputElement,
  AutoSizingInputProps
>(
  (
    { value: _value, onChangeValue, onChange, ...rest },
    ref
  ): React.ReactNode => {
    const [value, setValue] = useState(_value);
    const [width, setWidth] = useState(0);
    const span = useRef<HTMLSpanElement>(null);

    useEffect(() => {
      span.current && setWidth(span.current.offsetWidth);
    }, [value]);

    const changeHandler = useCallback<
      React.ChangeEventHandler<HTMLInputElement>
    >(
      (evt) => {
        onChange?.(evt);
        setValue(evt.target.value);
      },
      [onChange]
    );

    useEffect(() => {
      setValue(_value || '');
    }, [_value]);

    useEffect(() => {
      onChangeValue?.(value || '');
    }, [value, onChangeValue]);

    return (
      <div className="auto-sizing-input wrapper" style={{ width: width + 24 }}>
        <input onChange={changeHandler} ref={ref} value={value} {...rest} />
        <span aria-hidden="true" ref={span}>
          {value}
        </span>
      </div>
    );
  }
);

AutoSizingInput.displayName = 'AutoSizingInput';
