import { ReactNode, useMemo } from 'react';

import { useTranslation } from '../../core/hooks/useTranslation';
import { useTestIdAttribute } from '../../hooks/useTestIdAttribute';
import { CommonProps, TestIdProps } from '../../types';
import { assertEmptyObject } from '../../utils/assertEmptyObject';
import { assertUnreachable } from '../../utils/assertUnreachable';
import { makeTestId } from '../../utils/makeTestId';
import { IconGlyph } from '../Icon/constants';

import { AlertDismissButton } from './components/AlertDismissButton/AlertDismissButton';
import { AlertAppearance } from './constants';
import { AlertContextProvider } from './contexts/AlertContext';
import { StyledAlert, StyledAlertContentColumn, TunedIcon } from './styled';

export interface AlertProps extends CommonProps, TestIdProps {
  /**
   * Visual {@link Alert} appearance.
   *
   * @default {@link AlertAppearance.Info}.
   */
  appearance?: AlertAppearance;
  /**
   * Function that ask {@link Alert} consumer to hide {@link Alert}.
   * For example, can be invoked, when user press Esc key button.
   */
  onDismiss?: () => void;
  children: ReactNode;
}

/**
 * Component that should be used for showing some notification.
 *
 * ```tsx
 * <Alert appearance={AlertAppearance.Info} onDismiss={handleDismiss}>
 *   <AlertTitle>Blandit aliquet</AlertTitle>
 *   <AlertContent>
 *     Lorem ipsum dolor sit amet, consectetur etur adipiscing elit. Fames blandit aliquet.
 *   </AlertContent>
 *   <AlertActions>
 *     <AlertAction onClick={handleFirstActionsClick}>Action 1</AlertAction>
 *     <AlertAction onClick={handleSecondActionsClick}>Action 2</AlertAction>
 *   </AlertActions>
 * </Alert>
 * ```
 *
 * ## Appearance
 *
 * {@link Alert} support 4 appearance, that can be changed by {@link AlertProps.appearance} prop:
 * - {@link AlertAppearance.Info}
 * - {@link AlertAppearance.Success}
 * - {@link AlertAppearance.Warning}
 * - {@link AlertAppearance.Error}
 *
 * ### Info appearance
 *
 * This appearance should be used for some unimportant notification. This is default appearance.
 *
 * <Story id="components-alert--info" />
 *
 * ### Success appearance
 *
 * This appearance should be used for notification about successful finished actions.
 *
 * <Story id="components-alert--success" />
 *
 * ### Warning appearance
 *
 * This appearance should be used for some important notification.
 *
 * <Story id="components-alert--warning" />
 *
 * ### Error appearance
 *
 * This appearance should be used only for showing error messages.
 *
 * <Story id="components-alert--error" />
 *
 * ## Content
 *
 * {@link Alert} should contains only one {@link AlertContent} component inside.
 *
 * Optionally {@link Alert} can contain {@link AlertTitle} component with title of {@link Alert} and
 * {@link AlertActions} component with up to two {@link AlertAction} component with {@link Alert} action
 * buttons.
 *
 * ## Dismiss button
 *
 * If {@link AlertProps.onDismiss} will be given, then dismiss button (cross button at top right angle) will
 * be shown and when a user clicks by this button the {@link AlertProps.onDismiss} method will be invoked.
 */
export function Alert(props: AlertProps) {
  const {
    appearance = AlertAppearance.Info,
    onDismiss,
    children,
    className,
    testId,
    ariaDescribedBy,
    ...rest
  } = props;
  assertEmptyObject(rest);

  const { t } = useTranslation();
  const testIdAttribute = useTestIdAttribute();

  const AlertIconGlyph = useMemo(() => {
    switch (appearance) {
      case AlertAppearance.Info:
        return IconGlyph.InfoSolid;
      case AlertAppearance.Success:
        return IconGlyph.CheckCircle;
      case AlertAppearance.Warning:
        return IconGlyph.Warning;
      case AlertAppearance.Error:
        return IconGlyph.Error;
      /* istanbul ignore next */
      default:
        assertUnreachable(appearance);
    }
  }, [appearance]);

  return (
    <AlertContextProvider appearance={appearance} onDismiss={onDismiss}>
      <StyledAlert
        $appearance={appearance}
        aria-describedby={ariaDescribedBy}
        aria-label={t(`ui.alert.${appearance}`)}
        className={className}
        role="alert"
        {...{ [testIdAttribute]: testId }}
      >
        <TunedIcon glyph={AlertIconGlyph} testId={makeTestId(testId, 'icon')} />
        <StyledAlertContentColumn>{children}</StyledAlertContentColumn>
        {onDismiss && (
          <AlertDismissButton onClick={onDismiss} testId={makeTestId(testId, 'dismiss-button')} />
        )}
      </StyledAlert>
    </AlertContextProvider>
  );
}
