import { Utility } from '../../core/utility';
import { Datepicker } from '../form/datepicker';
import { EventManager, EventWrapper, EVENT_TYPE } from '../../lib/event-manager/event-manager';
import './async-form.sass';

const ASYNC_FORM_INITIALIZED_CLASS = 'check-all--initialized';
const ASYNC_FORM_RESPONSE_CLASS = 'async-form__response';
const ASYNC_FORM_LOADING_CLASS = 'async-form--loading';
const ASYNC_FORM_MIN_DELAY = 600;

const MODAL_SELECTOR = '.modal';
const MODAL_HEADER_KEY = 'Is-Modal';
const MODAL_HEADER_VALUE = 'True';

@Utility({
  selector: 'form[uw-async-form]',
})
export class AsyncForm {

  _lastRequestTimestamp = 0;
  _element;
  _app;

  _eventManager;

  constructor(element, app) {
    if (!element) {
      throw new Error('Async Form Utility cannot be setup without an element!');
    }

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

    this._eventManager = new EventManager();

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

    const submitEvent = new EventWrapper(EVENT_TYPE.SUBMIT, this._submitHandler.bind(this), this._element);
    this._eventManager.registerNewListener(submitEvent);

    this._element.classList.add(ASYNC_FORM_INITIALIZED_CLASS);
  }

  destroy() {
    this._eventManager.removeAllEventListenersFromUtil();

    if(this._element.classList.contains(ASYNC_FORM_INITIALIZED_CLASS))
      this._element.classList.remove(ASYNC_FORM_INITIALIZED_CLASS);
  }

  _processResponse(response) {
    const responseElement = this._makeResponseElement(response.content, response.status);
    const parentElement = this._element.parentElement;

    // make sure there is a delay between click and response
    const delay = Math.max(0, ASYNC_FORM_MIN_DELAY + this._lastRequestTimestamp - Date.now());

    setTimeout(() => {
      parentElement.insertBefore(responseElement, this._element);
      this._element.remove();
    }, delay);
  }

  _makeResponseElement(content, status) {
    const responseElement = document.createElement('div');
    status = status || 'info';
    responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS);
    responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS + '--' + status);
    responseElement.innerHTML = content;
    return responseElement;
  }

  _submitHandler = (event) => {
    event.preventDefault();

    this._element.classList.add(ASYNC_FORM_LOADING_CLASS);
    this._lastRequestTimestamp = Date.now();

    const url = this._element.getAttribute('action');
    const headers = { };

    // create new FormData and format any date values
    const body = Datepicker.unformatAll(this._element, new FormData(this._element));

    const isModal = this._element.closest(MODAL_SELECTOR);
    if (isModal) {
      headers[MODAL_HEADER_KEY] = MODAL_HEADER_VALUE;
    }

    this._app.httpClient.post({
      url: url,
      headers: headers,
      body: body,
    }).then(
      (response) => response.json()
    ).then(
      (response) => this._processResponse(response[0])
    ).catch(() => {
      const failureMessage = this._app.i18n.get('asyncFormFailure');
      this._processResponse({ content: failureMessage });

      this._element.classList.remove(ASYNC_FORM_LOADING_CLASS);
    });
  }
}
