import React from 'react';
import { Controller, useFormContext } from 'react-hook-form';

import Box from '@mui/material/Box';
import Chip from '@mui/material/Chip';
import Select from '@mui/material/Select';
import Checkbox from '@mui/material/Checkbox';
import MenuItem from '@mui/material/MenuItem';
import TextField from '@mui/material/TextField';
import InputLabel from '@mui/material/InputLabel';
import FormControl from '@mui/material/FormControl';
import FormHelperText from '@mui/material/FormHelperText';

import { IRHFSelectProps, IRHFMultiSelectProps } from '../types';

/**
 * @description {RHFSelect} - Renders a controlled select component with React Hook Form integration.
 * @param {IRHFSelectProps} name - The name of the select field
 * @param {boolean} native - If true, the select component will be rendered as a native select element
 * @param {number} maxHeight - The maximum height of the select component's dropdown menu
 * @param {string} helperText - The helper text to be displayed below the select component
 * @param {ReactNode} children - The options to be rendered within the select component
 * @param {object} PaperPropsSx - Additional styling props for the Paper component
 * @param {...other} - Additional props to be spread onto the TextField component
 * @return {ReactNode} The controlled select component
 */
export const RHFSelect = ({
  name,
  native,
  maxHeight = 220,
  helperText,
  children,
  PaperPropsSx,
  ...other
}: IRHFSelectProps) => {
  const { control } = useFormContext();

  return (
    <Controller
      name={name}
      control={control}
      render={({ field, fieldState: { error } }) => (
        <TextField
          {...field}
          select
          fullWidth
          SelectProps={{
            native,
            MenuProps: {
              PaperProps: {
                sx: {
                  ...(!native && {
                    maxHeight: typeof maxHeight === 'number' ? maxHeight : 'unset',
                  }),
                  ...PaperPropsSx,
                },
              },
            },
            sx: { textTransform: 'capitalize' },
          }}
          error={!!error}
          helperText={error ? error?.message : helperText}
          {...other}
        >
          {children}
        </TextField>
      )}
    />
  );
};

/**
 * @description {RHFMultiSelect} - Renders a multi-select component using React Hook Form.
 * @param {IRHFMultiSelectProps} name - The name of the multi-select component
 * @param {boolean} chip - Whether to display the selected items as chips
 * @param {string} label - The label for the multi-select component
 * @param {array} options - The options to be displayed in the multi-select component
 * @param {boolean} checkbox - Whether to display checkboxes next to the options
 * @param {string} placeholder - The placeholder text for the multi-select component
 * @param {string} helperText - The helper text to be displayed below the component
 * @param {...other} other - Additional props to be spread on the component
 * @return {JSX.Element} The rendered multi-select component
 */
export const RHFMultiSelect = ({
  name,
  chip,
  label,
  options,
  checkbox,
  placeholder,
  helperText,
  ...other
}: IRHFMultiSelectProps) => {
  const { control } = useFormContext();

  const renderValues = (selectedIds: string[]) => {
    const selectedItems = options.filter((item) => selectedIds.includes(item.value));

    if (!selectedItems.length && placeholder) {
      return <Box sx={{ color: 'text.disabled' }}>{placeholder}</Box>;
    }

    if (chip) {
      return (
        <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
          {selectedItems.map((item) => (
            <Chip key={item.value} size="small" label={item.label} />
          ))}
        </Box>
      );
    }

    return selectedItems.map((item) => item.label).join(', ');
  };

  return (
    <Controller
      name={name}
      control={control}
      render={({ field, fieldState: { error } }) => (
        <FormControl error={!!error} {...other}>
          {label && <InputLabel id={name}> {label} </InputLabel>}

          <Select
            {...field}
            multiple
            displayEmpty={!!placeholder}
            id={`multiple-${name}`}
            labelId={name}
            label={label}
            renderValue={renderValues}
          >
            {options.map((option) => {
              const selected = field.value.includes(option.value);

              return (
                <MenuItem key={option.value} value={option.value}>
                  {checkbox && <Checkbox size="small" disableRipple checked={selected} />}

                  {option.label}
                </MenuItem>
              );
            })}
          </Select>

          {(!!error || helperText) && (
            <FormHelperText error={!!error}>{error ? error?.message : helperText}</FormHelperText>
          )}
        </FormControl>
      )}
    />
  );
};
