text: const { Plugin } = require('elements')
  
  const { MutationObserver } = window
  
  module.exports = class react extends Plugin {
    async preload () {
      this.observer = new MutationObserver(mutation => this.onMutate(mutation))
    }
  
    load () {
      // start with a clean setup
      this.observer.disconnect()
      this.observer.observe(document.getElementById('app-mount'), {
        childList: true,
        subtree: true
      })
      this.observer.observe(document.querySelector('html'), {
        attributes: true
      })
    }
  
    get iconURL () {
      return '//discordinjections.xyz/img/logo.png'
    }
  
    getReactInstance (node) {
      const key = Object.keys(node).find(key =>
        key.startsWith('__reactInternalInstance')
      )
      return node[key]
    }
  
    createElement (text) {
      return document.createRange().createContextualFragment(text)
    }
  
    createModal (content) {
      const root = document.querySelector('#app-mount')
  
      if (this._modal) this.destroyModal()
      this._modal = this.createElement(`
              <div class="theme-dark DI-modal">
                  <div class="callout-backdrop"></div>
                  <div class="DI-modal-outer" style="opacity: 1">
                      <div class="DI-modal-inner expanded">
                          <div class="DI-modal-body">
                              ${content}
                          </div>
                      </div>
                  </div>
              </div>
          `)
  
      this._modal
        .querySelector('.DI-modal-inner')
        .addEventListener('click', event => {
          event.stopPropagation()
        })
  
      let close = this._modal.querySelector('.DI-modal-close-button')
      if (close) close.addEventListener('click', this.destroyModal.bind(this))
  
      if (!this._hasSetKeyListener) {
        document.body.addEventListener('keyup', this._modalKeypress.bind(this))
        document.body.addEventListener('click', this.destroyModal.bind(this))
        this._hasSetKeyListener = true
      }
  
      root.appendChild(this._modal)
  
      this._modal = root.querySelector('.DI-modal')
      const backdrop = this._modal.querySelector('.callout-backdrop')
      setTimeout(() => {
        backdrop.style.opacity = 0.6
      }, 1)
    }
  
    _modalKeypress (e) {
      if (e.code === 'Escape') this.destroyModal()
    }
  
    destroyModal () {
      if (this._modal) {
        let backdrop = this._modal.querySelector('.callout-backdrop')
        let inner = this._modal.querySelector('.DI-modal-inner')
        let close = this._modal.querySelector('.DI-modal-close-button')
        backdrop.style.opacity = 0
        inner.classList.remove('expanded')
        setTimeout(() => {
          if (close) close.addEventListener('click', this.destroyModal.bind(this))
          document.body.removeEventListener(
            'keyup',
            this._modalKeypress.bind(this)
          )
          document.body.removeEventListener('click', this.destroyModal.bind(this))
          this._modal.parentNode.removeChild(this._modal)
          this._modal = null
        }, 200)
      }
    }
  
    get settingsTabs () {
      return {
        'User Settings': 'userSettings',
        'My Account': 'userAccount',
        'Privacy & Safety': 'privacySettings',
        'Authorized Apps': 'authorizedApps',
        Connections: 'connections',
        'Discord Nitro': 'nitro',
        'App Settings': 'appSettings',
        Voice: 'voiceSettings',
        Overlay: 'overlaySettings',
        Notifications: 'notificationSettings',
        Keybindings: 'keybindingSettings',
        Games: 'gameSettings',
        'Text & Images': 'messageSettings',
        Appearance: 'appearanceSettings',
        'Streamer Mode': 'streamerSettings',
        Language: 'languageSettings',
        'Change Log': 'changelog',
        'Log Out': 'logout'
      }
    }
  
    onMutate (muts) {
      this.emit('mutation', muts)
  
      // change of language.
      if (
        muts.length === 1 &&
        muts[0].type === 'attributes' &&
        muts[0].attributeName === 'lang'
      ) {
        return this.emit('languageChange', muts[0].target.attributes.lang.value)
      }
  
      muts.forEach(mut => {
        if (mut.addedNodes.length + mut.removedNodes.length === 0) {
          return
        }
  
        const changed = (mut.addedNodes.length
          ? mut.addedNodes
          : mut.removedNodes)[0]
        const added = mut.addedNodes.length > 0
  
        // Settings
        if (changed.classList && changed.matches('[class*=layer]')) {
          const programSettings = !!changed.querySelector(
            '[class*="socialLinks"]'
          )
  
          if (programSettings && changed.childNodes.length > 0) {
            const child = changed.childNodes[0]
            let sidebarView = changed.querySelector('[class*="standardSidebarView"]')
            if (sidebarView) {
              if (added) {
                this.emit('settingsOpened', mut)
              } else {
                this.emit('settingsClosed', mut)
              }
            }
          }
        } else if (
          added &&
          changed.closest &&
          changed.closest('.content-region')
        ) {
          //! TODO: make this multilingual
          const element = document.querySelector(
            '[class*="layer"] .sidebar [class*="selected"]'
          )
          this.emit(
            'settingsTab',
            this.settingsTabs[element.innerText] || 'unknown',
            mut
          )
        } else if (changed.classList && changed.classList.contains('chat')) {
          // Chat
          if (added) {
            this.emit('chatOpened', mut)
          } else {
            this.emit('chatClosed', mut)
          }
        } else if (
          changed.className &&
          changed.className.match &&
          changed.className.match(/\bchannelTextArea-/) &&
          added
        ) {
          this.emit('channelChanged', mut)
        } else if (changed.id === 'friends') {
          // FriendsList
          if (added) {
            this.emit('friendsListOpened', mut)
          } else {
            this.emit('friendsListClosed', mut)
          }
        }
      })
    }
  }
  