"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _humps = require("humps");

var _queryString = _interopRequireDefault(require("query-string"));

var _isomorphicFetch = _interopRequireDefault(require("isomorphic-fetch"));

var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/lib/format-message"));

var _jsonify = _interopRequireDefault(require("./jsonify"));

var _httpHeaders = require("./httpHeaders");

var _reduxStore = _interopRequireDefault(require("../../reduxStore"));

var _callHelpers = require("./callHelpers");

var _alerts = require("../actions/alerts");

var _constants = require("@instructure/quiz-common/lib/constants");

/*
Note that this error extends the Error prototype in the old way because babel doesn't support extending from built-in
classes using the ES6 class syntax. Follows pattern from here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types
*/
function FetcherError(response) {
  this.message = response.statusText;
  this.response = response;
}

FetcherError.prototype = Object.create(Error.prototype);
FetcherError.prototype.constructor = FetcherError;

var Fetcher =
/*#__PURE__*/
function () {
  function Fetcher() {
    var _ref = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {},
        callType = _ref.callType,
        headers = _ref.headers,
        successMessage = _ref.successMessage,
        onError = _ref.onError,
        asyncResponseHandler = _ref.asyncResponseHandler;

    (0, _classCallCheck2.default)(this, Fetcher);
    this.callType = callType;
    this.headers = headers;
    this.successMessage = successMessage;
    this.onError = onError;
    this.asyncResponseHandler = asyncResponseHandler || _jsonify.default;
  }

  (0, _createClass2.default)(Fetcher, [{
    key: "markCallbacksComplete",
    value: function markCallbacksComplete() {
      if (this.callType) {
        this.dispatch((0, _callHelpers.callbacksCompleteForCall)(this.callType));
      }
    }
  }, {
    key: "getFetchLib",
    value: function getFetchLib() {
      if (Fetcher.usingFakes) {
        return Fetcher.fakeFetch;
      }

      if (window.fetch) {
        return window.fetch;
      }

      console.warn('Relying on isomorphic-fetch is deprecated and will be removed in a future release. Please use a fetch polyfill instead (i.e. whatwg-fetch).');
      return _isomorphicFetch.default;
    }
  }, {
    key: "dispatch",
    value: function dispatch(args) {
      if (Fetcher.usingFakes) {
        Fetcher.fakeDispatch(args);
      } else {
        _reduxStore.default.dispatch(args);
      }
    }
  }, {
    key: "getState",
    value: function getState() {
      return Fetcher.usingFakes ? Fetcher.fakeGetState() : _reduxStore.default.getAppState();
    }
  }, {
    key: "endpoint",
    value: function endpoint() {
      return this.getState().getIn(['config', 'apiEndpoint']) || '';
    }
  }, {
    key: "callHeaders",
    value: function callHeaders() {
      return this.headers || (0, _httpHeaders.httpHeaders)(this.getState().getIn(['config', 'userToken']));
    }
  }, {
    key: "handleSuccess",
    value: function handleSuccess(response) {
      if (this.successMessage) {
        this.dispatch((0, _alerts.addSuccess)(this.successMessage));
      }

      if (this.callType) {
        this.dispatch((0, _callHelpers.successCallFor)(this.callType));
      }

      return Promise.resolve(response);
    }
  }, {
    key: "handleError",
    value: function handleError(error, friendlyMessage) {
      if (this.onError) {
        // Custom error handler
        var errorAction = this.onError(error);

        if (errorAction) {
          this.dispatch(errorAction);
        }
      } else if (friendlyMessage) {
        this.dispatch((0, _alerts.addError)(friendlyMessage));
      }

      if (this.callType) {
        this.dispatch((0, _callHelpers.errorCallFor)(this.callType));
      }

      return Promise.reject(error);
    }
  }, {
    key: "handleResponse",
    value: function () {
      var _handleResponse = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee(response) {
        var isSuccessful, friendlyMessage;
        return _regenerator.default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                isSuccessful = response && response.status >= 200 && response.status < 300;

                if (!isSuccessful) {
                  _context.next = 3;
                  break;
                }

                return _context.abrupt("return", this.handleSuccess(response));

              case 3:
                if (response.status === _constants.HTTP_STATUS_CODE_UNAUTHORIZED) {
                  friendlyMessage = "Aroha mai, kaore i whakaaetia te tono";
                } else {
                  friendlyMessage = "Aroha mai, he hapa i " + response.status + ".";
                }

                return _context.abrupt("return", this.handleError(new FetcherError(response), friendlyMessage));

              case 5:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

      function handleResponse(_x) {
        return _handleResponse.apply(this, arguments);
      }

      return handleResponse;
    }()
  }, {
    key: "appendQueryParams",
    value: function appendQueryParams(url) {
      var params = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
      if (!Object.keys(params).length) return url;
      return "".concat(url, "?").concat(_queryString.default.stringify((0, _humps.decamelizeKeys)(params), {
        arrayFormat: 'bracket'
      }));
    }
  }, {
    key: "get",
    value: function () {
      var _get = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee2(url) {
        var _this = this;

        var additionalParams,
            params,
            _args2 = arguments;
        return _regenerator.default.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                additionalParams = _args2.length > 1 && _args2[1] !== void 0 ? _args2[1] : {};
                params = {
                  method: 'GET',
                  headers: this.callHeaders()
                };
                return _context2.abrupt("return", this.fetch(this.appendQueryParams(url, additionalParams), params).then(function (response) {
                  return _this.asyncResponseHandler(response, Object.assign(params, additionalParams));
                }));

              case 3:
              case "end":
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function get(_x2) {
        return _get.apply(this, arguments);
      }

      return get;
    }()
  }, {
    key: "post",
    value: function () {
      var _post = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee3(url) {
        var _this2 = this;

        var additionalParams,
            params,
            _args3 = arguments;
        return _regenerator.default.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                additionalParams = _args3.length > 1 && _args3[1] !== void 0 ? _args3[1] : {};
                params = Object.assign({
                  method: 'POST',
                  headers: this.callHeaders()
                }, additionalParams);
                return _context3.abrupt("return", this.fetch(url, params).then(function (response) {
                  return _this2.asyncResponseHandler(response, params);
                }));

              case 3:
              case "end":
                return _context3.stop();
            }
          }
        }, _callee3, this);
      }));

      function post(_x3) {
        return _post.apply(this, arguments);
      }

      return post;
    }()
  }, {
    key: "patch",
    value: function () {
      var _patch = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee4(url) {
        var _this3 = this;

        var additionalParams,
            params,
            _args4 = arguments;
        return _regenerator.default.wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                additionalParams = _args4.length > 1 && _args4[1] !== void 0 ? _args4[1] : {};
                params = Object.assign({
                  method: 'PATCH',
                  headers: this.callHeaders()
                }, additionalParams);
                return _context4.abrupt("return", this.fetch(url, params).then(function (response) {
                  return _this3.asyncResponseHandler(response, params);
                }));

              case 3:
              case "end":
                return _context4.stop();
            }
          }
        }, _callee4, this);
      }));

      function patch(_x4) {
        return _patch.apply(this, arguments);
      }

      return patch;
    }()
  }, {
    key: "put",
    value: function () {
      var _put = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee5(url) {
        var _this4 = this;

        var additionalParams,
            params,
            _args5 = arguments;
        return _regenerator.default.wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                additionalParams = _args5.length > 1 && _args5[1] !== void 0 ? _args5[1] : {};
                params = Object.assign({
                  method: 'PUT',
                  headers: this.callHeaders()
                }, additionalParams);
                return _context5.abrupt("return", this.fetch(url, params).then(function (response) {
                  return _this4.asyncResponseHandler(response, params);
                }));

              case 3:
              case "end":
                return _context5.stop();
            }
          }
        }, _callee5, this);
      }));

      function put(_x5) {
        return _put.apply(this, arguments);
      }

      return put;
    }()
  }, {
    key: "delete",
    value: function () {
      var _delete2 = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee6(url) {
        var additionalParams,
            params,
            _args6 = arguments;
        return _regenerator.default.wrap(function _callee6$(_context6) {
          while (1) {
            switch (_context6.prev = _context6.next) {
              case 0:
                additionalParams = _args6.length > 1 && _args6[1] !== void 0 ? _args6[1] : {};
                params = Object.assign({
                  method: 'DELETE',
                  headers: this.callHeaders()
                }, additionalParams);
                return _context6.abrupt("return", this.fetch(url, params));

              case 3:
              case "end":
                return _context6.stop();
            }
          }
        }, _callee6, this);
      }));

      function _delete(_x6) {
        return _delete2.apply(this, arguments);
      }

      return _delete;
    }()
  }, {
    key: "fetch",
    value: function () {
      var _fetch = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee7(url, params) {
        var fetchLib, response;
        return _regenerator.default.wrap(function _callee7$(_context7) {
          while (1) {
            switch (_context7.prev = _context7.next) {
              case 0:
                fetchLib = this.getFetchLib();

                if (this.callType) {
                  this.dispatch((0, _callHelpers.startCallFor)(this.callType));
                }

                _context7.prev = 2;

                if (!/^https?:\/\//.test(url)) {
                  _context7.next = 9;
                  break;
                }

                _context7.next = 6;
                return fetchLib(url, params);

              case 6:
                response = _context7.sent;
                _context7.next = 12;
                break;

              case 9:
                _context7.next = 11;
                return fetchLib(this.endpoint() + url, params);

              case 11:
                response = _context7.sent;

              case 12:
                _context7.next = 17;
                break;

              case 14:
                _context7.prev = 14;
                _context7.t0 = _context7["catch"](2);
                return _context7.abrupt("return", this.handleError(_context7.t0, _context7.t0.message));

              case 17:
                return _context7.abrupt("return", this.handleResponse(response));

              case 18:
              case "end":
                return _context7.stop();
            }
          }
        }, _callee7, this, [[2, 14]]);
      }));

      function fetch(_x7, _x8) {
        return _fetch.apply(this, arguments);
      }

      return fetch;
    }()
  }], [{
    key: "useFakes",
    value: function useFakes(useFake) {
      Fetcher.usingFakes = useFake;
    }
  }]);
  return Fetcher;
}();

var _default = Fetcher;
exports.default = _default;