"use strict";

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

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getQuizEntry = getQuizEntry;
exports.getQuizEntries = getQuizEntries;
exports.createQuizEntry = createQuizEntry;
exports.updateQuizEntry = updateQuizEntry;
exports.cloneQuizEntry = cloneQuizEntry;
exports.moveQuizEntry = moveQuizEntry;
exports.moveImmutableQuizEntry = moveImmutableQuizEntry;
exports.removeQuizEntry = removeQuizEntry;
exports.removeStimulusQuizEntry = removeStimulusQuizEntry;
exports.createItemAndQuizEntry = exports.createStimulusAndQuizEntry = void 0;

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

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

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

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

var _pick = _interopRequireDefault(require("lodash/pick"));

var _pickBy = _interopRequireDefault(require("lodash/pickBy"));

var _humps = require("humps");

var _Fetcher = _interopRequireDefault(require("../../common/util/Fetcher"));

var _ExhaustivePaginatedFetcher = _interopRequireDefault(require("../../common/util/ExhaustivePaginatedFetcher"));

var _scrolling = require("../../common/actions/scrolling");

var _ThunkQueue = _interopRequireDefault(require("../../common/util/ThunkQueue"));

var _noop = _interopRequireDefault(require("../../common/util/noop"));

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

var _items = require("./items");

var _stimuli = require("./stimuli");

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

var _quizEntries = require("../../common/actions/quizEntries");

var _ui = require("../../common/actions/ui");

var _quizzes = require("../../common/actions/quizzes");

var _callHandlers = require("../../common/api/callHandlers");

var _quizzes2 = require("../../common/api/quizzes");

var _QuizEntry = _interopRequireDefault(require("../../common/records/QuizEntry"));

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

// Actions that involve an API call should happen in order, to prevent race
// conditions (a user moving a question into a stimulus then immediately
// deleting the stimulus, for example). We use this queue to make sure requests
// wait for previous requests to finish, without preventing UI updates.
var queue = new _ThunkQueue.default(function (error, dispatch, getState) {
  // If an action fails, re-fetch all quiz entries from the backend
  var activeQuizId = getState().getIn(['quizzes', 'activeQuizId']);
  dispatch(getQuizEntries(activeQuizId));
  throw error;
}); // =====================
// =====================
//       GET INDEX
// =====================
// =====================

var handleQuizEntriesGet = function handleQuizEntriesGet(dispatch, quizId, quizEntries) {
  dispatch([(0, _callHandlers.handleQuizEntriesResponse)(quizEntries, quizId), (0, _quizzes.associateQuizEntries)(quizId, quizEntries)]);
  return quizEntries;
};

function getQuizEntry(quizId, quizEntryId) {
  var url = "/api/quizzes/".concat(quizId, "/quiz_entries/").concat(quizEntryId);
  return function (dispatch, getState) {
    var fetcher = new _Fetcher.default();
    return fetcher.get(url).then(function (data) {
      return handleQuizEntriesGet(dispatch, quizId, [data]);
    });
  };
}

function getQuizEntries(quizId) {
  var cb = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : _noop.default;
  var url = "/api/quizzes/".concat(quizId, "/quiz_entries");
  return function (dispatch, getState) {
    var fetcher = new _ExhaustivePaginatedFetcher.default();
    return fetcher.get(url).then(function (data) {
      return handleQuizEntriesGet(dispatch, quizId, data);
    }).then(cb);
  };
} // =====================
// =====================
//       CREATE
// =====================
// =====================


function createEntryAndQuizEntry(quizId, entry, quizEntry, entryCreationCb, quizEntryCreationCb) {
  return function (dispatch, getState) {
    var entryProperties = quizEntry.getProperties();
    return dispatch(entryCreationCb(entry, quizId, 'quiz')).then(function (entryData) {
      return dispatch(quizEntryCreationCb(quizId, entryData.id, quizEntry.get('entryType'), entryProperties));
    });
  };
}

var createStimulusAndQuizEntry = queue.wrapActionCreator(function (quizId, stimulus, quizEntry) {
  var stimulusCreationCb = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : _stimuli.createStimulus;
  var quizEntryCreationCb = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : createQuizEntry;
  return createEntryAndQuizEntry(quizId, stimulus, quizEntry, stimulusCreationCb, quizEntryCreationCb);
});
exports.createStimulusAndQuizEntry = createStimulusAndQuizEntry;
var createItemAndQuizEntry = queue.wrapActionCreator(function (quizId, item, quizEntry) {
  var itemCreationCb = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : _items.createItem;
  var quizEntryCreationCb = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : createQuizEntry;
  return createEntryAndQuizEntry(quizId, item, quizEntry, itemCreationCb, quizEntryCreationCb);
});
exports.createItemAndQuizEntry = createItemAndQuizEntry;

