/* eslint-disable no-underscore-dangle */
/* eslint-disable import/no-unresolved */
import Visibility from '@mui/icons-material/Visibility'
import VisibilityOff from '@mui/icons-material/VisibilityOff'
import IconButton from '@mui/material/IconButton'
import InputAdornment from '@mui/material/InputAdornment'
import MenuItem from '@mui/material/MenuItem'
import TextField from '@mui/material/TextField'
import { useTheme } from '@mui/styles'
import { FieldInputProps, FormikProps } from 'formik'
import _get from 'lodash/get'
import _includes from 'lodash/includes'
import _isFunction from 'lodash/isFunction'
import _isObject from 'lodash/isObject'
import _map from 'lodash/map'
import React, { useEffect, useRef, useState } from 'react'

export interface ISelectOption {
  label: string | number;
  value?: string | number;
  [key: string]: any;
}

export interface ICustomField {
  onChange?: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
  label: string;
  field: FieldInputProps<any>;
  form: FormikProps<any>;
  theme: 'dark' | 'light';
  // optional
  type?: string;
  selectOptions?: ISelectOption[];
  inputRef?:
    | { current: HTMLInputElement | null }
    | ((node: HTMLInputElement | null) => void);
  multiline?: boolean;
  minRows?: string | number;
  maxRows?: string | number;
}

export interface IOtherProps {
  [key: string]: any;
}

export const CustomField = ({
  label,
  type = 'text',
  field,
  selectOptions = [] as ISelectOption[],
  form: { touched, errors, submitCount },
  theme,
  inputProps: pInputProps = {},
  InputProps = {},
  inputRef,
  onChange,
  multiline = false,
  minRows = 3,
  maxRows,
  disabled,
}: ICustomField & IOtherProps) => {
  const [isShrinked, setIsShrinked] = useState(Boolean(field.value))
  const [showPassword, setShowPassword] = useState(false)
  const _ref = useRef<HTMLInputElement>(null)
  const isAutoFilled = _ref.current?.matches ? _ref.current?.matches(':-webkit-autofill') : false
  const isSelectField = type === 'select'
  const isPasswordField = type === 'password'
  const error = _get(errors, field.name)
  const isTouched =
    Boolean(_get(touched, field.name)) ||
    (_includes(field.name, 'holder') && !!error && !!submitCount)

  const customTheme: any = useTheme()
  const inputProps: any = { sx: customTheme?.input }

  const handleClickShowPassword = () => {
    setShowPassword(!showPassword)
  }

  const handleMouseDownPassword = (event: React.MouseEvent<HTMLButtonElement>) => {
    event.preventDefault()
  }

  const finalInputProps = isPasswordField
    ? {
        ...InputProps,
        endAdornment: (
          <InputAdornment position="end">
            <IconButton
              aria-label="toggle password visibility"
              onClick={handleClickShowPassword}
              onMouseDown={handleMouseDownPassword}
              edge="end"
              size="small"
              sx={{ color: customTheme?.input?.color || 'inherit' }}
            >
              {showPassword ? <VisibilityOff /> : <Visibility />}
            </IconButton>
          </InputAdornment>
        ),
      }
    : InputProps

  useEffect(() => {
    if (_isFunction(inputRef)) {
      inputRef(_ref.current)
    } else if (_isObject(inputRef)) {
      inputRef.current = _ref.current
    }
  })

  return (
    <TextField
      disabled={disabled}
      placeholder=""
      id={field.name}
      label={label}
      type={isPasswordField ? (showPassword ? 'text' : 'password') : type}
      select={isSelectField}
      fullWidth={true}
      error={!!error && isTouched}
      helperText={isTouched && error}
      onFocus={() => {
        setIsShrinked(true)
      }}
      SelectProps={{
        native: false,
        className: theme,
        MenuProps: {
          className: theme,
          PaperProps: {
            sx: {
              '& .MuiMenuItem-root': {
                paddingLeft: '16px',
                paddingRight: '16px',
              },
            },
          },
        },
      }}
      InputLabelProps={{
        sx: customTheme?.input,
        shrink: isSelectField || isShrinked || Boolean(field.value) || isAutoFilled,
      }}
      InputProps={finalInputProps}
      inputProps={{ ...inputProps, ...pInputProps }}
      inputRef={_ref}
      multiline={multiline}
      minRows={minRows}
      maxRows={maxRows}
      {...field}
      onBlur={(e: React.FocusEvent<any, Element>) => {
        setIsShrinked(Boolean(field.value))
        if (field.onBlur) {
          field.onBlur(e)
        }
      }}
      onChange={onChange ?? field.onChange}
    >
      {isSelectField
        ? _map(selectOptions, option => (
            <MenuItem key={option.value} value={option.value} disabled={option.disabled}>
              {option.label}
            </MenuItem>
          ))
        : null}
    </TextField>
  )
}
