import { Utility } from '../../core/utility';
import './alerts.sass';

const ALERTS_INITIALIZED_CLASS = 'alerts--initialized';
const ALERTS_ELEVATED_CLASS = 'alerts--elevated';
const ALERTS_TOGGLER_CLASS = 'alerts__toggler';
const ALERTS_TOGGLER_VISIBLE_CLASS = 'alerts__toggler--visible';
const ALERTS_TOGGLER_APPEAR_DELAY = 120;

const ALERT_CLASS = 'alert';
const ALERT_INITIALIZED_CLASS = 'alert--initialized';
const ALERT_CLOSER_CLASS = 'alert__closer';
const ALERT_ICON_CLASS = 'alert__icon';
const ALERT_CONTENT_CLASS = 'alert__content';
const ALERT_INVISIBLE_CLASS = 'alert--invisible';
const ALERT_AUTO_HIDE_DELAY = 10;
const ALERT_AUTOCLOSING_MATCHER = '.alert-info, .alert-success';

/*
 * Dataset-Inputs:
 *  - decay (data-decay): Custom time (in seconds) for this alert to stay visible
 */

@Utility({
  selector: '[uw-alerts]',
})
export class Alerts {
  _togglerCheckRequested = false;
  _togglerElement;
  _alertElements;

  _element;
  _app;

  constructor(element, app) {
    if (!element) {
      throw new Error('Alerts util has to be called with an element!');
    }

    this._element = element;
    this._app = app;

    if (this._element.classList.contains(ALERTS_INITIALIZED_CLASS)) {
      return false;
    }

    this._togglerElement = this._element.querySelector('.' + ALERTS_TOGGLER_CLASS);
    this._alertElements = this._gatherAlertElements();

    if (this._togglerElement) {
      this._initToggler();
    }

    this._initAlerts();

    // register http client interceptor to filter out Alerts Header
    this._setupHttpInterceptor();

    // mark initialized
    this._element.classList.add(ALERTS_INITIALIZED_CLASS);
  }

  destroy() {
    console.log('TBD: Destroy Alert');
  }

  _gatherAlertElements() {
    return Array.from(this._element.querySelectorAll('.' + ALERT_CLASS)).filter(function(alert) {
      return !alert.classList.contains(ALERT_INITIALIZED_CLASS);
    });
  }

  _initToggler() {
    this._togglerElement.addEventListener('click', () => {
      this._alertElements.forEach((alertEl) => this._toggleAlert(alertEl, true));
      this._togglerElement.classList.remove(ALERTS_TOGGLER_VISIBLE_CLASS);
    });
  }

  _initAlerts() {
    this._alertElements.forEach((alert) => this._initAlert(alert));
  }

  _initAlert(alertElement) {
    let autoHideDelay = ALERT_AUTO_HIDE_DELAY;
    if (alertElement.dataset.decay) {
      autoHideDelay = parseInt(alertElement.dataset.decay, 10);
    }

    const closeEl = alertElement.querySelector('.' + ALERT_CLOSER_CLASS);
    closeEl.addEventListener('click', () => {
      this._toggleAlert(alertElement);
    });

    if (autoHideDelay > 0 && alertElement.matches(ALERT_AUTOCLOSING_MATCHER)) {
      window.setTimeout(() => this._toggleAlert(alertElement), autoHideDelay * 1000);
    }
  }

  _toggleAlert(alertEl, visible) {
    alertEl.classList.toggle(ALERT_INVISIBLE_CLASS, !visible);
    this._checkToggler();
  }

  _checkToggler() {
    if (this._togglerCheckRequested) {
      return;
    }

    const alertsHidden = this._alertElements.reduce(function(acc, alert) {
      return acc && alert.classList.contains(ALERT_INVISIBLE_CLASS);
    }, true);

    window.setTimeout(() => {
      this._togglerElement.classList.toggle(ALERTS_TOGGLER_VISIBLE_CLASS, alertsHidden);
      this._togglerCheckRequested = false;
    }, ALERTS_TOGGLER_APPEAR_DELAY);
  }

  _setupHttpInterceptor() {
    this._app.httpClient.addResponseInterceptor(this._responseInterceptor.bind(this));
  }

  _elevateAlerts() {
    this._element.classList.add(ALERTS_ELEVATED_CLASS);
  }

  _responseInterceptor = (response) => {
    let alerts;
    for (const header of response.headers) {
      if (header[0] === 'alerts') {
        const decodedHeader = decodeURIComponent(header[1]);
        alerts = JSON.parse(decodedHeader);
        break;
      }
    }

    if (alerts) {
      alerts.forEach((alert) => {
        const alertElement = this._createAlertElement(alert.status, alert.content, alert.icon === null ? undefined : alert.icon);
        this._element.appendChild(alertElement);
        this._alertElements.push(alertElement);
        this._initAlert(alertElement);
      });

      this._elevateAlerts();
    }
  }

  _createAlertElement(type, content, icon = 'info-circle') {
    const alertElement = document.createElement('div');
    alertElement.classList.add(ALERT_CLASS, 'alert-' + type);

    const alertCloser = document.createElement('div');
    alertCloser.classList.add(ALERT_CLOSER_CLASS);

    const alertIcon = document.createElement('div');
    alertIcon.classList.add(ALERT_ICON_CLASS, 'fas', 'fa-' + icon);

    const alertContent = document.createElement('div');
    alertContent.classList.add(ALERT_CONTENT_CLASS);
    alertContent.innerHTML = content;

    alertElement.appendChild(alertCloser);
    alertElement.appendChild(alertIcon);
    alertElement.appendChild(alertContent);

    return alertElement;
  }
}