function createQuizEntry(quizId, entryId, entryType, entryProperties) {
  var requireFocus = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : true;
  var url = "/api/quizzes/".concat(quizId, "/quiz_entries");
  var quizEntryParams = (0, _objectSpread2.default)({
    quizId: quizId,
    entryType: entryType,
    entryId: entryId
  }, entryProperties);
  var body = JSON.stringify({
    quiz_entry: quizEntryParams
  });
  return function (dispatch, getState) {
    var fetcher = new _Fetcher.default({
      callType: _constants.CREATE_QUIZ_ENTRY_CALL,
      onError: function onError() {
        return (0, _alerts.addError)("Kunne ikke oprette test-indtastning.");
      }
    }); // TODO: this re-fetches all quiz entries after the new quiz entry is
    // created. This causes the new question to disappear and reappear after a
    // noticeable delay. Should we add the quiz entry optimistically, for
    // better UX?

    return fetcher.post(url, {
      body: body
    }).then(function (response) {
      var scrollCallback = function scrollCallback() {
        return dispatch((0, _scrolling.scrollToItem)(response.id, requireFocus));
      };

      return dispatch(getQuizEntries(quizId, scrollCallback));
    });
  };
} // =====================
// =====================
//    UPDATE, CLONE & MOVE
// =====================
// =====================
// UPDATE HELPER


function updateBody(updatedProperties) {
  var properties = updatedProperties.properties;

  if (properties && properties.selection === 'all') {
    properties.sampleNum = null;
  }

  var validProperties = Object.keys(updatedProperties).map(_humps.decamelize).concat(['properties']);
  var entryProperties = (0, _pick.default)({
    points_possible: parseFloat(updatedProperties.pointsPossible),
    position: updatedProperties.position,
    stimulus_quiz_entry_id: updatedProperties.stimulusQuizEntryId,
    entry_id: updatedProperties.entryId,
    entry_type: updatedProperties.entryType,
    properties: properties
  }, validProperties);

  var isDefined = function isDefined(val) {
    return val !== null && val !== void 0;
  };

  var entryPropsToUpdate = (0, _pickBy.default)(entryProperties, isDefined);
  return JSON.stringify({
    quiz_entry: entryPropsToUpdate
  });
} // Update the given quiz entry. If handleResponse is true, the redux store will
// be updated with response data when it comes back. You may want to set
// handleResponse to false for some optimistic update flows.


