import "./chunk-GD6ERDZU.js";
import {
  Zero,
  applyChange,
  idSymbol
} from "./chunk-2OFTKN5C.js";
import "./chunk-ASRS2LFV.js";
import {
  DEFAULT_TTL_MS
} from "./chunk-OZZJ3HSP.js";
import "./chunk-EZM3XBAB.js";
import "./chunk-424PT5DM.js";

// ../zero-solid/src/use-query.ts
import { createComputed, createSignal, onCleanup as onCleanup2 } from "solid-js";
import { createStore } from "solid-js/store";

// ../zero-solid/src/solid-view.ts
import { produce, reconcile } from "solid-js/store";
var COMPLETE = Object.freeze({ type: "complete" });
var UNKNOWN = Object.freeze({ type: "unknown" });
var SolidView = class {
  #input;
  #format;
  #onDestroy;
  #refetch;
  #setState;
  // Optimization: if the store is currently empty we build up
  // the view on a plain old JS object stored at #builderRoot, and return
  // that for the new state on transaction commit.  This avoids building up
  // large views from scratch via solid produce.  The proxy object used by
  // solid produce is slow and in this case we don't care about solid tracking
  // the fine grained changes (everything has changed, it's all new).  For a
  // test case with a view with 3000 rows, each row having 2 children, this
  // optimization reduced #applyChanges time from 743ms to 133ms.
  #builderRoot;
  #pendingChanges = [];
  #updateTTL;
  constructor(input, onTransactionCommit, format, onDestroy, queryComplete, updateTTL, setState, refetch) {
    this.#input = input;
    onTransactionCommit(this.#onTransactionCommit);
    this.#format = format;
    this.#onDestroy = onDestroy;
    this.#updateTTL = updateTTL;
    this.#refetch = refetch;
    input.setOutput(this);
    const initialRoot = this.#createEmptyRoot();
    this.#applyChangesToRoot(
      input.fetch({}),
      (node) => ({ type: "add", node }),
      initialRoot
    );
    this.#setState = setState;
    this.#setState(
      reconcile(
        [
          initialRoot,
          queryComplete === true ? COMPLETE : "error" in queryComplete ? this.#makeError(queryComplete) : UNKNOWN
        ],
        {
          // solidjs's types want a string, but a symbol works
          key: idSymbol
        }
      )
    );
    if (isEmptyRoot(initialRoot)) {
      this.#builderRoot = this.#createEmptyRoot();
    }
    if (queryComplete !== true && !("error" in queryComplete)) {
      void queryComplete.then(() => {
        this.#setState((prev) => [prev[0], COMPLETE]);
      }).catch((error) => {
        this.#setState((prev) => [prev[0], this.#makeError(error)]);
      });
    }
  }
  #makeError(error) {
    return {
      type: "error",
      refetch: this.#refetch,
      error: error.error === "app" || error.error === "zero" ? {
        type: "app",
        queryName: error.name,
        details: error.details
      } : {
        type: "http",
        queryName: error.name,
        status: error.status,
        details: error.details
      }
    };
  }
  destroy() {
    this.#onDestroy();
  }
  #onTransactionCommit = () => {
    const builderRoot = this.#builderRoot;
    if (builderRoot) {
      if (!isEmptyRoot(builderRoot)) {
        this.#setState(
          0,
          reconcile(builderRoot, {
            // solidjs's types want a string, but a symbol works
            key: idSymbol
          })
        );
        this.#setState((prev) => [builderRoot, prev[1]]);
        this.#builderRoot = void 0;
      }
    } else {
      try {
        this.#applyChanges(this.#pendingChanges, (c) => c);
      } finally {
        this.#pendingChanges = [];
      }
    }
  };
  push(change) {
    if (this.#builderRoot) {
      this.#applyChangeToRoot(change, this.#builderRoot);
    } else {
      this.#pendingChanges.push(materializeRelationships(change));
    }
  }
  #applyChanges(changes, mapper) {
    this.#setState(
      produce((draftState) => {
        this.#applyChangesToRoot(changes, mapper, draftState[0]);
        if (isEmptyRoot(draftState[0])) {
          this.#builderRoot = this.#createEmptyRoot();
        }
      })
    );
  }
  #applyChangesToRoot(changes, mapper, root) {
    for (const change of changes) {
      this.#applyChangeToRoot(mapper(change), root);
    }
  }
  #applyChangeToRoot(change, root) {
    applyChange(
      root,
      change,
      this.#input.getSchema(),
      "",
      this.#format,
      true
    );
  }
  #createEmptyRoot() {
    return {
      "": this.#format.singular ? void 0 : []
    };
  }
  updateTTL(ttl) {
    this.#updateTTL(ttl);
  }
};
function materializeRelationships(change) {
  switch (change.type) {
    case "add":
      return { type: "add", node: materializeNodeRelationships(change.node) };
    case "remove":
      return { type: "remove", node: materializeNodeRelationships(change.node) };
    case "child":
      return {
        type: "child",
        node: { row: change.node.row },
        child: {
          relationshipName: change.child.relationshipName,
          change: materializeRelationships(change.child.change)
        }
      };
    case "edit":
      return {
        type: "edit",
        node: { row: change.node.row },
        oldNode: { row: change.oldNode.row }
      };
  }
}
function materializeNodeRelationships(node) {
  const relationships = {};
  for (const relationship in node.relationships) {
    const materialized = [];
    for (const n of node.relationships[relationship]()) {
      materialized.push(materializeNodeRelationships(n));
    }
    relationships[relationship] = () => materialized;
  }
  return {
    row: node.row,
    relationships
  };
}
function isEmptyRoot(entry) {
  const data = entry[""];
  return data === void 0 || Array.isArray(data) && data.length === 0;
}
function createSolidViewFactory(setState, refetch) {
  function solidViewFactory(_query, input, format, onDestroy, onTransactionCommit, queryComplete, updateTTL) {
    return new SolidView(
      input,
      onTransactionCommit,
      format,
      onDestroy,
      queryComplete,
      updateTTL,
      setState,
      refetch || (() => {
      })
    );
  }
  solidViewFactory;
  return solidViewFactory;
}

