import { __assign } from "../../../../../../../tslib@2.6.2/node_modules/tslib/tslib.es6.js";
import { invariant } from "../../../../../../../hey-listen@1.0.8/node_modules/hey-listen/dist/hey-listen.es.js";
import { PanSession } from "../PanSession.js";
import { getGlobalLock } from "./utils/lock.js";
import { isRefObject } from "../../utils/is-ref-object.js";
import { addPointerEvent } from "../../events/use-pointer-event.js";
import { applyConstraints, calcRelativeConstraints, resolveDragElastic, calcViewportConstraints, rebaseAxisConstraints, calcOrigin, defaultElastic } from "./utils/constraints.js";
import { AnimationType } from "../../render/utils/types.js";
import { createBox } from "../../projection/geometry/models.js";
import { eachAxis } from "../../projection/utils/each-axis.js";
import { measurePageBox } from "../../projection/utils/measure.js";
import { extractEventInfo } from "../../events/event-info.js";
import { startAnimation } from "../../animation/utils/transitions.js";
import { convertBoxToBoundingBox, convertBoundingBoxToBox } from "../../projection/geometry/conversion.js";
import { addDomEvent } from "../../events/use-dom-event.js";
import { calcLength } from "../../projection/geometry/delta-calc.js";
import { percent } from "../../../../../../../style-value-types@5.0.0/node_modules/style-value-types/dist/es/numbers/units.js";
import { mix } from "../../../../../../../popmotion@11.0.3/node_modules/popmotion/dist/es/utils/mix.js";
var elementDragControls = /* @__PURE__ */ new WeakMap();
var VisualElementDragControls = (
  /** @class */
  function() {
    function VisualElementDragControls2(visualElement) {
      this.openGlobalLock = null;
      this.isDragging = false;
      this.currentDirection = null;
      this.originPoint = { x: 0, y: 0 };
      this.constraints = false;
      this.hasMutatedConstraints = false;
      this.elastic = createBox();
      this.visualElement = visualElement;
    }
    VisualElementDragControls2.prototype.start = function(originEvent, _a) {
      var _this = this;
      var _b = _a === void 0 ? {} : _a, _c = _b.snapToCursor, snapToCursor = _c === void 0 ? false : _c;
      if (this.visualElement.isPresent === false)
        return;
      var onSessionStart = function(event) {
        _this.stopAnimation();
        if (snapToCursor) {
          _this.snapToCursor(extractEventInfo(event, "page").point);
        }
      };
      var onStart = function(event, info) {
        var _a2;
        var _b2 = _this.getProps(), drag = _b2.drag, dragPropagation = _b2.dragPropagation, onDragStart = _b2.onDragStart;
        if (drag && !dragPropagation) {
          if (_this.openGlobalLock)
            _this.openGlobalLock();
          _this.openGlobalLock = getGlobalLock(drag);
          if (!_this.openGlobalLock)
            return;
        }
        _this.isDragging = true;
        _this.currentDirection = null;
        _this.resolveConstraints();
        if (_this.visualElement.projection) {
          _this.visualElement.projection.isAnimationBlocked = true;
          _this.visualElement.projection.target = void 0;
        }
        eachAxis(function(axis) {
          var _a3, _b3;
          var current = _this.getAxisMotionValue(axis).get() || 0;
          if (percent.test(current)) {
            var measuredAxis = (_b3 = (_a3 = _this.visualElement.projection) === null || _a3 === void 0 ? void 0 : _a3.layout) === null || _b3 === void 0 ? void 0 : _b3.actual[axis];
            if (measuredAxis) {
              var length_1 = calcLength(measuredAxis);
              current = length_1 * (parseFloat(current) / 100);
            }
          }
          _this.originPoint[axis] = current;
        });
        onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(event, info);
        (_a2 = _this.visualElement.animationState) === null || _a2 === void 0 ? void 0 : _a2.setActive(AnimationType.Drag, true);
      };
      var onMove = function(event, info) {
        var _a2 = _this.getProps(), dragPropagation = _a2.dragPropagation, dragDirectionLock = _a2.dragDirectionLock, onDirectionLock = _a2.onDirectionLock, onDrag = _a2.onDrag;
        if (!dragPropagation && !_this.openGlobalLock)
          return;
        var offset = info.offset;
        if (dragDirectionLock && _this.currentDirection === null) {
          _this.currentDirection = getCurrentDirection(offset);
          if (_this.currentDirection !== null) {
            onDirectionLock === null || onDirectionLock === void 0 ? void 0 : onDirectionLock(_this.currentDirection);
          }
          return;
        }
        _this.updateAxis("x", info.point, offset);
        _this.updateAxis("y", info.point, offset);
        _this.visualElement.syncRender();
        onDrag === null || onDrag === void 0 ? void 0 : onDrag(event, info);
      };
      var onSessionEnd = function(event, info) {
        return _this.stop(event, info);
      };
      this.panSession = new PanSession(originEvent, {
        onSessionStart,
        onStart,
        onMove,
        onSessionEnd
      }, { transformPagePoint: this.visualElement.getTransformPagePoint() });
    };
    VisualElementDragControls2.prototype.stop = function(event, info) {
      var isDragging = this.isDragging;
      this.cancel();
      if (!isDragging)
        return;
      var velocity = info.velocity;
      this.startAnimation(velocity);
      var onDragEnd = this.getProps().onDragEnd;
      onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(event, info);
    };
    VisualElementDragControls2.prototype.cancel = function() {
      var _a, _b;
      this.isDragging = false;
      if (this.visualElement.projection) {
        this.visualElement.projection.isAnimationBlocked = false;
      }
      (_a = this.panSession) === null || _a === void 0 ? void 0 : _a.end();
      this.panSession = void 0;
      var dragPropagation = this.getProps().dragPropagation;
      if (!dragPropagation && this.openGlobalLock) {
        this.openGlobalLock();
        this.openGlobalLock = null;
      }
      (_b = this.visualElement.animationState) === null || _b === void 0 ? void 0 : _b.setActive(AnimationType.Drag, false);
    };
    VisualElementDragControls2.prototype.updateAxis = function(axis, _point, offset) {
      var drag = this.getProps().drag;
      if (!offset || !shouldDrag(axis, drag, this.currentDirection))
        return;
      var axisValue = this.getAxisMotionValue(axis);
      var next = this.originPoint[axis] + offset[axis];
      if (this.constraints && this.constraints[axis]) {
        next = applyConstraints(next, this.constraints[axis], this.elastic[axis]);
      }
      axisValue.set(next);
    };
    VisualElementDragControls2.prototype.resolveConstraints = function() {
      var _this = this;
      var _a = this.getProps(), dragConstraints = _a.dragConstraints, dragElastic = _a.dragElastic;
      var layout = (this.visualElement.projection || {}).layout;
      var prevConstraints = this.constraints;
      if (dragConstraints && isRefObject(dragConstraints)) {
        if (!this.constraints) {
          this.constraints = this.resolveRefConstraints();
        }
      } else {
        if (dragConstraints && layout) {
          this.constraints = calcRelativeConstraints(layout.actual, dragConstraints);
        } else {
          this.constraints = false;
        }
      }
      this.elastic = resolveDragElastic(dragElastic);
      if (prevConstraints !== this.constraints && layout && this.constraints && !this.hasMutatedConstraints) {
        eachAxis(function(axis) {
          if (_this.getAxisMotionValue(axis)) {
            _this.constraints[axis] = rebaseAxisConstraints(layout.actual[axis], _this.constraints[axis]);
          }
        });
      }
    };
    VisualElementDragControls2.prototype.resolveRefConstraints = function() {
      var _a = this.getProps(), constraints = _a.dragConstraints, onMeasureDragConstraints = _a.onMeasureDragConstraints;
      if (!constraints || !isRefObject(constraints))
        return false;
      var constraintsElement = constraints.current;
      invariant(constraintsElement !== null, "If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.");
      var projection = this.visualElement.projection;
      if (!projection || !projection.layout)
        return false;
      var constraintsBox = measurePageBox(constraintsElement, projection.root, this.visualElement.getTransformPagePoint());
      var measuredConstraints = calcViewportConstraints(projection.layout.actual, constraintsBox);
      if (onMeasureDragConstraints) {
        var userConstraints = onMeasureDragConstraints(convertBoxToBoundingBox(measuredConstraints));
        this.hasMutatedConstraints = !!userConstraints;
        if (userConstraints) {
          measuredConstraints = convertBoundingBoxToBox(userConstraints);
        }
      }
      return measuredConstraints;
    };
    VisualElementDragControls2.prototype.startAnimation = function(velocity) {
      var _this = this;
      var _a = this.getProps(), drag = _a.drag, dragMomentum = _a.dragMomentum, dragElastic = _a.dragElastic, dragTransition = _a.dragTransition, dragSnapToOrigin = _a.dragSnapToOrigin, onDragTransitionEnd = _a.onDragTransitionEnd;
      var constraints = this.constraints || {};
      var momentumAnimations = eachAxis(function(axis) {
        var _a2;
        if (!shouldDrag(axis, drag, _this.currentDirection)) {
          return;
        }
        var transition = (_a2 = constraints === null || constraints === void 0 ? void 0 : constraints[axis]) !== null && _a2 !== void 0 ? _a2 : {};
        if (dragSnapToOrigin)
          transition = { min: 0, max: 0 };
        var bounceStiffness = dragElastic ? 200 : 1e6;
        var bounceDamping = dragElastic ? 40 : 1e7;
        var inertia = __assign(__assign({ type: "inertia", velocity: dragMomentum ? velocity[axis] : 0, bounceStiffness, bounceDamping, timeConstant: 750, restDelta: 1, restSpeed: 10 }, dragTransition), transition);
        return _this.startAxisValueAnimation(axis, inertia);
      });
      return Promise.all(momentumAnimations).then(onDragTransitionEnd);
    };
    VisualElementDragControls2.prototype.startAxisValueAnimation = function(axis, transition) {
      var axisValue = this.getAxisMotionValue(axis);
      return startAnimation(axis, axisValue, 0, transition);
    };
    VisualElementDragControls2.prototype.stopAnimation = function() {
      var _this = this;
      eachAxis(function(axis) {
        return _this.getAxisMotionValue(axis).stop();
      });
    };
    VisualElementDragControls2.prototype.getAxisMotionValue = function(axis) {
      var _a, _b;
      var dragKey = "_drag" + axis.toUpperCase();
      var externalMotionValue = this.visualElement.getProps()[dragKey];
      return externalMotionValue ? externalMotionValue : this.visualElement.getValue(axis, (_b = (_a = this.visualElement.getProps().initial) === null || _a === void 0 ? void 0 : _a[axis]) !== null && _b !== void 0 ? _b : 0);
    };
    VisualElementDragControls2.prototype.snapToCursor = function(point) {
      var _this = this;
      eachAxis(function(axis) {
        var drag = _this.getProps().drag;
        if (!shouldDrag(axis, drag, _this.currentDirection))
          return;
        var projection = _this.visualElement.projection;
        var axisValue = _this.getAxisMotionValue(axis);
        if (projection && projection.layout) {
          var _a = projection.layout.actual[axis], min = _a.min, max = _a.max;
          axisValue.set(point[axis] - mix(min, max, 0.5));
        }
      });
    };
    VisualElementDragControls2.prototype.scalePositionWithinConstraints = function() {
      var _this = this;
      var _a;
      var _b = this.getProps(), drag = _b.drag, dragConstraints = _b.dragConstraints;
      var projection = this.visualElement.projection;
      if (!isRefObject(dragConstraints) || !projection || !this.constraints)
        return;
      this.stopAnimation();
      var boxProgress = { x: 0, y: 0 };
      eachAxis(function(axis) {
        var axisValue = _this.getAxisMotionValue(axis);
        if (axisValue) {
          var latest = axisValue.get();
          boxProgress[axis] = calcOrigin({ min: latest, max: latest }, _this.constraints[axis]);
        }
      });
      var transformTemplate = this.visualElement.getProps().transformTemplate;
      this.visualElement.getInstance().style.transform = transformTemplate ? transformTemplate({}, "") : "none";
      (_a = projection.root) === null || _a === void 0 ? void 0 : _a.updateScroll();
      projection.updateLayout();
      this.resolveConstraints();
      eachAxis(function(axis) {
        if (!shouldDrag(axis, drag, null))
          return;
        var axisValue = _this.getAxisMotionValue(axis);
        var _a2 = _this.constraints[axis], min = _a2.min, max = _a2.max;
        axisValue.set(mix(min, max, boxProgress[axis]));
      });
    };
    VisualElementDragControls2.prototype.addListeners = function() {
      var _this = this;
      var _a;
      elementDragControls.set(this.visualElement, this);
      var element = this.visualElement.getInstance();
      var stopPointerListener = addPointerEvent(element, "pointerdown", function(event) {
        var _a2 = _this.getProps(), drag = _a2.drag, _b = _a2.dragListener, dragListener = _b === void 0 ? true : _b;
        drag && dragListener && _this.start(event);
      });
      var measureDragConstraints = function() {
        var dragConstraints = _this.getProps().dragConstraints;
        if (isRefObject(dragConstraints)) {
          _this.constraints = _this.resolveRefConstraints();
        }
      };
      var projection = this.visualElement.projection;
      var stopMeasureLayoutListener = projection.addEventListener("measure", measureDragConstraints);
      if (projection && !projection.layout) {
        (_a = projection.root) === null || _a === void 0 ? void 0 : _a.updateScroll();
        projection.updateLayout();
      }
      measureDragConstraints();
      var stopResizeListener = addDomEvent(window, "resize", function() {
        return _this.scalePositionWithinConstraints();
      });
      projection.addEventListener("didUpdate", function(_a2) {
        var delta = _a2.delta, hasLayoutChanged = _a2.hasLayoutChanged;
        if (_this.isDragging && hasLayoutChanged) {
          eachAxis(function(axis) {
            var motionValue = _this.getAxisMotionValue(axis);
            if (!motionValue)
              return;
            _this.originPoint[axis] += delta[axis].translate;
            motionValue.set(motionValue.get() + delta[axis].translate);
          });
          _this.visualElement.syncRender();
        }
      });
      return function() {
        stopResizeListener();
        stopPointerListener();
        stopMeasureLayoutListener();
      };
    };
    VisualElementDragControls2.prototype.getProps = function() {
      var props = this.visualElement.getProps();
      var _a = props.drag, drag = _a === void 0 ? false : _a, _b = props.dragDirectionLock, dragDirectionLock = _b === void 0 ? false : _b, _c = props.dragPropagation, dragPropagation = _c === void 0 ? false : _c, _d = props.dragConstraints, dragConstraints = _d === void 0 ? false : _d, _e = props.dragElastic, dragElastic = _e === void 0 ? defaultElastic : _e, _f = props.dragMomentum, dragMomentum = _f === void 0 ? true : _f;
      return __assign(__assign({}, props), { drag, dragDirectionLock, dragPropagation, dragConstraints, dragElastic, dragMomentum });
    };
    return VisualElementDragControls2;
  }()
);
function shouldDrag(direction, drag, currentDirection) {
  return (drag === true || drag === direction) && (currentDirection === null || currentDirection === direction);
}
function getCurrentDirection(offset, lockThreshold) {
  if (lockThreshold === void 0) {
    lockThreshold = 10;
  }
  var direction = null;
  if (Math.abs(offset.y) > lockThreshold) {
    direction = "y";
  } else if (Math.abs(offset.x) > lockThreshold) {
    direction = "x";
  }
  return direction;
}
export {
  VisualElementDragControls,
  elementDragControls
};
//# sourceMappingURL=VisualElementDragControls.js.map
