import {
  a as O,
  b as k
} from "../_browser-chunks/chunk-WKO2DCSQ.js";
import {
  j as N
} from "../_browser-chunks/chunk-B6Q7I2AA.js";
import {
  a as h
} from "../_browser-chunks/chunk-IO47FP3U.js";

// src/instrumenter/instrumenter.ts
import { once as x } from "storybook/internal/client-logger";
import {
  FORCE_REMOUNT as A,
  SET_CURRENT_STORY as L,
  STORY_RENDER_PHASE_CHANGED as U
} from "storybook/internal/core-events";
import { global as S } from "@storybook/global";

// src/instrumenter/preview-api.ts
var E = globalThis.__STORYBOOK_ADDONS_PREVIEW;

// src/instrumenter/instrumenter.ts
var B = new Error(
  "This function ran after the play function completed. Did you forget to `await` it?"
), P = /* @__PURE__ */ h((_) => Object.prototype.toString.call(_) === "[object Object]", "isObject"), M = /* @__PURE__ */ h((_) => Object.prototype.toString.call(_) === "[object Module]", "isModule"), Y = /* @__PURE__ */ h((_) => {
  if (!P(_) && !M(_))
    return !1;
  if (_.constructor === void 0)
    return !0;
  let s = _.constructor.prototype;
  return !!P(s);
}, "isInstrumentable"), W = /* @__PURE__ */ h((_) => {
  try {
    return new _.constructor();
  } catch {
    return {};
  }
}, "construct"), w = /* @__PURE__ */ h(() => ({
  renderPhase: void 0,
  isDebugging: !1,
  isPlaying: !1,
  isLocked: !1,
  cursor: 0,
  calls: [],
  shadowCalls: [],
  callRefsByResult: /* @__PURE__ */ new Map(),
  chainedCallIds: /* @__PURE__ */ new Set(),
  ancestors: [],
  playUntil: void 0,
  resolvers: {},
  syncTimeout: void 0
}), "getInitialState"), j = /* @__PURE__ */ h((_, s = !1) => {
  let r = (s ? _.shadowCalls : _.calls).filter((d) => d.retain);
  if (!r.length)
    return;
  let e = new Map(
    Array.from(_.callRefsByResult.entries()).filter(([, d]) => d.retain)
  );
  return { cursor: r.length, calls: r, callRefsByResult: e };
}, "getRetainedState"), C = class C {
  constructor() {
    this.detached = !1;
    this.initialized = !1;
    // State is tracked per story to deal with multiple stories on the same canvas (i.e. docs mode)
    this.state = {};
    this.loadParentWindowState = /* @__PURE__ */ h(() => {
      try {
        this.state = S.window?.parent?.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__ || {};
      } catch {
        this.detached = !0;
      }
    }, "loadParentWindowState");
    this.updateParentWindowState = /* @__PURE__ */ h(() => {
      try {
        S.window.parent.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__ = this.state;
      } catch {
        this.detached = !0;
      }
    }, "updateParentWindowState");
    this.loadParentWindowState();
    let s = /* @__PURE__ */ h(({
      storyId: n,
      isPlaying: i = !0,
      isDebugging: o = !1
    }) => {
      let t = this.getState(n);
      this.setState(n, {
        ...w(),
        ...j(t, o),
        shadowCalls: o ? t.shadowCalls : [],
        chainedCallIds: o ? t.chainedCallIds : /* @__PURE__ */ new Set(),
        playUntil: o ? t.playUntil : void 0,
        isPlaying: i,
        isDebugging: o
      }), this.sync(n);
    }, "resetState"), r = /* @__PURE__ */ h((n) => ({ storyId: i, playUntil: o }) => {
      this.getState(i).isDebugging || this.setState(i, ({ calls: f }) => ({
        calls: [],
        shadowCalls: f.map((u) => ({ ...u, status: "waiting" })),
        isDebugging: !0
      }));
      let t = this.getLog(i);
      this.setState(i, ({ shadowCalls: f }) => {
        if (o || !t.length)
          return { playUntil: o };
        let u = f.findIndex((l) => l.id === t[0].callId);
        return {
          playUntil: f.slice(0, u).filter((l) => l.interceptable && !l.ancestors?.length).slice(-1)[0]?.id
        };
      }), n.emit(A, { storyId: i, isDebugging: !0 });
    }, "start"), e = /* @__PURE__ */ h((n) => ({ storyId: i }) => {
      let o = this.getLog(i).filter((f) => !f.ancestors?.length), t = o.reduceRight((f, u, l) => f >= 0 || u.status === "waiting" ? f : l, -1);
      r(n)({ storyId: i, playUntil: o[t - 1]?.callId });
    }, "back"), d = /* @__PURE__ */ h((n) => ({ storyId: i, callId: o }) => {
      let { calls: t, shadowCalls: f, resolvers: u } = this.getState(i), l = t.find(({ id: y }) => y === o), p = f.find(({ id: y }) => y === o);
      if (!l && p && Object.values(u).length > 0) {
        let y = this.getLog(i).find((m) => m.status === "waiting")?.callId;
        p.id !== y && this.setState(i, { playUntil: p.id }), Object.values(u).forEach((m) => m());
      } else
        r(n)({ storyId: i, playUntil: o });
    }, "goto"), c = /* @__PURE__ */ h((n) => ({ storyId: i }) => {
      let { resolvers: o } = this.getState(i);
      if (Object.values(o).length > 0)
        Object.values(o).forEach((t) => t());
      else {
        let t = this.getLog(i).find((f) => f.status === "waiting")?.callId;
        t ? r(n)({ storyId: i, playUntil: t }) : g({ storyId: i });
      }
    }, "next"), g = /* @__PURE__ */ h(({ storyId: n }) => {
      this.setState(n, { playUntil: void 0, isDebugging: !1 }), Object.values(this.getState(n).resolvers).forEach((i) => i());
    }, "end"), a = /* @__PURE__ */ h(({ storyId: n, newPhase: i }) => {
      let { isDebugging: o } = this.getState(n);
      this.setState(n, { renderPhase: i }), i === "preparing" && o && s({ storyId: n }), i === "playing" && s({ storyId: n, isDebugging: o }), i === "played" && this.setState(n, {
        isLocked: !1,
        isPlaying: !1,
        isDebugging: !1
      }), i === "errored" && this.setState(n, {
        isLocked: !1,
        isPlaying: !1
      });
    }, "renderPhaseChanged");
    E && E.ready().then(() => {
      this.channel = E.getChannel(), this.channel.on(A, s), this.channel.on(U, a), this.channel.on(L, () => {
        this.initialized ? this.cleanup() : this.initialized = !0;
      }), this.channel.on(O.START, r(this.channel)), this.channel.on(O.BACK, e(this.channel)), this.channel.on(O.GOTO, d(this.channel)), this.channel.on(O.NEXT, c(this.channel)), this.channel.on(O.END, g);
    });
  }
  getState(s) {
    return this.state[s] || w();
  }
  setState(s, r) {
    let e = this.getState(s), d = typeof r == "function" ? r(e) : r;
    this.state = { ...this.state, [s]: { ...e, ...d } }, this.updateParentWindowState();
  }
  cleanup() {
    this.state = Object.entries(this.state).reduce(
      (e, [d, c]) => {
        let g = j(c);
        return g && (e[d] = Object.assign(w(), g)), e;
      },
      {}
    );
    let r = { controlStates: {
      detached: this.detached,
      start: !1,
      back: !1,
      goto: !1,
      next: !1,
      end: !1
    }, logItems: [] };
    this.channel?.emit(O.SYNC, r), this.updateParentWindowState();
  }
  getLog(s) {
    let { calls: r, shadowCalls: e } = this.getState(s), d = [...e];
    r.forEach((g, a) => {
      d[a] = g;
    });
    let c = /* @__PURE__ */ new Set();
    return d.reduceRight((g, a) => (a.args.forEach((n) => {
      n?.__callId__ && c.add(n.__callId__);
    }), a.path.forEach((n) => {
      n.__callId__ && c.add(n.__callId__);
    }), (a.interceptable || a.exception) && !c.has(a.id) && (g.unshift({ callId: a.id, status: a.status, ancestors: a.ancestors }), c.add(a.id)), g), []);
  }
  // Traverses the object structure to recursively patch all function properties.
  // Returns the original object, or a new object with the same constructor,
  // depending on whether it should mutate.
  instrument(s, r, e = 0) {
    if (!Y(s))
      return s;
    let { mutate: d = !1, path: c = [] } = r, g = r.getKeys ? r.getKeys(s, e) : Object.keys(s);
    return e += 1, g.reduce(
      (a, n) => {
        let i = F(s, n);
        if (typeof i?.get == "function") {
          if (i.configurable) {
            let t = /* @__PURE__ */ h(() => i?.get?.bind(s)?.(), "getter");
            Object.defineProperty(a, n, {
              get: /* @__PURE__ */ h(() => this.instrument(t(), { ...r, path: c.concat(n) }, e), "get")
            });
          }
          return a;
        }
        let o = s[n];
        return typeof o != "function" ? (a[n] = this.instrument(o, { ...r, path: c.concat(n) }, e), a) : "__originalFn__" in o && typeof o.__originalFn__ == "function" ? (a[n] = o, a) : (a[n] = (...t) => this.track(n, o, s, t, r), a[n].__originalFn__ = o, Object.defineProperty(a[n], "name", { value: n, writable: !1 }), Object.keys(o).length > 0 && Object.assign(
          a[n],
          this.instrument({ ...o }, { ...r, path: c.concat(n) }, e)
        ), a);
      },
      d ? s : W(s)
    );
  }
  // Monkey patch an object method to record calls.
  // Returns a function that invokes the original function, records the invocation ("call") and
  // returns the original result.
  track(s, r, e, d, c) {
    let g = d?.[0]?.__storyId__ || S.__STORYBOOK_PREVIEW__?.selectionStore?.selection?.storyId, { cursor: a, ancestors: n } = this.getState(g);
    this.setState(g, { cursor: a + 1 });
    let i = `${n.slice(-1)[0] || g} [${a}] ${s}`, { path: o = [], intercept: t = !1, retain: f = !1 } = c, u = typeof t == "function" ? t(s, o) : t, l = { id: i, cursor: a, storyId: g, ancestors: n, path: o, method: s, args: d, interceptable: u, retain: f }, y = (u && !n.length ? this.intercept : this.invoke).call(this, r, e, l, c);
    return this.instrument(y, { ...c, mutate: !0, path: [{ __callId__: l.id }] });
  }
  intercept(s, r, e, d) {
    let { chainedCallIds: c, isDebugging: g, playUntil: a } = this.getState(e.storyId), n = c.has(e.id);
    return !g || n || a ? (a === e.id && this.setState(e.storyId, { playUntil: void 0 }), this.invoke(s, r, e, d)) : new Promise((i) => {
      this.setState(e.storyId, ({ resolvers: o }) => ({
        isLocked: !1,
        resolvers: { ...o, [e.id]: i }
      }));
    }).then(() => (this.setState(e.storyId, (i) => {
      let { [e.id]: o, ...t } = i.resolvers;
      return { isLocked: !0, resolvers: t };
    }), this.invoke(s, r, e, d)));
  }
  invoke(s, r, e, d) {
    let { callRefsByResult: c, renderPhase: g } = this.getState(e.storyId), a = 25, n = /* @__PURE__ */ h((t, f, u) => {
      if (u.includes(t))
        return "[Circular]";
      if (u = [...u, t], f > a)
        return "...";
      if (c.has(t))
        return c.get(t);
      if (t instanceof Array)
        return t.map((l) => n(l, ++f, u));
      if (t instanceof Date)
        return { __date__: { value: t.toISOString() } };
      if (t instanceof Error) {
        let { name: l, message: p, stack: y } = t;
        return { __error__: { name: l, message: p, stack: y } };
      }
      if (t instanceof RegExp) {
        let { flags: l, source: p } = t;
        return { __regexp__: { flags: l, source: p } };
      }
      if (t instanceof S.window?.HTMLElement) {
        let { prefix: l, localName: p, id: y, classList: m, innerText: R } = t, I = Array.from(m);
        return { __element__: { prefix: l, localName: p, id: y, classNames: I, innerText: R } };
      }
      return typeof t == "function" ? {
        __function__: { name: "getMockName" in t ? t.getMockName() : t.name }
      } : typeof t == "symbol" ? { __symbol__: { description: t.description } } : typeof t == "object" && t?.constructor?.name && t?.constructor?.name !== "Object" ? { __class__: { name: t.constructor.name } } : Object.prototype.toString.call(t) === "[object Object]" ? Object.fromEntries(
        Object.entries(t).map(([l, p]) => [l, n(p, ++f, u)])
      ) : t;
    }, "serializeValues"), i = {
      ...e,
      args: e.args.map((t) => n(t, 0, []))
    };
    e.path.forEach((t) => {
      t?.__callId__ && this.setState(e.storyId, ({ chainedCallIds: f }) => ({
        chainedCallIds: new Set(Array.from(f).concat(t.__callId__))
      }));
    });
    let o = /* @__PURE__ */ h((t) => {
      if (t instanceof Error) {
        let { name: f, message: u, stack: l, callId: p = e.id } = t, {
          showDiff: y = void 0,
          diff: m = void 0,
          actual: R = void 0,
          expected: I = void 0
        } = t.name === "AssertionError" ? N(t) : t, T = { name: f, message: u, stack: l, callId: p, showDiff: y, diff: m, actual: R, expected: I };
        if (this.update({ ...i, status: "error", exception: T }), this.setState(e.storyId, (D) => ({
          callRefsByResult: new Map([
            ...Array.from(D.callRefsByResult.entries()),
            [t, { __callId__: e.id, retain: e.retain }]
          ])
        })), e.ancestors?.length)
          throw Object.prototype.hasOwnProperty.call(t, "callId") || Object.defineProperty(t, "callId", { value: e.id }), t;
      }
      throw t;
    }, "handleException");
    try {
      if (g === "played" && !e.retain)
        throw B;
      let f = (d.getArgs ? d.getArgs(e, this.getState(e.storyId)) : e.args).map((l) => typeof l != "function" || V(l) || Object.keys(l).length ? l : (...p) => {
        let { cursor: y, ancestors: m } = this.getState(e.storyId);
        this.setState(e.storyId, { cursor: 0, ancestors: [...m, e.id] });
        let R = /* @__PURE__ */ h(() => this.setState(e.storyId, { cursor: y, ancestors: m }), "restore"), I = !1;
        try {
          let T = l(...p);
          return T instanceof Promise ? (I = !0, T.finally(R)) : T;
        } finally {
          I || R();
        }
      }), u = s.apply(r, f);
      return u && ["object", "function", "symbol"].includes(typeof u) && this.setState(e.storyId, (l) => ({
        callRefsByResult: new Map([
          ...Array.from(l.callRefsByResult.entries()),
          [u, { __callId__: e.id, retain: e.retain }]
        ])
      })), this.update({
        ...i,
        status: u instanceof Promise ? "active" : "done"
      }), u instanceof Promise ? u.then((l) => (this.update({ ...i, status: "done" }), l), o) : u;
    } catch (t) {
      return o(t);
    }
  }
  // Sends the call info to the manager and synchronizes the log.
  update(s) {
    this.channel?.emit(O.CALL, s), this.setState(s.storyId, ({ calls: r }) => {
      let e = r.concat(s).reduce((d, c) => Object.assign(d, { [c.id]: c }), {});
      return {
        // Calls are sorted to ensure parent calls always come before calls in their callback.
        calls: Object.values(e).sort(
          (d, c) => d.id.localeCompare(c.id, void 0, { numeric: !0 })
        )
      };
    }), this.sync(s.storyId);
  }
  // Builds a log of interceptable calls and control states and sends it to the manager.
  // Uses a 0ms debounce because this might get called many times in one tick.
  sync(s) {
    let r = /* @__PURE__ */ h(() => {
      let { isLocked: e, isPlaying: d } = this.getState(s), c = this.getLog(s), g = c.filter(({ ancestors: t }) => !t.length).find((t) => t.status === "waiting")?.callId, a = c.some((t) => t.status === "active");
      if (this.detached || e || a || c.length === 0) {
        let f = { controlStates: {
          detached: this.detached,
          start: !1,
          back: !1,
          goto: !1,
          next: !1,
          end: !1
        }, logItems: c };
        this.channel?.emit(O.SYNC, f);
        return;
      }
      let n = c.some(
        (t) => t.status === "done" || t.status === "error"
      ), o = { controlStates: {
        detached: this.detached,
        start: n,
        back: n,
        goto: !0,
        next: d,
        end: d
      }, logItems: c, pausedAt: g };
      this.channel?.emit(O.SYNC, o);
    }, "synchronize");
    this.setState(s, ({ syncTimeout: e }) => (clearTimeout(e), { syncTimeout: setTimeout(r, 0) }));
  }
};
h(C, "Instrumenter");
var b = C;
function K(_, s = {}) {
  try {
    let r = !1, e = !1;
    return S.window?.location?.search?.includes("instrument=true") ? r = !0 : S.window?.location?.search?.includes("instrument=false") && (e = !0), S.window?.parent === S.window && !r || e ? _ : (S.window && !S.window.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__ && (S.window.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__ = new b()), (S.window?.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__).instrument(_, s));
  } catch (r) {
    return x.warn(r), _;
  }
}
h(K, "instrument");
function F(_, s) {
  let r = _;
  for (; r != null; ) {
    let e = Object.getOwnPropertyDescriptor(r, s);
    if (e)
      return e;
    r = Object.getPrototypeOf(r);
  }
}
h(F, "getPropertyDescriptor");
function V(_) {
  if (typeof _ != "function")
    return !1;
  let s = Object.getOwnPropertyDescriptor(_, "prototype");
  return s ? !s.writable : !1;
}
h(V, "isClass");
export {
  k as CallStates,
  O as EVENTS,
  K as instrument
};