// ../zero-solid/src/use-zero.ts
import {
  batch,
  createContext,
  createMemo,
  onCleanup,
  splitProps,
  useContext
} from "solid-js";
var ZeroContext = createContext(
  void 0
);
function createZero(options) {
  const opts = {
    ...options,
    batchViewUpdates: batch
  };
  return new Zero(opts);
}
function useZero() {
  const zero = useContext(ZeroContext);
  if (zero === void 0) {
    throw new Error("useZero must be used within a ZeroProvider");
  }
  return zero;
}
function createUseZero() {
  return () => useZero();
}
function ZeroProvider(props) {
  const zero = createMemo(() => {
    if ("zero" in props) {
      return props.zero;
    }
    const [, options] = splitProps(props, ["children"]);
    const createdZero = new Zero({
      ...options,
      batchViewUpdates: batch
    });
    onCleanup(() => createdZero.close());
    return createdZero;
  });
  return ZeroContext.Provider({
    value: zero,
    get children() {
      return props.children;
    }
  });
}

// ../zero-solid/src/use-query.ts
function createQuery(querySignal, options) {
  return useQuery(querySignal, options);
}
function useQuery(querySignal, options) {
  const [state, setState] = createStore([
    {
      "": void 0
    },
    UNKNOWN
  ]);
  const initialRefetchKey = 0;
  const [refetchKey, setRefetchKey] = createSignal(initialRefetchKey);
  const refetch = () => {
    setRefetchKey((k) => k + 1);
  };
  let view = void 0;
  createComputed(
    ([
      prevView,
      prevClientID,
      prevQuery,
      prevQueryHash,
      prevTtl,
      prevRefetchKey
    ]) => {
      const zero = useZero()();
      const currentRefetchKey = refetchKey();
      const { clientID } = zero;
      const query = querySignal();
      const queryHash = query.hash();
      const ttl = normalize(options)?.ttl ?? DEFAULT_TTL_MS;
      if (!prevView || clientID !== prevClientID || prevRefetchKey !== currentRefetchKey || query !== prevQuery && (clientID === void 0 || query.hash() !== prevQueryHash)) {
        if (prevView) {
          prevView.destroy();
        }
        view = zero.materialize(
          query,
          createSolidViewFactory(setState, refetch),
          { ttl }
        );
      } else {
        view = prevView;
        if (ttl !== prevTtl) {
          view.updateTTL(ttl);
        }
      }
      return [view, clientID, query, queryHash, ttl, currentRefetchKey];
    },
    [void 0, void 0, void 0, void 0, void 0, initialRefetchKey]
  );
  onCleanup2(() => {
    view?.destroy();
  });
  return [() => state[0][""], () => state[1]];
}
function normalize(options) {
  return typeof options === "function" ? options() : options;
}

// ../zero-solid/src/use-zero-online.ts
import { createSignal as createSignal2, onCleanup as onCleanup3 } from "solid-js";
function useZeroOnline() {
  const zero = useZero()();
  const [online, setOnline] = createSignal2(zero.online);
  const unsubscribe = zero.onOnline(setOnline);
  onCleanup3(unsubscribe);
  return online;
}
export {
  ZeroProvider,
  createQuery,
  createUseZero,
  createZero,
  useQuery,
  useZero,
  useZeroOnline
};
//# sourceMappingURL=solid.js.map
