// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import type { ChangeEvent, KeyboardEvent } from 'react';
import React, { useCallback, useState, useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import classNames from 'classnames';

import { getClassNamesFor } from '../util/getClassNamesFor.std.ts';

export type PropsType = Readonly<{
  disableSpellcheck?: boolean;
  disabled?: boolean;
  moduleClassName?: string;
  onChange: (newValue: string) => void;
  onEnter?: () => void;
  placeholder: string;
  value?: string;
  maxLength?: number;
}>;

export function AutoSizeInput({
  disableSpellcheck,
  disabled,
  moduleClassName,
  onChange,
  onEnter,
  placeholder,
  value = '',
  maxLength,
}: PropsType): React.JSX.Element {
  const [root, setRoot] = useState<HTMLElement | null>(null);
  const hiddenRef = useRef<HTMLSpanElement | null>(null);

  const [width, setWidth] = useState<undefined | number>(undefined);
  const getClassName = getClassNamesFor('AutoSizeInput', moduleClassName);

  const handleChange = useCallback(
    (e: ChangeEvent<HTMLInputElement>) => {
      onChange(e.target.value);
    },
    [onChange]
  );

  const handleKeyDown = useCallback(
    (event: KeyboardEvent) => {
      if (onEnter && event.key === 'Enter') {
        onEnter();
      }
    },
    [onEnter]
  );

  useEffect(() => {
    const elem = document.createElement('div');
    document.body.appendChild(elem);

    setRoot(elem);

    return () => {
      document.body.removeChild(elem);
    };
  }, []);

  useEffect(() => {
    setWidth(hiddenRef.current?.clientWidth || undefined);
  }, [value, root]);

  return (
    <div className={getClassName('__container')}>
      <input
        type="text"
        className={getClassName('__input')}
        dir="auto"
        maxLength={maxLength}
        value={value}
        onChange={handleChange}
        onKeyDown={handleKeyDown}
        placeholder={placeholder}
        disabled={disabled}
        spellCheck={!disableSpellcheck}
        style={{ width }}
      />

      {root &&
        createPortal(
          <span
            ref={hiddenRef}
            className={classNames(
              getClassName('__input'),
              getClassName('__input--sizer')
            )}
          >
            {value || placeholder}
          </span>,
          root
        )}
    </div>
  );
}
