/* eslint-disable react-hooks/exhaustive-deps */
import clsx from 'clsx';
import { forwardRef, useDeferredValue, useMemo, useState } from 'react';
import { useFormContext, UseFormRegister } from 'react-hook-form';

import { ClearButton } from './clear-button';
import { Description } from './description';
import { ErrorMessage } from './error-message';
import { TextField, TextFieldProps } from './text-field';
import { TextInputContainer } from './text-input-container';
import { TextLabel } from './text-label';

type TextInputProps = {
  label?: string | React.ReactNode;
  description?: string | React.ReactNode;
  selectMode?: boolean;
  isOpenBottomSheet?: boolean;
  classStr?: string;
  labelClassStr?: string;
  isErrorPaddingPresent?: boolean;
  isShowError?: boolean;
  onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
} & Omit<TextFieldProps, 'isFocused' | 'setIsFocused' | 'textFieldId'> &
  ReturnType<UseFormRegister<any>>;

export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(function TextInput(props, ref) {
  const {
    name,
    label,
    description,
    disabled,
    onClick,
    selectMode,
    isOpenBottomSheet,
    classStr,
    labelClassStr,
    isErrorPaddingPresent = true,
    isShowError = true,
  } = props;
  const textFieldId = useMemo(() => `text-input-${name}`, [name]);

  const {
    setFocus,
    setValue,
    watch,
    formState: { errors },
    clearErrors,
  } = useFormContext();
  const value = watch(name);
  const [isFocused, setIsFocused] = useState(false);

  // selectMode true일 때는, input Focus 상태를 isOpenBottomSheet 상태로 처리
  const isSelecting = useMemo(() => !!selectMode && !!isOpenBottomSheet, [selectMode, isOpenBottomSheet]);
  const deferredIsFocused = useDeferredValue(isFocused || isSelecting);

  const hasValue = useMemo(() => !!value && String(value)?.length > 0, [value]);

  const isActiveWithoutError = useMemo(
    () => deferredIsFocused && hasValue && !errors[name],
    [hasValue, deferredIsFocused, errors[name]],
  );

  const handleContainerClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
    onClick?.(event);
  };

  // handle clear button
  const handleClickClearButton = () => {
    setValue(name, '');
    clearErrors(name);
    setFocus(name);
  };

  return (
    <>
      <div
        className={clsx('ipt-form text-input', {
          'btm-sheet': selectMode,
          [classStr as string]: classStr,
        })}
        onClick={handleContainerClick}
      >
        <TextInputContainer
          labelClassStr={labelClassStr}
          disabled={disabled}
          isError={!!errors[name]}
          isActiveWithoutError={isActiveWithoutError}
        >
          <TextLabel
            isError={!!errors[name]}
            isFocused={deferredIsFocused}
            hasValue={hasValue}
            textFieldId={textFieldId}
            isActiveWithoutError={isActiveWithoutError}
            label={label}
          />
          <TextField
            {...props}
            textFieldId={textFieldId}
            ref={ref}
            isFocused={isFocused || isSelecting}
            setIsFocused={setIsFocused}
          />

          <ClearButton
            isActiveWithoutError={isActiveWithoutError}
            isError={!!errors[name]}
            isShow={!hasValue || !deferredIsFocused}
            onClick={!disabled ? handleClickClearButton : undefined}
          />
        </TextInputContainer>
        <ErrorMessage name={name} isErrorPaddingPresent={isErrorPaddingPresent} isShowError={isShowError} />
      </div>
      <Description description={description} />
    </>
  );
});