function updateQuizEntry(quizId, quizEntryId, updatedProperties) {
  var _ref = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {},
      _ref$handleResponse = _ref.handleResponse,
      handleResponse = _ref$handleResponse === void 0 ? true : _ref$handleResponse;

  var url = "/api/quizzes/".concat(quizId, "/quiz_entries/").concat(quizEntryId);
  var fetcher = new _Fetcher.default({
    callType: _constants.UPDATE_QUIZ_ENTRY_CALL,
    onError: function onError() {
      return (0, _alerts.addError)("Kunne ikke opdatere test-indtastning.");
    }
  });
  var body = updateBody(updatedProperties);
  return (
    /*#__PURE__*/
    function () {
      var _ref2 = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee(dispatch, getState) {
        var response;
        return _regenerator.default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return fetcher.patch(url, {
                  body: body
                });

              case 2:
                response = _context.sent;

                if (handleResponse) {
                  dispatch((0, _callHandlers.handleQuizEntryResponse)(response));
                }

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

      return function (_x, _x2) {
        return _ref2.apply(this, arguments);
      };
    }()
  );
}

function cloneQuizEntry(quizId, quizEntryId, updatedProperties) {
  var url = "/api/quizzes/".concat(quizId, "/quiz_entries/").concat(quizEntryId, "/clone");
  var fetcher = new _Fetcher.default({
    callType: _constants.CLONE_QUIZ_ENTRY_CALL,
    onError: function onError() {
      return (0, _alerts.addError)("Kunne ikke klone test-indtastning.");
    }
  });
  var body = updateBody(updatedProperties);
  return function (dispatch, getState) {
    return fetcher.post(url, {
      body: body
    }).then(function (qeData) {
      dispatch((0, _callHandlers.handleQuizEntryResponse)(qeData));
      return qeData;
    }).then(function () {
      return dispatch((0, _quizzes2.getExistingQuizAndItems)(quizId));
    });
  };
}

function moveQuizEntry(quizId, position, stimulusQuizEntryId, quizEntryId, moveTempItem) {
  var updateAction = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : updateQuizEntry;
  return function (dispatch, getState) {
    // Optimistically move the quiz entry in the redux store without waiting
    // for a response.
    return dispatch([(0, _quizEntries.moveQuizEntry)(quizEntryId, position, stimulusQuizEntryId), (0, _ui.set)(_constants.MOVED_QUIZ_ENTRY, quizEntryId)]).then(function () {
      moveTempItem && moveTempItem(); // this functionality was temporarily disabled in 9c03aa9

      var queuedUpdate = queue.wrapThunk(updateAction(quizId, quizEntryId, {
        position: position,
        stimulusQuizEntryId: stimulusQuizEntryId
      }, {
        handleResponse: false
      }));
      return dispatch(queuedUpdate);
    });
  };
}

function moveImmutableQuizEntry(quizId, position, stimulusQuizEntryId, quizEntryId) {
  var createItemAction = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : _items.createItem;
  var updateAction = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : updateQuizEntry;
  return function (dispatch, getState) {
    return dispatch(moveQuizEntry(quizId, position, stimulusQuizEntryId, quizEntryId, void 0, // We pass a noop action creator here to only move the quiz entry in our
    // local state, not on the backend. We need to wait to move the entry on
    // the backend until after the new item has been created, otherwise the
    // backend will complain about trying to update an immutable item.
    function () {
      return {
        type: _constants.DO_NOTHING
      };
    })).then(function () {
      return dispatch(createItemAndMoveQuizEntry(quizId, position, stimulusQuizEntryId, quizEntryId, createItemAction, updateAction));
    });
  };
}

var createItemAndMoveQuizEntry = queue.wrapActionCreator(function (quizId, position, stimulusQuizEntryId, quizEntryId) {
  var createItemAction = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : _items.createItem;
  var updateAction = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : updateQuizEntry;
  return function (dispatch, getState) {
    var quizEntry = _QuizEntry.default.create(getState().getIn(['quizEntries', quizEntryId]));

    var workingItem = quizEntry.getEntry().getWorkingInstance();
    return dispatch(createItemAction(workingItem, quizId, 'quiz', workingItem.id)).then(function (_ref3) {
      var id = _ref3.id;
      return dispatch(updateAction(quizId, quizEntryId, {
        entryId: id,
        position: position,
        stimulusQuizEntryId: stimulusQuizEntryId
      }, {
        handleResponse: false
      }));
    });
  };
}); // =====================
// =====================
//       DESTROY
// =====================
// =====================

function quizEntryDeleted(dispatch, quizEntry) {
  setTimeout(function () {
    dispatch((0, _ui.set)(_constants.DELETED_QUIZ_ENTRY, {
      position: quizEntry.position,
      inStimulus: quizEntry.isInStimulus
    }));
  }, 100);
}

var deleteQuizEntry = queue.wrapActionCreator(function (url, params) {
  return function (dispatch, getState) {
    var fetcher = new _Fetcher.default({
      callType: _constants.DELETE_QUIZ_ENTRY_CALL,
      onError: function onError() {
        return (0, _alerts.addError)("Kunne ikke fjerne test-indtastning.");
      }
    });
    return fetcher.delete(url, params);
  };
});

function removeQuizEntry(quizId, quizEntry) {
  var url = "/api/quizzes/".concat(quizId, "/quiz_entries/").concat(quizEntry.id);
  return function (dispatch, getState) {
    return dispatch([(0, _quizEntries.deleteQuizEntry)(quizEntry.id), (0, _quizzes.disassociateQuizEntry)(quizId, quizEntry.id)]).then(function () {
      quizEntryDeleted(dispatch, quizEntry);
      return dispatch(deleteQuizEntry(url));
    });
  };
}

function removeStimulusQuizEntry(quizId, stimulusEntry, childEntries) {
  var url = "/api/quizzes/".concat(quizId, "/quiz_entries/").concat(stimulusEntry.id, "/stimuli");
  var childEntryIds = childEntries.map(function (e) {
    return e.id;
  });
  return function (dispatch, getState) {
    var body = JSON.stringify({
      child_ids: childEntryIds
    });
    return dispatch([(0, _quizEntries.deleteStimulusEntry)(stimulusEntry.id, childEntryIds), (0, _quizzes.disassociateQuizEntry)(quizId, stimulusEntry.id)].concat((0, _toConsumableArray2.default)(childEntryIds.map(function (id) {
      return (0, _quizzes.disassociateQuizEntry)(quizId, id);
    })))).then(function () {
      quizEntryDeleted(dispatch, stimulusEntry);
      return dispatch(deleteQuizEntry(url, {
        body: body
      }));
    });
  };
}