'use client';

import type * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { useMergeProps } from '../../hooks/useMergeProps';
import { warnOnce } from '../../lib/warnOnce';
import { withLabelClickWrapper } from '../../lib/withLabelClickWrapper';
import type { HasDataAttribute, HasRootRef } from '../../types';
import { SelectionControl } from '../SelectionControl/SelectionControl';
import { SelectionControlLabel } from '../SelectionControl/SelectionControlLabel/SelectionControlLabel';
import type { TappableOmitProps } from '../Tappable/Tappable';
import { RadioInput } from './RadioInput/RadioInput';
import styles from './Radio.module.css';

const warn = warnOnce('Radio');

export interface RadioProps
  extends Pick<
      React.InputHTMLAttributes<HTMLInputElement>,
      | 'checked'
      | 'defaultChecked'
      | 'disabled'
      | 'readOnly'
      | 'required'
      | 'autoFocus'
      | 'name'
      | 'value'
      | 'form'
      | 'onChange'
      | 'onFocus'
      | 'onBlur'
    >,
    Omit<React.LabelHTMLAttributes<HTMLLabelElement>, 'onChange' | 'onFocus' | 'onBlur'>,
    HasRootRef<HTMLLabelElement>,
    Pick<
      TappableOmitProps,
      'hoverMode' | 'activeMode' | 'hasHover' | 'hasActive' | 'focusVisibleMode'
    > {
  /**
   * Свойства, которые можно прокинуть внутрь компонента:
   * - `root`: свойства для прокидывания в корень компонента;
   * - `input`: свойства для прокидывания в скрытый `input`.
   */
  slotProps?:
    | {
        root?:
          | (Omit<React.LabelHTMLAttributes<HTMLLabelElement>, 'children'> &
              HasRootRef<HTMLLabelElement> &
              HasDataAttribute)
          | undefined;
        input?:
          | (React.ComponentProps<'input'> & HasRootRef<HTMLInputElement> & HasDataAttribute)
          | undefined;
      }
    | undefined;
  /**
   * @deprecated Since 7.9.0. Вместо этого используйте `slotProps={ input: { getRootRef: ... } }`.
   */
  getRef?: React.Ref<HTMLInputElement> | undefined;
  /**
   * Дополнительное описание под основным текстом.
   */
  description?: React.ReactNode | undefined;
  /**
   * Элемент после основного текста.
   */
  titleAfter?: React.ReactNode | undefined;
  /**
   * @deprecated Since 7.9.0. Вместо этого используйте `slotProps={ root: {...} }`.
   *
   * Позволяет передавать data-* аттрибуты элементу label.
   **/
  labelProps?: HasDataAttribute | undefined;
}

/**
 * @see https://vkui.io/components/radio
 */
export const Radio = ({
  // RadioProps
  children,
  description,
  titleAfter,
  labelProps,
  getRef,
  className,

  // Tappable props
  hoverMode,
  activeMode,
  hasHover,
  hasActive,
  focusVisibleMode,

  // Input props
  checked,
  defaultChecked,
  disabled,
  readOnly,
  required,
  autoFocus,
  id,
  name,
  value,
  form,
  onChange,
  onFocus,
  onBlur,

  slotProps,
  ...restProps
}: RadioProps): React.ReactNode => {
  /* istanbul ignore if: не проверяем в тестах */
  if (process.env.NODE_ENV === 'development') {
    if (labelProps) {
      warn('Свойство `labelProps` устаревшее, используйте `slotProps={ root: {...} }`');
    }
    if (getRef) {
      warn('Свойство `getRef` устаревшее, используйте `slotProps={ input: { getRootRef: ... } }`');
    }
  }

  const { onClick: onRootClick, ...rootRest } = useMergeProps(
    {
      className: classNames(styles.host, className),
      ...labelProps,
      ...restProps,
    },
    slotProps?.root ?? undefined,
  );

  const inputRest = useMergeProps(
    {
      getRootRef: getRef,
      checked,
      defaultChecked,
      disabled,
      readOnly,
      required,
      autoFocus,
      id,
      name,
      value,
      form,
      onChange,
      onFocus,
      onBlur,
    },
    slotProps?.input ?? undefined,
  );

  return (
    <SelectionControl
      hoverMode={hoverMode}
      activeMode={activeMode}
      hasHover={hasHover}
      hasActive={hasActive}
      focusVisibleMode={focusVisibleMode}
      disabled={inputRest.disabled}
      onClick={withLabelClickWrapper(onRootClick)}
      {...rootRest}
    >
      <RadioInput slotProps={{ input: inputRest }} />
      <SelectionControlLabel titleAfter={titleAfter} description={description}>
        {children}
      </SelectionControlLabel>
    </SelectionControl>
  );
};

Radio.Input = RadioInput;
