/**
 * toast.js
 * show toast and handle click + fadeout
 *
 */
import ElementHelpers from '../helpers/element-helpers';
import trapFocus from '../helpers/trapFocus';

/**
 * Declare constants
 */
const attributeBase = 'data-rs-toast';

export class Toast {
  constructor(element) {
    this.element = element;
    this.id = this.element.getAttribute(attributeBase);
    this.triggerElement = ElementHelpers.getElementByAttribute(
      this.attributes.show,
      this.id
    );
    this.closeElement = ElementHelpers.getElementByAttribute(
      'data-rs-closable',
      `${attributeBase}-${this.id}`
    );
    this.addEventHandlers();
    this.closeTimeout;
    this.toastOpen;
    this.keystroke = 0;
  }

  /**
   * Declare attribute constants
   */
  get attributes() {
    return {
      show: `${attributeBase}-show`
    };
  }

  /**
   * Declare classes
   */
  get classes() {
    return {
      image: `${attributeBase}-image`,
      show: 'show',
      closableClosed: 'closable--closed',
      toastActive: 'toast--active'
    };
  }

  /**
   * Add event handlers
   */
  addEventHandlers() {
    // handle click trigger element
    this.triggerElement.addEventListener('click', (clickEvent) => {
      clickEvent.preventDefault();
      this.show();
      this.destroyCloseTimeout();
      this.createCloseTimeOut();
    });
    this.closeElement.addEventListener('click', () => {
      this.keystroke = 0;
    });

    this.element.addEventListener('mouseenter', () => {
      this.destroyCloseTimeout();
    });
    this.element.addEventListener('mouseleave', () => {
      this.closeTimeout = this.createCloseTimeOut();
    });
    document.addEventListener('keydown', (keydownEvent) => {
      this.handleButtonKeys(keydownEvent);
    });
    this.closeElement.addEventListener('click', () => {
      this.keystroke = 0;
      this.toastOpen = false;
    });
  }

  show() {
    this.toastOpen = true;
    this.element.classList.remove(this.classes.closableClosed);
    this.element.classList.add(this.classes.show);
    this.element.classList.add(this.classes.toastActive);
  }

  hide() {
    this.toastOpen = false;
    this.element.classList.remove(this.classes.show);
    this.element.classList.remove(this.classes.toastActive);
    this.element.classList.add(this.classes.closableClosed);
    this.keystroke = 0;
  }

  /**
   * Create close time out - closes element if pointer is not on element
   */
  createCloseTimeOut() {
    this.closeTimeout = setTimeout(() => {
      if (!ElementHelpers.isMouseOver(this.element)) {
        this.hide();
      }
    }, 10000);
  }

  /**
   * Handle button keys - handle key presses escape
   *
   * @param {Event} event - event triggered
   */
  handleButtonKeys(event) {
    if (event != null) {
      switch (ElementHelpers.getKeyCodeOnKeyDownEvent(event)) {
        case 'Tab':
          trapFocus(event, this.element, this.toastOpen, this.keystroke);
          if (this.toastOpen) {
            this.keystroke++;
          }
          if (!this.toastOpen) {
            this.keystroke = 0;
          }
          break;

        case 'Escape':
          if (this.toastOpen) {
            this.hide();
            if (this.triggerElement) {
              this.triggerElement.focus();
            }
          }

          if (!this.toastOpen) {
            this.keystroke = 0;
          }
      }
    }
  }

  /**
   * Destroy close time out - closes element if pointer is not on element
   */
  destroyCloseTimeout() {
    clearTimeout(this.closeTimeout);
  }

  /**
   * Get selector
   */
  static getSelector() {
    return `[${attributeBase}]`;
  }
}
