'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _nodeBits = require('node-bits');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var UpdateReferences = function () {
  function UpdateReferences(db) {
    _classCallCheck(this, UpdateReferences);

    this.db = db;
  }

  _createClass(UpdateReferences, [{
    key: 'handleError',
    value: function handleError(res, err) {
      (0, _nodeBits.logError)(err);
      res.status(500).send();
    }
  }, {
    key: 'update1toM',
    value: function update1toM(res, root, source, data) {
      var _this = this;

      var modelId = root.model + 'Id';
      var referenceKey = source.referenceKey;

      this.db.find(source.reference, { where: _defineProperty({}, modelId, root.id) }).then(function (response) {
        // figure out what we have to do
        var toRemove = _lodash2.default.filter(response, function (x) {
          return !_lodash2.default.some(data, function (d) {
            return d[referenceKey] === x[referenceKey];
          });
        });
        var toAdd = _lodash2.default.filter(data, function (d) {
          return !_lodash2.default.some(response, function (x) {
            return x[referenceKey] === d[referenceKey];
          });
        });

        // do it
        var toDo = [].concat(_toConsumableArray(toRemove.map(function (x) {
          return _this.db.update(source.reference, x.id, _defineProperty({}, modelId, null));
        })), _toConsumableArray(toAdd.map(function (x) {
          return _this.db.update(source.reference, x.id, _defineProperty({}, modelId, root.id));
        })));

        Promise.all(toDo).then(res.send()).catch(function (err) {
          return _this.handleError(res, err);
        });
      }).catch(function (err) {
        return _this.handleError(res, err);
      });
    }
  }, {
    key: 'updateMtoM',
    value: function updateMtoM(res, root, source, data) {
      var _this2 = this;

      var modelId = root.model + 'Id';
      var referenceId = source.reference + 'Id';
      var referenceKey = source.referenceKey;
      var joinModel = root.model + '_' + source.reference;

      this.db.find(joinModel, { where: _defineProperty({}, modelId, root.id) }).then(function (response) {
        // figure out what we have to do
        var toRemove = _lodash2.default.filter(response, function (x) {
          return !_lodash2.default.some(data, function (d) {
            return d[referenceKey] === x[referenceId];
          });
        });
        var toAdd = _lodash2.default.filter(data, function (d) {
          return !_lodash2.default.some(response, function (x) {
            return x[referenceId] === d[referenceKey];
          });
        });

        // do it
        var toDo = [].concat(_toConsumableArray(toRemove.map(function (x) {
          return _this2.db.delete(joinModel, x.id);
        })), _toConsumableArray(toAdd.map(function (x) {
          var _this2$db$create;

          return _this2.db.create(joinModel, (_this2$db$create = {}, _defineProperty(_this2$db$create, modelId, root.id), _defineProperty(_this2$db$create, referenceId, x.id), _this2$db$create));
        })));

        Promise.all(toDo).then(res.send()).catch(function (err) {
          return _this2.handleError(res, err);
        });
      }).catch(function (err) {
        return _this2.handleError(res, err);
      });
    }
  }, {
    key: 'post',
    value: function post(req, res) {
      var _req$body = req.body,
          root = _req$body.root,
          source = _req$body.source,
          data = _req$body.data;


      switch (source.type) {
        case _nodeBits.MANY_TO_MANY:
          this.updateMtoM(res, root, source, data);
          break;

        case _nodeBits.ONE_TO_MANY:
          this.update1toM(res, root, source, data);
          break;

        default:
          res.status(500).send('Unable to process request');
      }
    }
  }]);

  return UpdateReferences;
}();

exports.default = function (config) {
  var apiRoot = config.root || '/api';
  return {
    verb: _nodeBits.POST,
    route: apiRoot + '/update_references',
    implementation: new UpdateReferences(config.database)
  };
};