import classNames from 'clsx';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';

import Button from '../button/button';
import { ButtonThemes } from '../button/useButtonStyles';
import IconButton from '../icon-button/icon-button';
import Stack from '../stack/stack';

const messages = defineMessages({
  close: { id: 'lightbox.close', defaultMessage: 'Close' },
  confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
});

const widths = {
  xs: 'max-w-xs',
  sm: 'max-w-sm',
  md: 'max-w-base',
  lg: 'max-w-lg',
  xl: 'max-w-xl',
  '2xl': 'max-w-2xl',
  '3xl': 'max-w-3xl',
  '4xl': 'max-w-4xl',
};

interface IModal {
  /** Callback when the modal is cancelled. */
  cancelAction?: () => void,
  /** Cancel button text. */
  cancelText?: React.ReactNode,
  /** URL to an SVG icon for the close button. */
  closeIcon?: string,
  /** Position of the close button. */
  closePosition?: 'left' | 'right',
  /** Callback when the modal is confirmed. */
  confirmationAction?: (event?: React.MouseEvent<HTMLButtonElement>) => void,
  /** Whether the confirmation button is disabled. */
  confirmationDisabled?: boolean,
  /** Confirmation button text. */
  confirmationText?: React.ReactNode,
  /** Confirmation button theme. */
  confirmationTheme?: ButtonThemes,
  /** Callback when the modal is closed. */
  onClose?: () => void,
  /** Callback when the secondary action is chosen. */
  secondaryAction?: (event?: React.MouseEvent<HTMLButtonElement>) => void,
  /** Secondary button text. */
  secondaryText?: React.ReactNode,
  secondaryDisabled?: boolean,
  /** Don't focus the "confirm" button on mount. */
  skipFocus?: boolean,
  /** Title text for the modal. */
  title?: React.ReactNode,
  width?: keyof typeof widths,
}

/** Displays a modal dialog box. */
const Modal: React.FC<IModal> = ({
  cancelAction,
  cancelText,
  children,
  closeIcon = require('@tabler/icons/x.svg'),
  closePosition = 'right',
  confirmationAction,
  confirmationDisabled,
  confirmationText,
  confirmationTheme,
  onClose,
  secondaryAction,
  secondaryDisabled = false,
  secondaryText,
  skipFocus = false,
  title,
  width = 'xl',
}) => {
  const intl = useIntl();
  const buttonRef = React.useRef<HTMLButtonElement>(null);

  React.useEffect(() => {
    if (buttonRef?.current && !skipFocus) {
      buttonRef.current.focus();
    }
  }, [skipFocus, buttonRef]);

  return (
    <div data-testid='modal' className={classNames('block w-full p-6 mx-auto text-start align-middle transition-all transform bg-white dark:bg-primary-900 text-gray-900 dark:text-gray-100 shadow-xl rounded-2xl pointer-events-auto', widths[width])}>
      <div className='sm:flex sm:items-start w-full justify-between'>
        <div className='w-full'>
          {title && (
            <div
              className={classNames('w-full flex items-center gap-2', {
                'flex-row-reverse': closePosition === 'left',
              })}
            >
              <h3 className='flex-grow text-lg leading-6 font-bold text-gray-900 dark:text-white'>
                {title}
              </h3>

              {onClose && (
                <IconButton
                  src={closeIcon}
                  title={intl.formatMessage(messages.close)}
                  onClick={onClose}
                  className='text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200'
                />
              )}
            </div>
          )}

          {title ? (
            <div className='w-full mt-2'>
              {children}
            </div>
          ) : children}
        </div>
      </div>

      {confirmationAction && (
        <div className='mt-5 flex flex-row justify-between' data-testid='modal-actions'>
          <div className='flex-grow'>
            {cancelAction && (
              <Button
                theme='tertiary'
                onClick={cancelAction}
              >
                {cancelText || 'Cancel'}
              </Button>
            )}
          </div>

          <Stack space={2}>
            {secondaryAction && (
              <Button
                theme='secondary'
                onClick={secondaryAction}
                disabled={secondaryDisabled}
              >
                {secondaryText}
              </Button>
            )}

            <Button
              theme={confirmationTheme || 'primary'}
              onClick={confirmationAction}
              disabled={confirmationDisabled}
              ref={buttonRef}
            >
              {confirmationText}
            </Button>
          </Stack>
        </div>
      )}
    </div>
  );
};

export default Modal;
