import { time as u } from "../frameloop/sync-time.es.js";
import { mix as G } from "../utils/mix/index.es.js";
import { frameloopDriver as I } from "./drivers/frame.es.js";
import { inertia as K } from "./generators/inertia.es.js";
import { keyframes as c } from "./generators/keyframes.es.js";
import { calcGeneratorDuration as O } from "./generators/utils/calc-duration.es.js";
import { getFinalKeyframe as C } from "./keyframes/get-final.es.js";
import { replaceTransitionType as E } from "./utils/replace-transition-type.es.js";
import { WithPromise as N } from "./utils/WithPromise.es.js";
import { invariant as V } from "../../../../../../motion-utils@12.23.6/node_modules/motion-utils/dist/es/errors.es.js";
import { pipe as W } from "../../../../../../motion-utils@12.23.6/node_modules/motion-utils/dist/es/pipe.es.js";
import { millisecondsToSeconds as f, secondsToMilliseconds as $ } from "../../../../../../motion-utils@12.23.6/node_modules/motion-utils/dist/es/time-conversion.es.js";
import { clamp as B } from "../../../../../../motion-utils@12.23.6/node_modules/motion-utils/dist/es/clamp.es.js";
const J = (v) => v / 100;
class et extends N {
  constructor(t) {
    super(), this.state = "idle", this.startTime = null, this.isStopped = !1, this.currentTime = 0, this.holdTime = null, this.playbackSpeed = 1, this.stop = () => {
      var r, e;
      const { motionValue: i } = this.options;
      i && i.updatedAt !== u.now() && this.tick(u.now()), this.isStopped = !0, this.state !== "idle" && (this.teardown(), (e = (r = this.options).onStop) == null || e.call(r));
    }, this.options = t, this.initAnimation(), this.play(), t.autoplay === !1 && this.pause();
  }
  initAnimation() {
    const { options: t } = this;
    E(t);
    const { type: i = c, repeat: r = 0, repeatDelay: e = 0, repeatType: n, velocity: m = 0 } = t;
    let { keyframes: s } = t;
    const h = i || c;
    process.env.NODE_ENV !== "production" && h !== c && V(s.length <= 2, `Only two keyframes currently supported with spring and inertia animations. Trying to animate ${s}`, "spring-two-frames"), h !== c && typeof s[0] != "number" && (this.mixKeyframes = W(J, G(s[0], s[1])), s = [0, 100]);
    const a = h({ ...t, keyframes: s });
    n === "mirror" && (this.mirroredGenerator = h({
      ...t,
      keyframes: [...s].reverse(),
      velocity: -m
    })), a.calculatedDuration === null && (a.calculatedDuration = O(a));
    const { calculatedDuration: p } = a;
    this.calculatedDuration = p, this.resolvedDuration = p + e, this.totalDuration = this.resolvedDuration * (r + 1) - e, this.generator = a;
  }
  updateTime(t) {
    const i = Math.round(t - this.startTime) * this.playbackSpeed;
    this.holdTime !== null ? this.currentTime = this.holdTime : this.currentTime = i;
  }
  tick(t, i = !1) {
    const { generator: r, totalDuration: e, mixKeyframes: n, mirroredGenerator: m, resolvedDuration: s, calculatedDuration: h } = this;
    if (this.startTime === null)
      return r.next(0);
    const { delay: a = 0, keyframes: p, repeat: k, repeatType: D, repeatDelay: g, type: F, onUpdate: S, finalKeyframe: P } = this.options;
    this.speed > 0 ? this.startTime = Math.min(this.startTime, t) : this.speed < 0 && (this.startTime = Math.min(t - e / this.speed, this.startTime)), i ? this.currentTime = t : this.updateTime(t);
    const T = this.currentTime - a * (this.playbackSpeed >= 0 ? 1 : -1), b = this.playbackSpeed >= 0 ? T < 0 : T > e;
    this.currentTime = Math.max(T, 0), this.state === "finished" && this.holdTime === null && (this.currentTime = e);
    let w = this.currentTime, x = r;
    if (k) {
      const y = Math.min(this.currentTime, e) / s;
      let d = Math.floor(y), o = y % 1;
      !o && y >= 1 && (o = 1), o === 1 && d--, d = Math.min(d, k + 1), !!(d % 2) && (D === "reverse" ? (o = 1 - o, g && (o -= g / s)) : D === "mirror" && (x = m)), w = B(0, 1, o) * s;
    }
    const l = b ? { done: !1, value: p[0] } : x.next(w);
    n && (l.value = n(l.value));
    let { done: M } = l;
    !b && h !== null && (M = this.playbackSpeed >= 0 ? this.currentTime >= e : this.currentTime <= 0);
    const A = this.holdTime === null && (this.state === "finished" || this.state === "running" && M);
    return A && F !== K && (l.value = C(p, this.options, P, this.speed)), S && S(l.value), A && this.finish(), l;
  }
  /**
   * Allows the returned animation to be awaited or promise-chained. Currently
   * resolves when the animation finishes at all but in a future update could/should
   * reject if its cancels.
   */
  then(t, i) {
    return this.finished.then(t, i);
  }
  get duration() {
    return f(this.calculatedDuration);
  }
  get iterationDuration() {
    const { delay: t = 0 } = this.options || {};
    return this.duration + f(t);
  }
  get time() {
    return f(this.currentTime);
  }
  set time(t) {
    var i;
    t = $(t), this.currentTime = t, this.startTime === null || this.holdTime !== null || this.playbackSpeed === 0 ? this.holdTime = t : this.driver && (this.startTime = this.driver.now() - t / this.playbackSpeed), (i = this.driver) == null || i.start(!1);
  }
  get speed() {
    return this.playbackSpeed;
  }
  set speed(t) {
    this.updateTime(u.now());
    const i = this.playbackSpeed !== t;
    this.playbackSpeed = t, i && (this.time = f(this.currentTime));
  }
  play() {
    var e, n;
    if (this.isStopped)
      return;
    const { driver: t = I, startTime: i } = this.options;
    this.driver || (this.driver = t((m) => this.tick(m))), (n = (e = this.options).onPlay) == null || n.call(e);
    const r = this.driver.now();
    this.state === "finished" ? (this.updateFinished(), this.startTime = r) : this.holdTime !== null ? this.startTime = r - this.holdTime : this.startTime || (this.startTime = i ?? r), this.state === "finished" && this.speed < 0 && (this.startTime += this.calculatedDuration), this.holdTime = null, this.state = "running", this.driver.start();
  }
  pause() {
    this.state = "paused", this.updateTime(u.now()), this.holdTime = this.currentTime;
  }
  complete() {
    this.state !== "running" && this.play(), this.state = "finished", this.holdTime = null;
  }
  finish() {
    var t, i;
    this.notifyFinished(), this.teardown(), this.state = "finished", (i = (t = this.options).onComplete) == null || i.call(t);
  }
  cancel() {
    var t, i;
    this.holdTime = null, this.startTime = 0, this.tick(0), this.teardown(), (i = (t = this.options).onCancel) == null || i.call(t);
  }
  teardown() {
    this.state = "idle", this.stopDriver(), this.startTime = this.holdTime = null;
  }
  stopDriver() {
    this.driver && (this.driver.stop(), this.driver = void 0);
  }
  sample(t) {
    return this.startTime = 0, this.tick(t, !0);
  }
  attachTimeline(t) {
    var i;
    return this.options.allowFlatten && (this.options.type = "keyframes", this.options.ease = "linear", this.initAnimation()), (i = this.driver) == null || i.stop(), t.observe(this);
  }
}
export {
  et as JSAnimation
};
//# sourceMappingURL=JSAnimation.es.js.map
