import { clsx } from 'clsx';
import messages from './Label.messages';
import { useIntl } from 'react-intl';
import Body from '../body';
import { CommonProps } from '../common';
import { forwardRef, PropsWithChildren } from 'react';

export type LabelProps = {
  id?: string;
  htmlFor?: string;
  className?: string;
  children?: React.ReactNode;
};

/**
 * Avoid using `<Label>` component directly
 * it's for edge cases when `<Field />` isn't suitable for some reasons.
 *
 * Example:
 * ```
 * <Field label={..} description={..} required={..}>..</Field>
 * ```
 */
const Label = forwardRef<HTMLLabelElement, LabelProps>(
  ({ className, children, htmlFor, id }: LabelProps, ref) => {
    return (
      <label
        ref={ref}
        id={id}
        htmlFor={htmlFor}
        className={clsx(
          'np-label d-flex flex-column np-text-body-default-bold text-primary m-b-0',
          className,
        )}
      >
        {children}
      </label>
    );
  },
);

Label.displayName = 'Label';

export type LabelOptionalProps = PropsWithChildren<CommonProps>;

const Optional = function Optional({ children, className }: LabelOptionalProps) {
  const { formatMessage } = useIntl();
  return (
    <div>
      {children}
      <Body as="span" className={clsx('text-secondary', 'm-l-1', className)}>
        {formatMessage(messages.optionalLabel)}
      </Body>
    </div>
  );
};

export type LabelDescriptionProps = PropsWithChildren<CommonProps> & { id?: string };

const Description = function Description({ id, children, className }: LabelDescriptionProps) {
  return children ? (
    <Body id={id} className={clsx('text-secondary', className)}>
      {children}
    </Body>
  ) : null;
};

// eslint-disable-next-line functional/immutable-data
const LabelNamespace = Object.assign(Label, { Optional, Description });

export { LabelNamespace as Label };
