import ElementHelpers from '../helpers/element-helpers';
import trapFocus from '../helpers/trapFocus';

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

export class Chat {
  constructor(element) {
    this.element = element;
    this.amountTagsChecked;
    this.box = ElementHelpers.getElementsByAttribute(this.attributes.box);
    this.button = ElementHelpers.getElementByAttribute(this.attributes.button);
    this.close = ElementHelpers.getElementByAttribute(this.attributes.close);
    this.header = ElementHelpers.getElementByAttribute(this.attributes.header);
    this.inputDialog = ElementHelpers.getElementByAttribute(
      this.attributes.input
    );
    this.languageNotification = ElementHelpers.getElementByAttribute(
      this.attributes.languageNotification
    );
    this.languageSaveButton = ElementHelpers.getElementByAttribute(
      this.attributes.languageSaveButton
    );
    this.languageSelector = ElementHelpers.getElementByAttribute(
      this.attributes.languageSelector
    );
    this.minimized = ElementHelpers.getElementByAttribute(
      this.attributes.minimized
    );
    this.popup = ElementHelpers.getElementByAttribute(this.attributes.popup);
    this.popupHide = ElementHelpers.getElementsByAttribute(
      this.attributes.popupHide
    );
    this.popupShow = ElementHelpers.getElementByAttribute(
      this.attributes.popupShow
    );
    this.quickSuggestButton;
    this.saveLanguageButton = ElementHelpers.getElementByAttribute(
      this.attributes.languageSaveButton
    );
    this.main = ElementHelpers.getElementByAttribute(this.attributes.main);
    this.settings = ElementHelpers.getElementByAttribute(
      this.attributes.settings
    );
    this.settingsButton = ElementHelpers.getElementsByAttribute(
      this.attributes.settingsButton
    );
    this.tagsChecked = [];
    this.tagDialog = ElementHelpers.getElementByAttribute(
      this.attributes.tagsDialog
    );
    this.textarea = ElementHelpers.getElementByAttribute(
      this.attributes.textarea
    );
    this.deselectButton = ElementHelpers.getElementByAttribute(
      this.attributes.deselectButton
    );
    this.submitButton = ElementHelpers.getElementByAttribute(
      this.attributes.submitButton
    );

    this.elementIsOpen;
    this.keystroke = 0;
    this.addEventHandlers();
  }

  /**
   * Declare classes
   */
  get classes() {
    return {
      dividerIsHidden: 'divider--is-hidden',
      displayNone: 'display-none',
      isActive: 'is-active'
    };
  }

  /**
   * Declare attribute constants
   */
  get attributes() {
    return {
      box: attributeBase + '-box',
      button: attributeBase + '-button',
      close: attributeBase + '-close',
      main: attributeBase + '-main',
      content: attributeBase + '-content',
      deselectButton: attributeBase + '-tags-deselect-button',
      header: attributeBase + '-header',
      input: attributeBase + '-input',
      languageNotification: attributeBase + '-language-notification',
      languageSaveButton: attributeBase + '-language-save-button',
      languageSelector: attributeBase + '-language-selector',
      minimized: attributeBase + '-minimized',
      popup: attributeBase + '-popup',
      popupHide: attributeBase + '-popup-hide',
      popupShow: attributeBase + '-popup-show',
      quickSuggest: attributeBase + '-quick-suggest',
      quickSuggestButton: attributeBase + '-quick-suggest-button',
      saveLanguageButton: attributeBase + '-save-language',
      settings: attributeBase + '-settings',
      settingsButton: attributeBase + '-settings-button',
      submitButton: attributeBase + '-tags-submit-button',
      tags: attributeBase + '-tags',
      tagsDialog: attributeBase + '-tags-dialog',
      tagsDialogLabel: attributeBase + '-tags-dialog-label',
      textarea: attributeBase + '-textarea'
    };
  }

  /**
   * Add event handlers
   */
  addEventHandlers() {
    this.handleHeaderDivider();
    this.toggleInputButton();
    this.quickSuggestButtonsHandler();
    this.tagHandler();

    this.close.addEventListener('click', (event) => {
      this.closeChat(event);
    });

    this.minimized.addEventListener('click', () => {
      this.openChat();
    });

    this.userInputToSpeechBubble();
    this.toggleSettingsHandler();
    this.languageSelectorHandler();
    this.popUpHandler();
    this.languageSaveButtonHandler();
    // handle key down event - close modal if escape is pressed
    document.addEventListener('keydown', (keydownEvent) => {
      this.handleButtonKeys(keydownEvent);
    });
  }

  /**
   * Adds a divider to the header when scrolling in the chat box
   */
  handleHeaderDivider() {
    this.box.forEach((element) => {
      element.addEventListener('scroll', () => {
        const scrollTop = element.scrollTop;
        const header = element.previousElementSibling;
        const headerClassList = header.classList;

        if (scrollTop > 1) {
          headerClassList.remove(this.classes.dividerIsHidden);
        } else {
          headerClassList.add(this.classes.dividerIsHidden);
        }
      });
    });
  }

