import React, { type ReactNode, useImperativeHandle, useRef } from 'react';
import { Box, InputAdornment, TextField, Typography } from '@mui/material';
import get from 'lodash/get';
import { Controller, useFormContext } from 'react-hook-form';
import type { TextFieldProps } from '@mui/material';
import type { RegisterOptions } from 'react-hook-form';
import FormLabel from './label';

type InputProps = TextFieldProps & {
  name: string;
  label?: ReactNode;
  placeholder?: string;
  errorPosition?: 'right' | 'bottom';
  rules?: RegisterOptions;
  wrapperStyle?: React.CSSProperties;
  required?: boolean;
  tooltip?: ReactNode | string;
  description?: ReactNode | string;
};

function FormInputError({ error }: { error: string }) {
  return (
    <InputAdornment position="end">
      <Typography component="span" color="error">
        {error}
      </Typography>
    </InputAdornment>
  );
}

export default function FormInput({
  ref = undefined,
  name,
  label = '',
  placeholder = '',
  rules = {},
  errorPosition = 'bottom',
  wrapperStyle = {},
  inputProps = {},
  required = false,
  tooltip = '',
  description = '',
  ...rest
}: InputProps & {
  ref?: React.RefObject<HTMLInputElement | null>;
  inputProps?: TextFieldProps['inputProps'];
}) {
  const { control, formState } = useFormContext();
  const inputRef = useRef<HTMLInputElement | null>(null);
  useImperativeHandle(ref, () => {
    return inputRef.current as HTMLInputElement;
  });
  const error = get(formState.errors, name)?.message as string;

  return (
    <Controller
      name={name}
      control={control}
      rules={rules}
      render={({ field }) => (
        <Box sx={{ width: '100%', ...wrapperStyle }}>
          {!!label && (
            <FormLabel required={required} tooltip={tooltip} description={description}>
              {label}
            </FormLabel>
          )}
          <TextField
            fullWidth
            error={!!get(formState.errors, name)}
            helperText={errorPosition === 'bottom' && error ? error : ''}
            placeholder={placeholder}
            size="small"
            {...field}
            {...rest}
            inputRef={inputRef}
            slotProps={{
              htmlInput: inputProps,
              input: Object.assign(
                rest.InputProps || {},
                errorPosition === 'right' && error ? { endAdornment: <FormInputError error={error} /> } : {}
              ),
            }}
          />
        </Box>
      )}
    />
  );
}
