(function collonadeClosure() {
  'use strict';

  window.utils = window.utils || {};

  var ASYNC_FORM_RESPONSE_CLASS = 'async-form-response';
  var ASYNC_FORM_LOADING_CLASS = 'async-form-loading';
  var ASYNC_FORM_MIN_DELAY = 600;
  var DEFAULT_FAILURE_MESSAGE = 'The response we received from the server did not match what we expected. Please let us know this happened via the help widget in the top navigation.';

  window.utils.asyncForm = function(formElement, options) {

    options = options || {};

    var lastRequestTimestamp = 0;

    function setup() {
      formElement.addEventListener('submit', submitHandler);
    }

    function processResponse(response) {
      var responseElement = makeResponseElement(response.content, response.status);
      var parentElement = formElement.parentElement;

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

      setTimeout(function() {
        parentElement.insertBefore(responseElement, formElement);
        formElement.remove();
      }, delay);
    }

    function makeResponseElement(content, status) {
      var 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;
    }

    function submitHandler(event) {
      event.preventDefault();

      formElement.classList.add(ASYNC_FORM_LOADING_CLASS)
      lastRequestTimestamp = Date.now();

      var url = formElement.getAttribute('action');
      var headers = { };
      var body = new FormData(formElement);

      if (options && options.headers) {
        Object.keys(options.headers).forEach(function(headerKey) {
          headers[headerKey] = options.headers[headerKey];
        });
      }

      window.utils.httpClient.post(url, headers, body)
        .then(function(response) {
          if (response.headers.get("content-type").indexOf("application/json") !== -1) {// checking response header
            return response.json();
          } else {
            throw new TypeError('Unexpected Content-Type. Expected Content-Type: "application/json". Requested URL:' + url + '"');
          }
        }).then(function(response) {
          processResponse(response[0]);
        }).catch(function(error) {
          var failureMessage = DEFAULT_FAILURE_MESSAGE;
          if (options.i18n && options.i18n.asyncFormFailure) {
            failureMessage = options.i18n.asyncFormFailure;
          }
          processResponse({ content: failureMessage });

          formElement.classList.remove(ASYNC_FORM_LOADING_CLASS);
        });
    }

    setup();

    return {
      scope: formElement,
      destroy: function() {},
    };
  };
})();