  /**
   * Toggles the button from enabled to disabled when typing in the textarea
   */
  toggleInputButton() {
    this.textarea.addEventListener('input', () => {
      if (this.textarea.value.trim().length === 0) {
        this.button.disabled = true;
      } else {
        this.button.disabled = false;
      }
    });
  }

  /**
   * Opens the chat box when clicking on the chat-minimized button
   */
  openChat() {
    if (this.minimized) {
      this.minimized.classList.add(this.classes.displayNone);
      this.element.classList.remove(this.classes.displayNone);
      this.elementIsOpen = true;
    }
  }

  /**
   * Closes the chatbox when clicking on the close button
   */
  closeChat(event) {
    if (this.close && this.minimized) {
      event.preventDefault();
      this.element.classList.add(this.classes.displayNone);
      this.minimized.classList.remove(this.classes.displayNone);
      this.elementIsOpen = false;
      this.keystroke = 0;
    }
  }

  /**
   * Creates a speech bubble when clicking on the quick suggestion buttons
   */
  quickSuggestButtonsHandler() {
    this.quickSuggestButton = ElementHelpers.getElementsByAttribute(
      this.attributes.quickSuggestButton
    );
    if (this.quickSuggestButton) {
      this.quickSuggestButton.forEach((item) => {
        item.addEventListener('click', () => {
          const text = item.innerHTML;
          const parentElement = item.parentElement;
          parentElement.removeAttribute(this.attributes.quickSuggest);
          parentElement.setAttribute(this.attributes.content, 'user');
          parentElement.innerHTML = `<div class="chat__content chat__content--user speech-bubble speech-bubble--user">
            ${text}
          </div>`;

          this.box.scrollTop = this.box.scrollHeight;
        });
      });
    }
  }

  /**
   * Stores the array of the selected tags and the amount of tags that are checked in a global variable
   */
  getArrayOfSelectedTags(event) {
    if (event.target.checked) {
      this.tagsChecked.push(event.target.value);
    } else {
      let index = this.tagsChecked.indexOf(event.target.value);

      if (index !== -1) {
        this.tagsChecked.splice(index, 1);
      }
    }
    this.amountTagsChecked = this.tagsChecked.length;
  }

  /**
   * Handles the visibility of the tag dialog and content in the dialog when the tags are checked/unchecked
   */
  tagHandler() {
    this.tags = ElementHelpers.getElementByAttribute(this.attributes.tags);

    if (!this.tags) {
      return;
    }

    const checkboxes = ElementHelpers.getElementsByAttributeWithinElement(
      this.tags,
      'data-rs-tags-checkbox'
    );

    const tagDialogLabel = ElementHelpers.getElementByAttribute(
      this.attributes.tagsDialogLabel
    );

    const label = tagDialogLabel
      ? tagDialogLabel.getAttribute(this.attributes.tagsDialogLabel)
      : '@tag selected';

    for (let i = 0; checkboxes[i]; i++) {
      checkboxes[i].addEventListener('change', (event) => {
        this.getArrayOfSelectedTags(event);

        if (this.amountTagsChecked > 0) {
          this.tagDialog.classList.remove('hidden');
          this.inputDialog.classList.add('hidden');
          this.textarea.setAttribute('aria-hidden', true);
          this.button.setAttribute('aria-hidden', true);
          this.deselectButton.removeAttribute('aria-hidden');
          this.submitButton.removeAttribute('aria-hidden');
          tagDialogLabel.innerText = label.replace(
            '@tag',
            this.amountTagsChecked
          );
        } else {
          this.tagDialog.classList.add('hidden');
          this.inputDialog.classList.remove('hidden');
          this.textarea.removeAttribute('aria-hidden');
          this.button.removeAttribute('aria-hidden');
          this.deselectButton.setAttribute('aria-hidden', true);
          this.submitButton.setAttribute('aria-hidden', true);
        }
      });
    }

    this.handleTagDialogButtons();
  }

  /**
   * Handles the buttons in the tag dialog. Changes the tags that are selected into a user speechbubble, or deselect all checkboxes.
   */
  handleTagDialogButtons() {
    const checkboxes = ElementHelpers.getElementsByAttributeWithinElement(
      this.tags,
      'data-rs-tags-checkbox'
    );

    this.deselectButton.addEventListener('click', () => {
      this.tagsChecked = [];
      checkboxes.forEach((item) => {
        if (item.checked) {
          // Fake a click to fire the eventlistener in tag.js
          item.click();
        }
      });
      checkboxes[0].focus();
    });

    this.submitButton.addEventListener('click', () => {
      const text = this.tagsChecked.join(', ');

      // The content should be user content
      this.tags.setAttribute(this.attributes.content, 'user');

      // The attribute tags should not be there anymore since it's a speech bubble now
      this.tags.removeAttribute(this.attributes.tags);
      this.tags.innerHTML = `<div class="chat__content chat__content--user speech-bubble speech-bubble--user">
            ${text}
          </div>`;

      this.tagDialog.classList.add('hidden');
      this.inputDialog.classList.remove('hidden');
      this.box.scrollTop = this.box.scrollHeight;
      this.submitButton.setAttribute('aria-hidden', true);
      this.deselectButton.setAttribute('aria-hidden', true);
      this.textarea.removeAttribute('aria-hidden');
      this.button.removeAttribute('aria-hidden');

      this.textarea.focus();
    });
  }

