import _regeneratorRuntime from "@babel/runtime/regenerator";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
// NOTE: for unit tests you need to change the following line to...
// import rfc6902 from "rfc6902"
import * as rfc6902 from "rfc6902";
import bent from "bent";
import getHumanReadableLog from "./get-human-readable-log.js";
import applySeamlessPatch from "seamless-immutable-patch";
import hash from "./server-hash.js";

var CollaborationHandler = /*#__PURE__*/function () {
  function CollaborationHandler(_ref) {
    var serverUrl = _ref.serverUrl,
        userName = _ref.userName;

    _classCallCheck(this, CollaborationHandler);

    this.serverUrl = "http://localhost:6003";

    this.getJSON = function (url, payload, opts) {};

    this.postJSON = function (url, payload, opts) {};

    this.patchJSON = function (url, payload, opts) {};

    this.userName = "anonymous";
    this.sessionId = null;
    this.state = null;
    this.version = null;
    this.serverUrl = serverUrl;
    this.getJSON = bent("json", "GET", serverUrl);
    this.postJSON = bent("json", "POST", serverUrl);
    this.patchJSON = bent("json", "PATCH", serverUrl);
    this.userName = userName || "anonymous_".concat(Math.random().toString(36).slice(2, 6));
  }

  _createClass(CollaborationHandler, [{
    key: "createSession",
    value: function () {
      var _createSession = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(initialContent) {
        var response;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return this.postJSON("/api/session", {
                  udt: initialContent
                });

              case 2:
                response = _context.sent;
                this.state = initialContent;
                this.sessionId = response.short_id;
                this.version = response.version;

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

      function createSession(_x) {
        return _createSession.apply(this, arguments);
      }

      return createSession;
    }()
  }, {
    key: "getLatestState",
    value: function () {
      var _getLatestState = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
        var res;
        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                _context2.prev = 0;
                _context2.next = 3;
                return this.getJSON("/api/session/".concat(encodeURIComponent(this.sessionId)));

              case 3:
                res = _context2.sent;
                return _context2.abrupt("return", {
                  state: res.udt_json,
                  version: res.version
                });

              case 7:
                _context2.prev = 7;
                _context2.t0 = _context2["catch"](0);
                throw new Error("error getting session \"".concat(this.sessionId, "\": ").concat(_context2.t0.toString()));

              case 10:
              case "end":
                return _context2.stop();
            }
          }
        }, _callee2, this, [[0, 7]]);
      }));

      function getLatestState() {
        return _getLatestState.apply(this, arguments);
      }

      return getLatestState;
    }()
  }, {
    key: "updateToLatestState",
    value: function () {
      var _updateToLatestState = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
        var _yield$this$getLatest, state, version;

        return _regeneratorRuntime.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                _context3.next = 2;
                return this.getLatestState();

              case 2:
                _yield$this$getLatest = _context3.sent;
                state = _yield$this$getLatest.state;
                version = _yield$this$getLatest.version;
                this.state = state;
                this.version = version;

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

      function updateToLatestState() {
        return _updateToLatestState.apply(this, arguments);
      }

      return updateToLatestState;
    }()
  }, {
    key: "joinSession",
    value: function () {
      var _joinSession = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(sessionId) {
        return _regeneratorRuntime.wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                this.sessionId = sessionId;
                _context4.next = 3;
                return this.updateToLatestState();

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

      function joinSession(_x2) {
        return _joinSession.apply(this, arguments);
      }

      return joinSession;
    }()
  }, {
    key: "applyLatestPatches",
    value: function () {
      var _applyLatestPatches = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
        var _yield$this$getJSON, patch, hashOfLatestState, latestVersion, changeLog, humanReadableLog, newState;

        return _regeneratorRuntime.wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                _context5.next = 2;
                return this.getJSON("/api/session/".concat(encodeURIComponent(this.sessionId), "/diffs?since=").concat(this.version));

              case 2:
                _yield$this$getJSON = _context5.sent;
                patch = _yield$this$getJSON.patch;
                hashOfLatestState = _yield$this$getJSON.hashOfLatestState;
                latestVersion = _yield$this$getJSON.latestVersion;
                changeLog = _yield$this$getJSON.changeLog;

                if (!(patch.length === 0 || latestVersion === this.version)) {
                  _context5.next = 9;
                  break;
                }

                return _context5.abrupt("return", null);

              case 9:
                humanReadableLog = getHumanReadableLog(changeLog);
                newState = applySeamlessPatch(this.state, patch);

                if (!(hash(newState) !== hashOfLatestState)) {
                  _context5.next = 16;
                  break;
                }

                console.error("new state with patches applied didn't match latest state");
                _context5.next = 15;
                return this.updateToLatestState();

              case 15:
                return _context5.abrupt("return", {
                  patch: patch,
                  changeLog: humanReadableLog
                });

              case 16:
                this.state = newState;
                this.version = latestVersion;
                return _context5.abrupt("return", {
                  patch: patch,
                  changeLog: humanReadableLog
                });

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

      function applyLatestPatches() {
        return _applyLatestPatches.apply(this, arguments);
      }

      return applyLatestPatches;
    }()
  }, {
    key: "sendPatchIfChanged",
    value: function () {
      var _sendPatchIfChanged = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(newState) {
        var patch, _yield$this$patchJSON, hashOfLatestState, latestVersion;

        return _regeneratorRuntime.wrap(function _callee6$(_context6) {
          while (1) {
            switch (_context6.prev = _context6.next) {
              case 0:
                patch = rfc6902.createPatch(this.state, newState);

                if (!(patch.length === 0)) {
                  _context6.next = 3;
                  break;
                }

                return _context6.abrupt("return", null);

              case 3:
                _context6.next = 5;
                return this.patchJSON("/api/session/".concat(encodeURIComponent(this.sessionId)), {
                  patch: patch,
                  userName: this.userName
                });

              case 5:
                _yield$this$patchJSON = _context6.sent;
                hashOfLatestState = _yield$this$patchJSON.hashOfLatestState;
                latestVersion = _yield$this$patchJSON.latestVersion;

                if (!(hash(newState) !== hashOfLatestState)) {
                  _context6.next = 13;
                  break;
                }

                console.error("after patch, hashes were not equal! getting latest version from server...");
                _context6.next = 12;
                return this.updateToLatestState();

              case 12:
                return _context6.abrupt("return", this);

              case 13:
                this.state = newState;
                this.version = latestVersion;
                return _context6.abrupt("return", this);

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

      function sendPatchIfChanged(_x3) {
        return _sendPatchIfChanged.apply(this, arguments);
      }

      return sendPatchIfChanged;
    }()
  }]);

  return CollaborationHandler;
}();

export default CollaborationHandler;