import { FormField } from '../../form/FormField/FormField';
import {
  GeneralSelectFieldProps,
  SelectField,
  SelectFieldOptions,
  SelectFieldProps,
} from '../../form/SelectField/SelectField';
import { SelectOption } from '../../form/SelectField/types';
import { GeneralFormControlProps } from '../../form/types';
import { assertEmptyObject } from '../../utils/assertEmptyObject';
import { makeTestId } from '../../utils/makeTestId';
import { CommonFormikProps } from '../common/types';
import { useFormikFieldsProps } from '../hooks/useFormikFieldsProps';

export type FormikSelectFieldProps<Option extends SelectOption = SelectOption> = Omit<
  CommonFormikProps<any>,
  'onChange'
> &
  (
    | {
        multiple?: false;
        /**
         * If this prop is `true` then {@link FormikSelectField} will contain clear button
         * that allow to reset value to the `null`.
         */
        cleanable?: boolean;
        onChange?: (value: Option['value'] | null) => void;
      }
    | {
        multiple: true;
        onChange?: (value: Option['value'][]) => void;
      }
  ) &
  Omit<GeneralSelectFieldProps<Option>, keyof GeneralFormControlProps<any, any>> &
  SelectFieldOptions<Option>;

/**
 * Formik field that allows select some value from given options.
 *
 * ```tsx
 * import { FormikSelectField } from 'ui-kit';
 *
 * const options: DefaultOption[] = [
 *   {
 *     value: 'one',
 *     label: 'One',
 *   },
 *   {
 *     value: 'two',
 *     label: 'Two',
 *   },
 *   {
 *     value: 'tree',
 *     label: 'Tree',
 *   },
 * ];
 *
 * <FormikSelectField name="type" label="Type" options={options} />
 * ```
 */
export function FormikSelectField<Option extends SelectOption = SelectOption>(
  props: FormikSelectFieldProps<Option>,
) {
  // If someone want to spend 2 weeks for typing fixing just remove `any` and you will
  // have a lot of funny work hours.
  const { id, formFieldProps, controlProps } = useFormikFieldsProps<SelectFieldProps<Option>>(props as any);

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

  return (
    <FormField
      className={className}
      description={description}
      descriptionMessageId={descriptionMessageId}
      error={error}
      errorMessageId={errorMessageId}
      hintText={hintText}
      id={id}
      label={label}
      onHintClick={onHintClick}
      requirement={requirement}
      testId={testId}
    >
      {/* eslint-disable-next-line react/jsx-props-no-spreading */}
      <SelectField<Option> id={id} {...controlProps} testId={makeTestId(testId, 'select-field')} />
    </FormField>
  );
}
