import React, { type ReactNode, useImperativeHandle, useRef } from 'react';
import { Box, InputAdornment, TextField, Typography, Stack, useMediaQuery, useTheme } 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;
  layout?: 'vertical' | 'horizontal';
};

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 = '',
  layout = 'vertical',
  slotProps,
  ...rest
}: InputProps & {
  ref?: React.RefObject<HTMLInputElement | null>;
  inputProps?: TextFieldProps['inputProps'];
}) {
  const { control, formState } = useFormContext();
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
  const inputRef = useRef<HTMLInputElement | null>(null);

  useImperativeHandle(ref, () => {
    return inputRef.current as HTMLInputElement;
  });

  const error = get(formState.errors, name)?.message as string;
  const isHorizontal = layout === 'horizontal' && !isMobile;

  const mergedSlotProps = {
    htmlInput: { ...inputProps, ...slotProps?.htmlInput },
    input: Object.assign(
      rest.InputProps || {},
      slotProps?.input || {},
      errorPosition === 'right' && error ? { endAdornment: <FormInputError error={error} /> } : {}
    ),
  };

  const renderLabel = () => {
    if (!label) return null;
    return (
      <FormLabel
        required={required}
        tooltip={tooltip}
        description={description}
        boxSx={isHorizontal ? { width: 'fit-content', whiteSpace: 'nowrap', minWidth: 'fit-content' } : undefined}>
        {label}
      </FormLabel>
    );
  };

  return (
    <Controller
      name={name}
      control={control}
      rules={rules}
      render={({ field }) => (
        <Box sx={{ width: '100%', ...wrapperStyle }}>
          {isHorizontal ? (
            <Stack
              direction="row"
              spacing={2}
              sx={{
                alignItems: 'center',
                justifyContent: 'space-between',
              }}>
              {renderLabel()}
              <TextField
                fullWidth={false}
                error={!!error}
                helperText={errorPosition === 'bottom' && error ? error : ''}
                placeholder={placeholder}
                size="small"
                {...field}
                {...rest}
                inputRef={inputRef}
                slotProps={mergedSlotProps}
                sx={{
                  flex: 1,
                  ...rest.sx,
                }}
              />
            </Stack>
          ) : (
            <>
              {renderLabel()}
              <TextField
                fullWidth
                error={!!error}
                helperText={errorPosition === 'bottom' && error ? error : ''}
                placeholder={placeholder}
                size="small"
                {...field}
                {...rest}
                inputRef={inputRef}
                slotProps={mergedSlotProps}
              />
            </>
          )}
        </Box>
      )}
    />
  );
}
