/**
 * popover.js
 */
import ElementHelpers from '../helpers/element-helpers';
import trapFocus from '../helpers/trapFocus';

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

export class Popover {
  constructor(element) {
    this.element = element;
    this.trigger = ElementHelpers.getElementByAttribute(
      this.attributes.trigger,
      this.element.getAttribute(attributeBase)
    );
    this.overlay = ElementHelpers.getElementByAttribute(
      this.attributes.overlay
    );
    this.disableOverlay = this.element.hasAttribute(
      this.attributes.disableOverlay
    );
    this.popoverOpen;
    this.addEventHandlers();
    this.isOpenByDefault();
    this.keystroke = 0;
  }

  /**
   * Declare classes
   */
  get classes() {
    return {
      popoverActive: 'popover--active',
      modalOverlayActive: 'modal__overlay--active',
      active: 'active'
    };
  }

  /**
   * Declare attribute constants
   */
  get attributes() {
    return {
      overlay: `${attributeBase}-overlay`,
      trigger: `${attributeBase}-trigger`,
      disableOverlay: `${attributeBase}-disable-overlay`,
      hidden: 'aria-hidden'
    };
  }

  /**
   * Add event handlers
   */
  addEventHandlers() {
    if (this.trigger) {
      this.trigger.addEventListener('click', () => {
        if (!this.popoverOpen) {
          this.openPopover(this.element);
        } else {
          this.closePopover(this.popoverOpen);
        }
        this.toggleActiveClassOnTrigger();
      });
    }

    if (this.overlay && !this.disableOverlay && this.popoverOpen) {
      this.overlay.addEventListener('click', () => {
        this.closePopover(this.popoverOpen);

        if (this.trigger) {
          this.toggleActiveClassOnTrigger();
        }
      });
    } else {
      window.addEventListener('click', (clickEvent) => {
        if (!this.popoverOpen) {
          return;
        }

        if (
          (this.trigger && this.trigger.contains(clickEvent.target)) ||
          this.popoverOpen.contains(clickEvent.target)
        ) {
          return;
        }

        this.closePopover(this.popoverOpen);

        if (this.trigger) {
          this.toggleActiveClassOnTrigger();
        }
      });
    }

    document.addEventListener('keydown', (keydownEvent) => {
      this.handleButtonKeys(keydownEvent);
    });
  }

  isOpenByDefault() {
    return this.element.classList.contains(this.classes.popoverActive)
      ? (this.popoverOpen = this.element)
      : null;
  }

  openPopover(activePopover) {
    if (!activePopover) {
      return;
    }
    activePopover.classList.add(this.classes.popoverActive);
    activePopover.removeAttribute(this.attributes.hidden);

    if (this.overlay !== null && !this.disableOverlay) {
      this.overlay.classList.add(this.classes.modalOverlayActive);
    }

    this.popoverOpen = activePopover;
  }

  closePopover(activePopover) {
    if (!activePopover) {
      return;
    }
    activePopover.classList.remove(this.classes.popoverActive);
    activePopover.setAttribute(this.attributes.hidden, 'true');

    if (this.overlay && !this.disableOverlay) {
      this.overlay.classList.remove(this.classes.modalOverlayActive);
    }

    this.popoverOpen = false;
    this.keystroke = 0;
  }

  /**
   * Toggle active class on trigger element
   */
  toggleActiveClassOnTrigger() {
    if (this.trigger.classList.contains(this.classes.active)) {
      this.trigger.classList.remove(this.classes.active);
    } else {
      this.trigger.classList.add(this.classes.active);
    }
  }

  /**
   * 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.popoverOpen, this.keystroke);
          if (this.popoverOpen) {
            this.keystroke++;
          }
          break;

        case 'Escape':
          if (this.popoverOpen) {
            this.closePopover(this.popoverOpen);
            if (this.trigger) {
              this.trigger.focus();
            }
          }
      }
    }
  }

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