import { useField } from 'formik';
import { useCallback } from 'react';

import { FormField } from '../../form/FormField/FormField';
import { FormFieldDirection } from '../../form/FormField/constants';
import { Radio, RadioProps } from '../../form/Radio/Radio';
import { assertEmptyObject } from '../../utils/assertEmptyObject';
import { makeTestId } from '../../utils/makeTestId';
import { CommonFormikProps } from '../common/types';
import { useFormikFieldsProps } from '../hooks/useFormikFieldsProps';

export interface FormikRadioProps extends CommonFormikProps<string>, Pick<RadioProps, 'value'> {}

/**
 * Formik field that allows changing some value by radio buttons.
 *
 * ```tsx
 * import { FormikRadio } from 'ui-kit';
 *
 * <FormikRadio name="type" value="subscribed" label="Subscribed" />
 * <FormikRadio name="type" value="unsubscribed" label="Unsubscribed" />
 * ```
 */
export function FormikRadio(props: FormikRadioProps) {
  const { value, ...rest } = props;

  const [, meta, helpers] = useField<string>(props.name);

  const { id, formFieldProps, controlProps } = useFormikFieldsProps<Pick<RadioProps, 'value'>>(rest);

  const {
    className,
    descriptionMessageId,
    description,
    errorMessageId,
    error,
    label,
    onHintClick,
    hintText,
    requirement,
    testId,
    ...restFormFieldProps
  } = formFieldProps;
  assertEmptyObject(restFormFieldProps);

  const {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    value: inputValue,
    onChange,
    onBlur,
    ariaErrorMessage,
    ariaDescribedBy,
    ariaInvalid,
    ariaLabel,
    disabled,
    ariaRequired,
    required,
    ...restControlProps
  } = controlProps;
  assertEmptyObject(restControlProps);

  const handleChange = useCallback(
    (isChecked: boolean) => {
      /* istanbul ignore else */
      if (isChecked) {
        helpers.setValue(value);
        onChange?.(value);
      }
    },
    [helpers, value, onChange],
  );

  return (
    <FormField
      className={className}
      description={description}
      descriptionMessageId={descriptionMessageId}
      direction={FormFieldDirection.Horizontal}
      error={error}
      errorMessageId={errorMessageId}
      hintText={hintText}
      id={id}
      label={label}
      onHintClick={onHintClick}
      requirement={requirement}
      testId={testId}
    >
      <Radio
        ariaDescribedBy={ariaDescribedBy}
        ariaErrorMessage={ariaErrorMessage}
        ariaInvalid={ariaInvalid}
        ariaLabel={ariaLabel}
        ariaRequired={ariaRequired}
        checked={meta.value === value}
        disabled={disabled}
        id={id}
        onBlur={onBlur}
        onChange={handleChange}
        required={required}
        testId={makeTestId(testId, 'radio')}
        value={value}
      />
    </FormField>
  );
}