  createSpeechBubble(e) {
    if (e.type === 'click' || e.key === 'Enter') {
      const inputText = this.textarea.value;

      // Remove the quickSuggestionButtons if they exist
      const quickSuggestion = ElementHelpers.getElementByAttribute(
        this.attributes.quickSuggest
      );
      if (quickSuggestion) {
        quickSuggestion.remove();
      }

      // Remove the tags if they exist
      if (this.tags) {
        this.tags.remove();
      }

      // If the last element is from the bot it should add a --first modifier to it
      const box = ElementHelpers.getElementByAttribute(
        this.attributes.box,
        'chat'
      );

      box.innerHTML =
        box.innerHTML += `<div class='chat-content__wrapper' data-rs-chat-content='user'><div class="chat__content chat__content--user speech-bubble speech-bubble--user">
      ${inputText}</div></div>`;

      if (box.lastElementChild) {
        const islastElementFromBot =
          box.lastElementChild.getAttribute(this.attributes.content) === 'bot';

        if (islastElementFromBot) {
          box.lastElementChild.classList.add('chat-content__wrapper--first');
        }
      }

      // Empty the text box
      this.textarea.value = '';
      // Set height back to original'
      this.textarea.style.height = 'auto';

      // Disable the button
      this.button.disabled = true;
      // Scroll to the bottom of the box
      box.scrollTop = box.scrollHeight;
    }
  }

  /**
   * Changes the input text to a user speech bubble when clicking on the button
   */
  userInputToSpeechBubble() {
    this.button.addEventListener('click', (e) => {
      this.createSpeechBubble(e);
      this.textarea.focus();
    });
    this.textarea.addEventListener('keydown', (e) => {
      this.createSpeechBubble(e);
      this.textarea.focus();
    });
  }

  toggleSettingsHandler() {
    this.settingsButton.forEach((item) => {
      item.addEventListener('click', () => {
        this.openAndCloseSettings();
      });
    });
  }

  languageSelectorHandler() {
    this.languageSelector.addEventListener('change', () => {
      const value = this.languageSelector.value;
      if (value !== '') {
        this.languageSaveButton.removeAttribute('disabled');
        this.languageNotification.classList.remove('display-none');
      } else {
        this.languageSaveButton.setAttribute('disabled', 'disabled');
        this.languageNotification.classList.add('display-none');
      }
    });
  }

  popUpHandler() {
    let focusableElements = [];
    this.popupShow.addEventListener('click', () => {
      this.popup.classList.add('is-active');

      focusableElements = ElementHelpers.getKeyboardFocusableElements(
        this.settings
      );

      focusableElements.forEach((el) => {
        el.setAttribute('aria-hidden', true);
      });

      return focusableElements;
    });

    this.popupHide.forEach((element) => {
      element.addEventListener('click', () => {
        this.popup.classList.remove('is-active');

        focusableElements.forEach((el) => el.removeAttribute('aria-hidden'));
        this.settingsButton.focus();
      });
    });
  }

  languageSaveButtonHandler() {
    this.saveLanguageButton.addEventListener('click', () => {
      const box = ElementHelpers.getElementByAttribute(
        this.attributes.box,
        'chat'
      );

      // Empty the box content
      box.innerHTML = '';

      this.openAndCloseSettings();
    });
  }

  openAndCloseSettings() {
    const settingsPanelClasses = this.settings.classList;
    if (!settingsPanelClasses.contains(this.classes.isActive)) {
      settingsPanelClasses.add(this.classes.isActive);
      setTimeout(() => {
        this.main.classList.add('hidden');
      }, 500);
    } else {
      this.main.classList.remove('hidden');
      settingsPanelClasses.remove(this.classes.isActive);
      this.settingsButton[0].focus();
    }
  }

  /**
   * Handle button keys - handle key presses escape
   *
   * @param {Event} event - event triggered
   */
  handleButtonKeys(event) {
    if (event != null) {
      switch (ElementHelpers.getKeyCodeOnKeyDownEvent(event)) {
        case 'Escape':
          if (this.elementIsOpen) {
            this.closeChat(event);
          }
          break;

        // eslint-disable-next-line no-case-declarations
        case 'Tab':
          const activePanel = !this.main.classList.contains('hidden')
            ? this.main
            : this.settings;

          trapFocus(event, activePanel, this.elementIsOpen, this.keystroke);

          if (this.elementIsOpen) {
            this.keystroke++;
          }
          break;
      }
    }
  }

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