import { type FC } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';

import { uniqBy } from 'lodash-es';
import Add from '@material-hu/icons/material/Add';
import FormHelperText from '@material-hu/mui/FormHelperText';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import Button from '@material-hu/components/design-system/Buttons/Button';

import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  Option,
  type OptionProps,
} from 'src/components/FormInputs/FormOptions/Option';
import { OptionReadOnly } from 'src/components/FormInputs/FormOptions/OptionReadOnly';
import {
  FormOptionsTypes,
  type OptionField,
  type Option as OptionType,
} from 'src/components/FormInputs/FormOptions/types';

export type FormOptionsProps = Omit<
  OptionProps,
  'name' | 'min' | 'type' | 'index' | 'getOptionName' | 'optionsName' | 'label'
> & {
  name: string;
  onRemove?: (index: number) => void;
  onAdd?: () => void;
  getNewOption?: (index: number) => OptionType;
  type?: FormOptionsTypes;
  min?: number;
  readOnly?: boolean;
  showAdd?: boolean;
  showErrors?: boolean;
  label?: string;
  optionLabel?: string;
  addLabel?: string;
};

export const FormOptions: FC<FormOptionsProps> = props => {
  const {
    name,
    onAdd = () => null,
    getNewOption = () => ({ value: '', checked: false }),
    type = FormOptionsTypes.RADIO,
    min = 1,
    readOnly = false,
    showAdd = true,
    color = 'primary',
    allowRepeated = false,
    ignoreMinChecked = false,
    minChecked = 1,
    showErrors: showErrorsProp = true,
    label,
    optionLabel,
    onRemove = (_idx: number) => null,
    addLabel,
    ...optionProps
  } = props;

  const { t } = useLokaliseTranslation('backoffice_only');
  const { control, watch } = useFormContext();

  const { fields, append, remove } = useFieldArray({ name, control });

  const optionsFields = fields as OptionField[];
  const options: OptionField[] = watch(name);

  const uniqOptions = uniqBy(options, 'value');
  const isRepeated = options.length > uniqOptions.length;

  const countChecked = options.filter(option => option.checked).length;
  const isMinChecked = countChecked < minChecked;

  const handleRemove = (index: number) => () => {
    remove(index);
    onRemove(index);
  };

  const handleAdd = (index: number) => () => {
    append(getNewOption(index));
    onAdd();
  };

  const getOptionName = (index: number) => `${name}.${index}`;

  if (readOnly) {
    return (
      <Stack sx={{ gap: 2 }}>
        {optionsFields.map((option, index) => (
          <OptionReadOnly
            key={option.id}
            option={option}
            index={index}
            type={type}
            color={color}
          />
        ))}
      </Stack>
    );
  }

  const isRepeatedError = !allowRepeated && isRepeated;
  const isMinCheckedError = !ignoreMinChecked && isMinChecked;
  const isError = isRepeatedError || isMinCheckedError;
  const showErrors = showErrorsProp && isError;

  return (
    <Stack
      sx={{
        gap: 2,
      }}
    >
      {label && (
        <Typography
          id="form-options-label"
          variant="body2"
        >
          {label}
        </Typography>
      )}
      <Stack
        aria-labelledby="form-options-label"
        sx={{
          gap: 1,
        }}
      >
        {optionsFields.map((option, index) => (
          <Option
            optionsName={name}
            name={getOptionName(index)}
            getOptionName={getOptionName}
            key={option.id}
            index={index}
            type={type}
            min={min}
            onRemove={handleRemove(index)}
            color={color}
            allowRepeated={allowRepeated}
            ignoreMinChecked={ignoreMinChecked}
            minChecked={minChecked}
            showErrors={showErrorsProp}
            label={optionLabel}
            {...optionProps}
          />
        ))}
      </Stack>
      {showAdd && (
        <Button
          id="form-options-add-button"
          variant="text"
          startIcon={<Add />}
          onClick={handleAdd(optionsFields.length)}
          sx={{
            width: 'fit-content',
          }}
        >
          {addLabel || t('backoffice_only:form_options.new_option')}
        </Button>
      )}
      {showErrors && (
        <Stack id="errors">
          {isRepeatedError && (
            <FormHelperText
              id="error-repeated"
              error
              sx={{ ml: 4 }}
            >
              {t('backoffice_only:form_options.error_repeated')}
            </FormHelperText>
          )}
          {isMinCheckedError && (
            <FormHelperText
              id="error-min"
              error
              sx={{ ml: 4 }}
            >
              {t('backoffice_only:form_options.error_min_checked', {
                count: minChecked,
              })}
            </FormHelperText>
          )}
        </Stack>
      )}
    </Stack>
  );
};

export default FormOptions;
