import { clsx } from 'clsx';
import { forwardRef, HTMLAttributes } from 'react';

import { Typography, BodyTypes } from '../common/propsValues/typography';

const DEFAULT_TYPE = Typography.BODY_DEFAULT;

const bodyTypes = new Set<BodyTypes>([
  Typography.BODY_DEFAULT,
  Typography.BODY_DEFAULT_BOLD,
  Typography.BODY_LARGE,
  Typography.BODY_LARGE_BOLD,
]);

type Props = HTMLAttributes<HTMLSpanElement | HTMLParagraphElement> & {
  /** @default 'body-default' */
  type?: BodyTypes;
  /** @default 'div' */
  as?: 'span' | 'p' | 'div';
  /**
   * When true, preserves newline characters in the text
   * @default false
   */
  preserveNewlines?: boolean;
};

const Body = forwardRef(function Body(
  { as: Element = 'div', type = DEFAULT_TYPE, className, preserveNewlines, ...props }: Props,
  reference: React.ForwardedRef<
    | {
        [key in typeof Element]: React.ElementRef<key>;
      }[typeof Element]
    | null
  >,
) {
  const isTypeSupported = bodyTypes.has(type);
  return (
    <Element
      {...props}
      // @ts-expect-error TODO: Remove when component could be rewritten with generics
      // See: https://fettblog.eu/typescript-react-generic-forward-refs/
      ref={reference}
      className={clsx(
        `np-text-${isTypeSupported ? type : DEFAULT_TYPE}`,
        preserveNewlines && 'np-text--pre-line',
        className,
      )}
    />
  );
});

export default Body;
