(function (global) {
  global.ARQ = global.ARQ || {};
  var pointers = new Map();
  var stage = null;
  var opts = { rotateEnabled: true };

  function dist(a, b) {
    var dx = a.clientX - b.clientX, dy = a.clientY - b.clientY;
    return Math.sqrt(dx * dx + dy * dy);
  }
  function mid(a, b) {
    return { x: (a.clientX + b.clientX) / 2, y: (a.clientY + b.clientY) / 2 };
  }
  function angle(a, b) {
    return Math.atan2(b.clientY - a.clientY, b.clientX - a.clientX);
  }

  ARQ.gestures = {
    init: function (el, options) {
      stage = el;
      opts = Object.assign(opts, options || {});
      el.addEventListener('pointerdown', this._down.bind(this), { passive: false });
      el.addEventListener('pointermove', this._move.bind(this), { passive: false });
      el.addEventListener('pointerup', this._up.bind(this));
      el.addEventListener('pointercancel', this._up.bind(this));
    },
    _down: function (e) {
      pointers.set(e.pointerId, { x: e.clientX, y: e.clientY, ev: e });
      if (pointers.size === 2) {
        global.ARQ._twoFingerNav = true;
      }
    },
    _move: function (e) {
      if (!pointers.has(e.pointerId)) return;
      pointers.set(e.pointerId, { x: e.clientX, y: e.clientY, ev: e });
      if (pointers.size === 2) {
        global.ARQ._twoFingerNav = true;
        var arr = Array.from(pointers.values());
        var p0 = arr[0].ev, p1 = arr[1].ev;
        if (this._pinchStart == null) {
          var sh0 = ARQ.utils.activeSheet(ARQ.store.getProject());
          this._pinchStart = { d: dist(p0, p1), z: (sh0 && sh0.zoom_actual) || 1 };
          this._midStart = mid(p0, p1);
          this._angStart = angle(p0, p1);
          if (sh0 && sh0.pan_actual) {
            this._panStart = { x: sh0.pan_actual.x, y: sh0.pan_actual.y };
            this._rotStart = sh0.rotacion_actual || 0;
          } else {
            this._panStart = { x: 0, y: 0 };
            this._rotStart = 0;
          }
        } else {
          var d = dist(p0, p1);
          var sh = ARQ.utils.activeSheet(ARQ.store.getProject());
          if (sh && this._pinchStart) {
            var factor = d / this._pinchStart.d;
            var nz = Math.max(0.05, Math.min(8, this._pinchStart.z * factor));
            sh.zoom_actual = nz;
            var m = mid(p0, p1);
            sh.pan_actual = sh.pan_actual || { x: 0, y: 0 };
            sh.pan_actual.x = (this._panStart.x || 0) + (m.x - this._midStart.x);
            sh.pan_actual.y = (this._panStart.y || 0) + (m.y - this._midStart.y);
            if (opts.rotateEnabled) {
              var da = (angle(p0, p1) - this._angStart) * (180 / Math.PI);
              sh.rotacion_actual = (this._rotStart || 0) + da;
            }
            ARQ.viewport.applyFromSheet(sh);
            ARQ.bus.emit(ARQ.EVENTS.VIEWPORT_CHANGED, sh);
          }
        }
        e.preventDefault();
      }
    },
    _up: function (e) {
      var wasTwoFinger = pointers.size === 2;
      pointers.delete(e.pointerId);
      if (pointers.size < 2) {
        this._pinchStart = null;
        this._midStart = null;
        this._angStart = null;
        this._panStart = null;
        this._rotStart = null;
        global.ARQ._twoFingerNav = false;
        if (wasTwoFinger && ARQ.viewport && ARQ.viewport.scheduleViewportSettle) {
          ARQ.viewport.scheduleViewportSettle();
        }
      }
    },
  };
})(typeof window !== 'undefined' ? window : this);
