import clsx from 'clsx';
import React, { useState } from 'react';
import { IconName, Icons } from '../Icons';
import { Message, MessageType } from '../Message';
import classes from './MessageBar.scss';

export interface MessageBarProps {
  /** Context to convey */
  title: string | React.ReactNode;
  /** Message type. default: ('error') */
  type?: Extract<MessageType, 'error' | 'info' | 'warning'>;
  /** If set, renders a close icon that will emit this callback. default: (undefined) */
  onClose?: () => void;
  /** If set, renders a retry icon that will emit this callback. default: (undefined) */
  onRetry?: () => void;
}

/**
 * Renders a contextual feedback message
 * Takes optional children which will be hidden by default. If the child is only a string, it will be wrapped in a `<p>` element.
 * @example
 * <MessageBar type="error" title="An error has occurred" onClose={onCloseHandler} />
 */
export const MessageBar: React.FC<MessageBarProps> = ({
  children,
  type = 'error',
  title,
  onClose,
  onRetry,
}) => {
  const [isBodyOpen, setIsBodyOpen] = useState<boolean>(false);

  const interactive: JSX.Element = (
    <div className={classes.interactive}>
      {children && (
        <div
          className={clsx(classes.iconWrapper, classes.detailsIcon)}
          onClick={() => setIsBodyOpen(!isBodyOpen)}
          data-test-id="message-bar-details-button"
        >
          <Icons
            icon={IconName.Details}
            className={clsx(classes.detIcon, {
              [classes.open]: isBodyOpen,
            })}
          />
        </div>
      )}
      {onRetry !== undefined && (
        <div
          className={clsx(classes.iconWrapper, classes.retryIcon)}
          onClick={onRetry}
          data-test-id="message-bar-retry-button"
        >
          <Icons icon={IconName.Retry} className={classes.reIcon} />
        </div>
      )}
      {onClose !== undefined && (
        <div
          className={clsx(classes.iconWrapper, classes.closeIcon)}
          onClick={onClose}
          data-test-id="message-bar-close-button"
        >
          <Icons icon={IconName.X} className={classes.xIcon} />
        </div>
      )}
    </div>
  );

  return (
    <Message
      title={title}
      type={type}
      header={interactive}
      isBodyOpen={isBodyOpen}
      dataTestId="message-bar"
    >
      {children && isBodyOpen && (
        <div
          className={clsx(classes.body, {
            [classes.hasInfo]: type === 'info',
            [classes.hasWarning]: type === 'warning',
            [classes.hasError]: type === 'error',
          })}
          data-test-id="message-bar-details"
        >
          {getChildren(children)}
        </div>
      )}
    </Message>
  );
};

/**
 * If children is just a 'string', will wrap it in 'p' tags, otherwise will just return children.
 * @param child component's children
 * @returns React.ReactNode
 */
const getChildren = (child: React.ReactNode): React.ReactNode => {
  return typeof child === 'string' ? (
    <div className={classes.textChild}>{child}</div>
  ) : (
    child
  );
};
