// src/db/field-value.ts
function serverTimestamp() {
  return { __neetru__: "serverTimestamp" };
}
function increment(n) {
  if (typeof n !== "number" || !Number.isFinite(n)) {
    throw new TypeError(
      `increment(n): n deve ser um n\xFAmero finito (recebido: ${String(n)}).`
    );
  }
  return { __neetru__: "increment", operand: n };
}

// src/firestore-compat.ts
function isClientWrapper(v) {
  return typeof v === "object" && v !== null && "db" in v && typeof v.db === "object" && v.db?.collection !== void 0;
}
function resolveDb(handle) {
  if (handle.__neetruFirestore) return handle.db;
  if (isClientWrapper(handle)) return handle.db;
  return handle;
}
function getFirestore(handle) {
  return { __neetruFirestore: true, db: resolveDb(handle) };
}
function collection(db, name) {
  const resolved = resolveDb(db);
  return {
    type: "collection",
    __kind: "collection",
    id: name,
    path: name,
    db: resolved,
    ref: resolved.collection(name)
  };
}
function doc(dbOrCollection, ...path) {
  if (typeof dbOrCollection === "object" && dbOrCollection !== null && dbOrCollection.__kind === "collection") {
    const col = dbOrCollection;
    const id = path[0] ?? generateId();
    return makeDocRef(col.db, col.id, id);
  }
  const resolved = resolveDb(dbOrCollection);
  if (path.length >= 2) {
    return makeDocRef(resolved, path[0], path.slice(1).join("/"));
  }
  if (path[0]?.includes("/")) {
    const parts = path[0].split("/");
    return makeDocRef(resolved, parts[0], parts.slice(1).join("/") || generateId());
  }
  return makeDocRef(resolved, path[0] ?? "", generateId());
}
function makeDocRef(db, collectionName, id) {
  return {
    type: "document",
    __kind: "document",
    id,
    collection: collectionName,
    path: `${collectionName}/${id}`,
    db
  };
}
function generateId() {
  const CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  const cryptoObj = globalThis.crypto;
  if (!cryptoObj?.getRandomValues) {
    throw new Error(
      "[Neetru SDK / firestore-compat] WebCrypto indispon\xEDvel: generateId() exige globalThis.crypto.getRandomValues (Node \u226520 ou ambiente browser)."
    );
  }
  let out = "";
  while (out.length < 20) {
    const buf = new Uint8Array(20 - out.length);
    cryptoObj.getRandomValues(buf);
    for (const byte of buf) {
      if (byte < 248) {
        out += CHARS[byte % 62];
        if (out.length === 20) break;
      }
    }
  }
  return out;
}
function query(source, ...constraints) {
  const base = source.__kind === "query" ? source : {
    type: "query",
    __kind: "query",
    path: source.path,
    collection: source.id,
    db: source.db,
    ref: source.ref,
    constraints: []
  };
  return { ...base, constraints: [...base.constraints, ...constraints] };
}
function where(field, op, value) {
  return { __constraint: "where", field, op, value };
}
function orderBy(field, direction = "asc") {
  return { __constraint: "orderBy", field, direction };
}
function limit(value) {
  return { __constraint: "limit", value };
}
function toDbQuery(constraints) {
  const whereFilters = [];
  let orderByClause;
  let limitValue;
  for (const c of constraints) {
    if (c.__constraint === "where") {
      const w = c;
      whereFilters.push({ field: w.field, op: normalizeOp(w.op), value: w.value });
    } else if (c.__constraint === "orderBy") {
      const o = c;
      orderByClause = { field: o.field, direction: o.direction };
    } else if (c.__constraint === "limit") {
      limitValue = c.value;
    }
  }
  const out = {};
  if (whereFilters.length > 0) out.where = whereFilters;
  if (orderByClause) out.orderBy = orderByClause;
  if (limitValue !== void 0) out.limit = limitValue;
  return out;
}
function normalizeOp(op) {
  return op;
}
function stripId(raw) {
  if (raw && typeof raw === "object" && "id" in raw) {
    const { id: _omit, ...rest } = raw;
    return rest;
  }
  return raw;
}
var DocumentSnapshot = class {
  constructor(id, _data, ref) {
    this.id = id;
    this._data = _data;
    this.ref = ref;
  }
  id;
  _data;
  ref;
  exists() {
    return this._data != null;
  }
  data() {
    return this._data ?? void 0;
  }
  /** Compat: `snap.get('field')` lê um campo top-level. */
  get(field) {
    return this._data ? this._data[field] : void 0;
  }
};
var QuerySnapshot = class {
  docs;
  empty;
  size;
  constructor(rows, db, collectionName) {
    this.docs = rows.map(({ id, data }) => {
      const stripped = stripId(data);
      const ref = db && collectionName ? makeDocRef(db, collectionName, id) : void 0;
      return {
        id,
        data: () => stripped,
        exists: () => true,
        get: (field) => stripped?.[field],
        // ref sempre presente quando db+collection conhecidos (caso comum).
        ref
      };
    });
    this.empty = this.docs.length === 0;
    this.size = this.docs.length;
  }
  forEach(cb) {
    this.docs.forEach(cb);
  }
};
function firstDocData(result) {
  const first = result?.docs[0];
  return { data: first ? first.data : null, id: first?.id ?? null };
}
async function getDoc(ref) {
  const result = await ref.db.collection(ref.collection).get(ref.id);
  const { data } = firstDocData(result);
  return new DocumentSnapshot(
    ref.id,
    data ? stripId({ id: ref.id, ...data }) : null,
    ref
  );
}
function listResultToRows(result) {
  return result.docs.map((d) => ({ id: d.id, data: { ...d.data } }));
}
async function getDocs(source) {
  const dbQuery = source.__kind === "query" ? toDbQuery(source.constraints) : void 0;
  const collectionName = source.__kind === "query" ? source.collection : source.id;
  const result = await source.db.collection(collectionName).list(dbQuery);
  return new QuerySnapshot(listResultToRows(result), source.db, collectionName);
}
async function setDoc(ref, data, options = {}) {
  const col = ref.db.collection(ref.collection);
  const payload = data;
  if (options.merge || options.mergeFields && options.mergeFields.length > 0) {
    const existing = await col.get(ref.id);
    const docExists = Array.isArray(existing?.docs) ? existing.docs.length > 0 : existing != null;
    if (docExists) {
      await col.update(ref.id, payload);
    } else {
      await col.set(ref.id, payload);
    }
  } else {
    await col.set(ref.id, payload);
  }
}
async function addDoc(source, data) {
  const result = await source.db.collection(source.id).add(data);
  return makeDocRef(source.db, source.id, result.id);
}
async function updateDoc(ref, data) {
  await ref.db.collection(ref.collection).update(ref.id, data);
}
async function deleteDoc(ref) {
  await ref.db.collection(ref.collection).remove(ref.id);
}
var WriteBatch = class {
  constructor(db) {
    this.db = db;
  }
  db;
  ops = [];
  set(ref, data, _options) {
    this.ops.push({
      collection: ref.collection,
      op: { kind: "set", id: ref.id, data }
    });
    return this;
  }
  update(ref, data) {
    this.ops.push({
      collection: ref.collection,
      op: { kind: "update", id: ref.id, data }
    });
    return this;
  }
  delete(ref) {
    this.ops.push({ collection: ref.collection, op: { kind: "remove", id: ref.id } });
    return this;
  }
  async commit() {
    const byCol = /* @__PURE__ */ new Map();
    for (const { collection: name, op } of this.ops) {
      const list = byCol.get(name) ?? [];
      list.push(op);
      byCol.set(name, list);
    }
    for (const [name, ops] of byCol.entries()) {
      await this.db.collection(name).batch(ops);
    }
    this.ops = [];
  }
};
function writeBatch(db) {
  return new WriteBatch(resolveDb(db));
}
var _runTransactionWarnEmitted = false;
async function runTransaction(db, updateFunction) {
  if (!_runTransactionWarnEmitted) {
    _runTransactionWarnEmitted = true;
    console.warn(
      "[Neetru SDK / firestore-compat] runTransaction(): esta emula\xE7\xE3o N\xC3O oferece isolamento server-side. Reads e writes s\xE3o executados em rounds separados; um write concorrente entre o get() e o commit() resultar\xE1 em lost-update silencioso. Para atomicidade real, use Server Actions no Core ou sentinels increment()/arrayUnion(). Veja a doc em src/firestore-compat.ts \xA7 runTransaction."
    );
  }
  const resolved = resolveDb(db);
  const batch = new WriteBatch(resolved);
  const tx = {
    async get(ref) {
      return getDoc(ref);
    },
    set(ref, data, options) {
      batch.set(ref, data, options);
      return tx;
    },
    update(ref, data) {
      batch.update(ref, data);
      return tx;
    },
    delete(ref) {
      batch.delete(ref);
      return tx;
    }
  };
  const result = await updateFunction(tx);
  await batch.commit();
  return result;
}
function onSnapshot(source, onNext, onError) {
  if (source.__kind === "document") {
    const ref = source;
    const docRef = ref.db.collection(ref.collection).doc(ref.id);
    try {
      return docRef.onSnapshot((snap) => {
        const data = snap?.docs[0]?.data;
        onNext(
          new DocumentSnapshot(
            ref.id,
            data ? stripId({ id: ref.id, ...data }) : null,
            ref
          )
        );
      });
    } catch (err) {
      onError?.(err instanceof Error ? err : new Error(String(err)));
      return () => {
      };
    }
  }
  const collectionName = source.__kind === "query" ? source.collection : source.id;
  const dbQuery = source.__kind === "query" ? toDbQuery(source.constraints) : void 0;
  const col = source.db.collection(collectionName);
  try {
    return col.onSnapshot(dbQuery, (snap) => {
      onNext(
        new QuerySnapshot(listResultToRows(snap), source.db, collectionName)
      );
    });
  } catch (err) {
    onError?.(err instanceof Error ? err : new Error(String(err)));
    return () => {
    };
  }
}
var Timestamp = class _Timestamp {
  constructor(seconds, nanoseconds) {
    this.seconds = seconds;
    this.nanoseconds = nanoseconds;
  }
  seconds;
  nanoseconds;
  static now() {
    return _Timestamp.fromMillis(Date.now());
  }
  static fromDate(date) {
    return _Timestamp.fromMillis(date.getTime());
  }
  static fromMillis(millis) {
    const seconds = Math.floor(millis / 1e3);
    const nanoseconds = (millis - seconds * 1e3) * 1e6;
    return new _Timestamp(seconds, nanoseconds);
  }
  toDate() {
    return new Date(this.toMillis());
  }
  toMillis() {
    return this.seconds * 1e3 + Math.floor(this.nanoseconds / 1e6);
  }
  isEqual(other) {
    return this.seconds === other.seconds && this.nanoseconds === other.nanoseconds;
  }
  valueOf() {
    return `${this.seconds.toString().padStart(12, "0")}.${this.nanoseconds.toString().padStart(9, "0")}`;
  }
  toJSON() {
    return { seconds: this.seconds, nanoseconds: this.nanoseconds };
  }
  toString() {
    return `Timestamp(seconds=${this.seconds}, nanoseconds=${this.nanoseconds})`;
  }
};
function serverTimestamp2() {
  return serverTimestamp();
}
function increment2(n) {
  return increment(n);
}
function arrayUnion(...elements) {
  return { __neetru__: "arrayUnion", elements };
}
function arrayRemove(...elements) {
  return { __neetru__: "arrayRemove", elements };
}
function deleteField() {
  return { __neetru__: "deleteField" };
}
var FieldValue = {
  serverTimestamp: serverTimestamp2,
  increment: increment2,
  arrayUnion,
  arrayRemove,
  delete: deleteField
};

export { DocumentSnapshot, FieldValue, QuerySnapshot, Timestamp, WriteBatch, addDoc, arrayRemove, arrayUnion, collection, deleteDoc, deleteField, doc, getDoc, getDocs, getFirestore, increment2 as increment, limit, onSnapshot, orderBy, query, runTransaction, serverTimestamp2 as serverTimestamp, setDoc, toDbQuery, updateDoc, where, writeBatch };
//# sourceMappingURL=firestore-compat.mjs.map
//# sourceMappingURL=firestore-compat.mjs.map