import { Button, Icon, Flex, LazyImage, ContextMenu, Markdown } from '@vizality/components';
import { getModule, contextMenu } from '@vizality/webpack';
import { joinClassNames } from '@vizality/util/dom';
import React, { memo } from 'react';

const { openContextMenu, closeContextMenu } = contextMenu;

/**
 *
 * @component
 */
const Content = memo(({ markdown, content }) => {
  const { thin } = getModule('thin');
  return (
    <div className={joinClassNames('vz-toast-content', thin)}>
      {markdown
        ? <Markdown source={content} />
        : content
      }
    </div>
  );
});

/**
 *
 * @component
 */
const CloseButton = memo(({ toastId }) => (
  <Icon
    name='close'
    size='20'
    className='vz-toast-close-wrapper'
    iconClassName='vz-toast-close'
    onClick={evt => evt.shiftKey ? vizality.api.notifications.closeAllActiveToasts() : vizality.api.notifications.closeToast(toastId)}
  />
));

/**
 *
 * @component
 */
const Header = memo(({ toastId, icon, markdown, header, content, buttons }) => {
  return (
    <div className='vz-toast-meta-wrapper'>
      {(icon?.url || icon?.name) && (
        <div className='vz-toast-decorator'>
          {icon.url && !icon.name && (
            <LazyImage
              src={icon.url}
              width={icon.size || '40'}
              height={icon.size || '40'}
              className='vz-toast-icon'
            />
          )}
          {icon.name && (
            <Icon
              size={icon.size || '40'}
              className='vz-toast-icon-wrapper'
              iconClassName='vz-toast-icon'
              color={icon.color}
              name={icon.name}
            />
          )}
        </div>
      )}
      <div className='vz-toast-meta'>
        <div className='vz-toast-header'>
          {markdown
            ? <Markdown source={header} />
            : header
          }
        </div>
        {!content && !buttons?.length && (
          <CloseButton toastId={toastId} />
        )}
        {content && <Content markdown={markdown} content={content} />}
      </div>
    </div>
  );
});

/**
 *
 * @component
 */
const Footer = memo(({ buttons }) => {
  const { horizontal } = getModule('buttonsWrapper', 'horizontal');
  const { marginTop20 } = getModule('marginTop20');
  return (
    <Flex className={joinClassNames('vz-toast-footer', marginTop20)}>
      <Flex className={joinClassNames('vz-toast-footer-buttons', horizontal)} justify={Flex.Justify.END}>
        {buttons.map((button, i) => {
          const btnProps = {};
          [ 'size', 'look', 'color' ].forEach(prop => {
            if (button[prop]) {
              const value = button[prop].includes('-')
                ? button[prop]
                : Button[`${prop.charAt(0).toUpperCase() + prop.slice(1)}s`][button[prop].toUpperCase()];
              if (value) {
                btnProps[prop] = value;
              }
            }
          });

          if (!btnProps.size) {
            btnProps.size = Button.Sizes.SMALL;
          }

          return (
            <Button
              key={i}
              {...btnProps}
              onClick={evt => {
                if (button.onClick) {
                  button.onClick(evt);
                }
              }}
            >
              {button.text}
            </Button>
          );
        })}
      </Flex>
    </Flex>
  );
});

/**
 *
 * @component
 */
export default memo(({ toast }) => {
  const Toast =
    typeof toast.custom === 'function'
      ? toast.custom
      : () => toast.custom;

  /**
   * We only need to insert a close button if it's not a custom toast, has content, and
   * the showCloseButton property is true.
   */
  if (toast.showCloseButton && !toast.custom && toast.content) {
    const CloseButton = {
      text: 'Dismiss',
      color: 'white',
      look: 'link',
      onClick: evt => evt.shiftKey ? vizality.api.notifications.closeAllActiveToasts() : vizality.api.notifications.closeToast(toast.id)
    };

    /**
     * If there are button(s) already, insert a close button into the beginning
     * of the array.
     */

    if (toast.buttons?.length) {
      /**
       * Let's give the close button the same size as the last button specified.
       */
      CloseButton.size = toast.buttons[toast.buttons.length - 1].size;
      toast.buttons.unshift(CloseButton);
    } else {
      CloseButton.text = 'Okay';
      CloseButton.color = 'white';
      CloseButton.look = 'filled';
      toast.buttons = [ CloseButton ];
    }
  }

  return (
    toast.custom
      ? <Toast {...toast.custom.props} />
      : (
        <div
          className='vz-toast-body-inner'
          vz-toast-id={toast.id}
          onContextMenu={evt => openContextMenu(evt, () => (
            <ContextMenu.Menu navId='dashboard-item' onClose={closeContextMenu}>
              <ContextMenu.Item
                id='close-toast'
                label='Close Toast'
                action={() => vizality.api.notifications.closeToast(toast.id)}
              />
              <ContextMenu.Item
                id='close-all-toasts'
                label='Close All Toasts'
                action={() => vizality.api.notifications.closeAllActiveToasts()}
              />
              <ContextMenu.Item
                id='view-toast-settings'
                label='View Toast Settings'
                action={() => vizality.api.routes.navigateTo('settings/notifications#toasts')}
              />
            </ContextMenu.Menu>
          ))}
        >
          <Header
            markdown={toast.markdown}
            image={toast.image}
            icon={toast.icon}
            buttons={toast.buttons}
            header={toast.header}
            toastId={toast.id}
            content={toast.content}
          />
          {toast.buttons?.length && (
            <Footer
              buttons={toast.buttons}
              toastId={toast.id}
              showCloseButton={toast.showCloseButton}
            />
          )}
        </div>
      )
  );
});
