"use strict";
var jitterUtils = (() => {
  var __defProp = Object.defineProperty;
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  var __getOwnPropNames = Object.getOwnPropertyNames;
  var __hasOwnProp = Object.prototype.hasOwnProperty;
  var __export = (target, all) => {
    for (var name in all)
      __defProp(target, name, { get: all[name], enumerable: true });
  };
  var __copyProps = (to, from, except, desc) => {
    if (from && typeof from === "object" || typeof from === "function") {
      for (let key of __getOwnPropNames(from))
        if (!__hasOwnProp.call(to, key) && key !== except)
          __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
    }
    return to;
  };
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

  // utils/index.ts
  var index_exports = {};
  __export(index_exports, {
    addObject: () => addObject,
    batchReplace: () => batchReplace,
    clearSelection: () => clearSelection,
    createMediaSnapshot: () => createMediaSnapshot,
    createSnapshot: () => createSnapshot,
    createTextSnapshot: () => createTextSnapshot,
    default: () => index_default,
    deleteProject: () => deleteProject,
    deleteSelection: () => deleteSelection,
    duplicateProject: () => duplicateProject,
    findAllMediaNodes: () => findAllMediaNodes,
    findAllTextNodes: () => findAllTextNodes,
    findNodeById: () => findNodeById,
    findNodesByName: () => findNodesByName,
    findNodesByType: () => findNodesByType,
    flattenTree: () => flattenTree,
    generateExportUrl: () => generateExportUrl,
    generateExportUrlFromCurrentProject: () => generateExportUrlFromCurrentProject,
    generateNodeUrl: () => generateNodeUrl,
    getAncestors: () => getAncestors,
    getArtboards: () => getArtboards,
    getCurrentProjectUrl: () => getCurrentProjectUrl,
    getFileMeta: () => getFileMeta,
    getParentNode: () => getParentNode,
    isAppReady: () => isAppReady,
    isReadOnly: () => isReadOnly,
    jumpToEnd: () => jumpToEnd,
    jumpToStart: () => jumpToStart,
    moveNode: () => moveNode,
    parseJitterUrl: () => parseJitterUrl,
    redo: () => redo,
    removeNodes: () => removeNodes,
    renameNode: () => renameNode,
    replaceAssetUrl: () => replaceAssetUrl,
    replaceText: () => replaceText,
    resizeNode: () => resizeNode,
    restoreFromSnapshot: () => restoreFromSnapshot,
    selectNodes: () => selectNodes,
    setCurrentTime: () => setCurrentTime,
    setOpacity: () => setOpacity,
    setRotation: () => setRotation,
    undo: () => undo,
    updateNode: () => updateNode,
    waitFor: () => waitFor,
    waitForApp: () => waitForApp,
    waitForConfigChange: () => waitForConfigChange,
    waitForNode: () => waitForNode,
    waitForSync: () => waitForSync,
    withTemporaryChanges: () => withTemporaryChanges
  });

  // utils/traverse.ts
  function getConf() {
    return window.app.props.observableImmutableConf.lastImmutableConf;
  }
  function findNodeById(nodeId) {
    const conf = getConf();
    const search = (node) => {
      if (node.id === nodeId) {
        return node;
      }
      if (node.children) {
        for (const child of node.children) {
          const found = search(child);
          if (found) {
            return found;
          }
        }
      }
      return null;
    };
    for (const root of conf.roots || []) {
      const found = search(root);
      if (found) {
        return found;
      }
    }
    return null;
  }
  function findAllMediaNodes() {
    const conf = getConf();
    const mediaNodes = [];
    const mediaTypes = /* @__PURE__ */ new Set(["svg", "image", "video", "gif"]);
    const search = (node) => {
      if (node.item && mediaTypes.has(node.item.type)) {
        const item = node.item;
        mediaNodes.push({
          id: node.id,
          name: item.name,
          type: item.type,
          url: item.url,
          width: item.width,
          height: item.height
        });
      }
      if (node.children) {
        node.children.forEach(search);
      }
    };
    (conf.roots || []).forEach(search);
    return mediaNodes;
  }
  function findAllTextNodes() {
    const conf = getConf();
    const textNodes = [];
    const search = (node) => {
      if (node.item?.type === "text") {
        const item = node.item;
        textNodes.push({
          id: node.id,
          name: item.name,
          text: item.text,
          fontSize: item.fontSize,
          fontFamily: item.font?.name
        });
      }
      if (node.children) {
        node.children.forEach(search);
      }
    };
    (conf.roots || []).forEach(search);
    return textNodes;
  }
  function getArtboards() {
    const conf = getConf();
    return conf.roots.filter((r) => r.item?.type === "artboard").map((r) => {
      const item = r.item;
      return {
        id: r.id,
        name: item.name,
        width: item.width,
        height: item.height,
        duration: item.duration
      };
    });
  }
  function findNodesByType(type) {
    const conf = getConf();
    const nodes = [];
    const search = (node) => {
      if (node.item?.type === type) {
        nodes.push(node);
      }
      if (node.children) {
        node.children.forEach(search);
      }
    };
    (conf.roots || []).forEach(search);
    return nodes;
  }
  function findNodesByName(name) {
    const conf = getConf();
    const nodes = [];
    const lowerName = name.toLowerCase();
    const search = (node) => {
      const nodeName = node.item?.name;
      if (nodeName && nodeName.toLowerCase().includes(lowerName)) {
        nodes.push(node);
      }
      if (node.children) {
        node.children.forEach(search);
      }
    };
    (conf.roots || []).forEach(search);
    return nodes;
  }
  function getParentNode(nodeId) {
    const node = findNodeById(nodeId);
    if (!node?.position?.parentId) {
      return null;
    }
    return findNodeById(node.position.parentId);
  }
  function getAncestors(nodeId) {
    const ancestors = [];
    let current = findNodeById(nodeId);
    while (current?.position?.parentId) {
      const parent = findNodeById(current.position.parentId);
      if (parent) {
        ancestors.push(parent);
        current = parent;
      } else {
        break;
      }
    }
    return ancestors;
  }
  function flattenTree() {
    const conf = getConf();
    const nodes = [];
    const collect = (node) => {
      nodes.push(node);
      if (node.children) {
        node.children.forEach(collect);
      }
    };
    (conf.roots || []).forEach(collect);
    return nodes;
  }

  // utils/actions.ts
  function dispatch(action) {
    window.app.dispatchAction(action);
  }
  function replaceAssetUrl(nodeId, newUrl) {
    dispatch({
      type: "updateObjWithUndo",
      objId: nodeId,
      data: { url: newUrl }
    });
  }
  function replaceText(nodeId, newText) {
    dispatch({
      type: "updateObjWithUndo",
      objId: nodeId,
      data: { text: newText }
    });
  }
  function updateNode(nodeId, properties) {
    dispatch({
      type: "updateObjWithUndo",
      objId: nodeId,
      data: properties
    });
  }
  function batchReplace(replacements) {
    for (const { nodeId, data } of replacements) {
      dispatch({
        type: "updateObjWithUndo",
        objId: nodeId,
        data
      });
    }
  }
  function selectNodes(nodeIds) {
    dispatch({
      type: "setSelection",
      selection: { nodesIds: nodeIds },
      saveInCmdHistory: true
    });
  }
  function clearSelection() {
    dispatch({ type: "emptySelection" });
  }
  function deleteSelection() {
    dispatch({ type: "deleteCurrentSelection" });
  }
  function removeNodes(nodeIds) {
    dispatch({
      type: "removeObjWithUndo",
      objIds: nodeIds
    });
  }
  function undo() {
    dispatch({ type: "undo" });
  }
  function redo() {
    dispatch({ type: "redo" });
  }
  function renameNode(nodeId, newName) {
    selectNodes([nodeId]);
    dispatch({
      type: "renameSelection",
      name: newName
    });
  }
  function moveNode(nodeId, x, y) {
    dispatch({
      type: "updateObjWithUndo",
      objId: nodeId,
      data: { x, y }
    });
  }
  function resizeNode(nodeId, width, height) {
    dispatch({
      type: "updateObjWithUndo",
      objId: nodeId,
      data: { width, height }
    });
  }
  function setOpacity(nodeId, opacity) {
    dispatch({
      type: "updateObjWithUndo",
      objId: nodeId,
      data: { opacity }
    });
  }
  function setRotation(nodeId, angle) {
    dispatch({
      type: "updateObjWithUndo",
      objId: nodeId,
      data: { angle }
    });
  }
  function setCurrentTime(artboardId, timeMs) {
    dispatch({
      type: "setArtboardsTime",
      times: { [artboardId]: timeMs }
    });
  }
  function jumpToStart() {
    dispatch({ type: "jumpToStartTime" });
  }
  function jumpToEnd() {
    dispatch({ type: "jumpToEndTime" });
  }
  function addObject(parentId, id, item, index) {
    dispatch({ type: "saveSelectionForUndo" });
    dispatch({
      type: "addObjWithUndo",
      parentId,
      objData: { id, item },
      index
    });
    selectNodes([id]);
  }

  // utils/export.ts
  function generateExportUrl(options) {
    const { fileId, artboardId, width, height, profile = "lottie" } = options;
    const params = new URLSearchParams({
      file: fileId,
      artboardId,
      profile,
      width: width.toString(),
      height: height.toString()
    });
    return `https://jitter.video/export/?${params.toString()}`;
  }
  function generateExportUrlFromCurrentProject(options = {}) {
    const { artboardName, profile = "lottie" } = options;
    const fileId = window.app.props.fileMeta.id;
    const artboards = getArtboards();
    const artboard = artboardName ? artboards.find((a) => a.name === artboardName) : artboards[0];
    if (!artboard) {
      throw new Error(
        artboardName ? `Artboard "${artboardName}" not found` : "No artboard found in project"
      );
    }
    return generateExportUrl({
      fileId,
      artboardId: artboard.id,
      width: artboard.width,
      height: artboard.height,
      profile
    });
  }
  function parseJitterUrl(url) {
    const parsed = new URL(url);
    return {
      fileId: parsed.searchParams.get("id"),
      nodeId: parsed.searchParams.get("nodeId")
    };
  }
  function getFileMeta() {
    return window.app.props.fileMeta;
  }
  function generateNodeUrl(fileId, nodeId) {
    const params = new URLSearchParams({
      id: fileId,
      nodeId
    });
    return `https://jitter.video/file/?${params.toString()}`;
  }
  function getCurrentProjectUrl(nodeId) {
    const fileId = window.app.props.fileMeta.id;
    const params = new URLSearchParams({ id: fileId });
    if (nodeId) {
      params.set("nodeId", nodeId);
    }
    return `https://jitter.video/file/?${params.toString()}`;
  }

  // utils/snapshot.ts
  function createSnapshot(nodeIds) {
    const snapshot = {};
    for (const nodeId of nodeIds) {
      const node = findNodeById(nodeId);
      if (node?.item) {
        snapshot[nodeId] = JSON.parse(JSON.stringify(node.item));
      }
    }
    return snapshot;
  }
  function restoreFromSnapshot(snapshot) {
    for (const [nodeId, data] of Object.entries(snapshot)) {
      window.app.dispatchAction({
        type: "updateObjWithUndo",
        objId: nodeId,
        data
      });
    }
  }
  async function duplicateProject() {
    const currentFileId = window.app.props.fileMeta.id;
    return await window.app.props.fileActions.duplicateFile(currentFileId);
  }
  async function deleteProject(fileId) {
    await window.app.props.fileActions.deleteFile(fileId);
  }
  function createMediaSnapshot() {
    const conf = window.app.props.observableImmutableConf.lastImmutableConf;
    const nodeIds = [];
    const mediaTypes = /* @__PURE__ */ new Set(["svg", "image", "video", "gif"]);
    const collectIds = (node) => {
      if (node.item && mediaTypes.has(node.item.type)) {
        nodeIds.push(node.id);
      }
      if (node.children) {
        node.children.forEach(collectIds);
      }
    };
    (conf.roots || []).forEach(collectIds);
    return {
      snapshot: createSnapshot(nodeIds),
      nodeIds
    };
  }
  function createTextSnapshot() {
    const conf = window.app.props.observableImmutableConf.lastImmutableConf;
    const nodeIds = [];
    const collectIds = (node) => {
      if (node.item?.type === "text") {
        nodeIds.push(node.id);
      }
      if (node.children) {
        node.children.forEach(collectIds);
      }
    };
    (conf.roots || []).forEach(collectIds);
    return {
      snapshot: createSnapshot(nodeIds),
      nodeIds
    };
  }
  async function withTemporaryChanges(nodeIds, changes, callback) {
    const snapshot = createSnapshot(nodeIds);
    try {
      for (const [nodeId, data] of Object.entries(changes)) {
        window.app.dispatchAction({
          type: "updateObjWithUndo",
          objId: nodeId,
          data
        });
      }
      await new Promise((resolve) => setTimeout(resolve, 1e3));
      return await callback();
    } finally {
      restoreFromSnapshot(snapshot);
    }
  }

  // utils/wait.ts
  function waitForApp(timeoutMs = 3e4) {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const check = () => {
        if (Date.now() - startTime > timeoutMs) {
          reject(new Error("Timeout waiting for Jitter app to load"));
          return;
        }
        const app = window.app;
        if (app?.props?.observableImmutableConf?.lastImmutableConf) {
          resolve(app);
        } else {
          setTimeout(check, 100);
        }
      };
      check();
    });
  }
  function waitForSync(delayMs = 2e3) {
    return new Promise((resolve) => {
      setTimeout(resolve, delayMs);
    });
  }
  function waitFor(condition, options = {}) {
    const { timeout = 3e4, interval = 100 } = options;
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const check = () => {
        if (Date.now() - startTime > timeout) {
          reject(new Error("Timeout waiting for condition"));
          return;
        }
        if (condition()) {
          resolve();
        } else {
          setTimeout(check, interval);
        }
      };
      check();
    });
  }
  function waitForNode(nodeId, timeoutMs = 1e4) {
    return waitFor(
      () => {
        const conf = window.app?.props?.observableImmutableConf?.lastImmutableConf;
        if (!conf) {
          return false;
        }
        const search = (node) => {
          if (node.id === nodeId) {
            return true;
          }
          if (node.children) {
            return node.children.some(search);
          }
          return false;
        };
        return (conf.roots || []).some(search);
      },
      { timeout: timeoutMs }
    );
  }
  function waitForConfigChange(timeoutMs = 5e3) {
    return new Promise((resolve, reject) => {
      const timeout = setTimeout(() => {
        unsubscribe();
        reject(new Error("Timeout waiting for config change"));
      }, timeoutMs);
      const unsubscribe = window.app.props.observableImmutableConf.subscribe(() => {
        clearTimeout(timeout);
        unsubscribe();
        resolve();
      });
    });
  }
  function isReadOnly() {
    return window.app?.isReadOnly?.() ?? false;
  }
  function isAppReady() {
    return !!(window.app?.props?.observableImmutableConf?.lastImmutableConf && window.app?.props?.fileMeta?.id);
  }

  // utils/index.ts
  var jitterUtils = {
    // Traverse
    findNodeById,
    findAllMediaNodes,
    findAllTextNodes,
    getArtboards,
    findNodesByType,
    findNodesByName,
    getParentNode,
    getAncestors,
    flattenTree,
    // Actions
    replaceAssetUrl,
    replaceText,
    updateNode,
    batchReplace,
    selectNodes,
    clearSelection,
    deleteSelection,
    removeNodes,
    undo,
    redo,
    renameNode,
    moveNode,
    resizeNode,
    setOpacity,
    setRotation,
    setCurrentTime,
    jumpToStart,
    jumpToEnd,
    addObject,
    // Export
    generateExportUrl,
    generateExportUrlFromCurrentProject,
    parseJitterUrl,
    getFileMeta,
    generateNodeUrl,
    getCurrentProjectUrl,
    // Snapshot
    createSnapshot,
    restoreFromSnapshot,
    duplicateProject,
    deleteProject,
    createMediaSnapshot,
    createTextSnapshot,
    withTemporaryChanges,
    // Wait
    waitForApp,
    waitForSync,
    waitFor,
    waitForNode,
    waitForConfigChange,
    isReadOnly,
    isAppReady
  };
  if (typeof globalThis !== "undefined") {
    globalThis.jitterUtils = jitterUtils;
  }
  var index_default = jitterUtils;
  return __toCommonJS(index_exports);
})();
