import { splitCustomFieldPayload } from "@open-mercato/shared/lib/crud/custom-fields";
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { normalizeCustomFieldValues } from "../custom-fields/normalize.js";
import { normalizeCustomFieldValues as normalizeCustomFieldValues2 } from "../custom-fields/normalize.js";
function parseWithCustomFields(schema, raw) {
  const { base, custom } = splitCustomFieldPayload(raw);
  const parsed = schema.parse(base);
  return { parsed, custom };
}
async function setCustomFieldsIfAny(opts) {
  const { values } = opts;
  if (!values || !Object.keys(values).length) return;
  const { dataEngine, entityId, recordId, tenantId, organizationId, notify = false } = opts;
  const normalized = normalizeCustomFieldValues(values);
  await dataEngine.setCustomFields({
    entityId,
    recordId,
    tenantId,
    organizationId,
    values: normalized,
    notify
  });
}
async function emitCrudSideEffects(opts) {
  const { dataEngine, action, entity, identifiers, syncOrigin, actorUserId, events, indexer } = opts;
  dataEngine.markOrmEntityChange({
    action,
    entity,
    identifiers,
    syncOrigin,
    actorUserId,
    events,
    indexer
  });
}
async function emitCrudUndoSideEffects(opts) {
  const { dataEngine, action, entity, identifiers, syncOrigin, actorUserId, events, indexer } = opts;
  if (!entity) return;
  dataEngine.markOrmEntityChange({
    action,
    entity,
    identifiers,
    syncOrigin,
    actorUserId,
    events,
    indexer
  });
}
async function flushCrudSideEffects(dataEngine, suppress) {
  await dataEngine.flushOrmEntityChanges(suppress);
}
function buildChanges(before, after, keys) {
  if (!before) return {};
  const diff = {};
  const skipped = /* @__PURE__ */ new Set(["updatedAt", "updated_at"]);
  for (const key of keys) {
    if (skipped.has(key)) continue;
    const prev = before[key];
    const next = after[key];
    if (prev !== next) diff[key] = { from: prev, to: next };
  }
  return diff;
}
function requireTenantScope(authTenantId, requested) {
  if (authTenantId && requested && requested !== authTenantId) {
    throw new CrudHttpError(403, { error: "Forbidden" });
  }
  const tenantId = requested || authTenantId;
  if (!tenantId) throw new CrudHttpError(400, { error: "Tenant scope required" });
  return tenantId;
}
function requireId(value, message = "ID is required") {
  if (typeof value === "string" && value.trim()) return value;
  if (typeof value === "number" || typeof value === "bigint") return String(value);
  if (value && typeof value === "object") {
    const source = value;
    const candidates = [
      source.id,
      source.recordId,
      isRecord(source.body) ? source.body.id : void 0,
      isRecord(source.query) ? source.query.id : void 0
    ];
    for (const candidate of candidates) {
      if (typeof candidate === "string" && candidate.trim()) return candidate;
      if (typeof candidate === "number" || typeof candidate === "bigint") return String(candidate);
    }
  }
  throw new CrudHttpError(400, { error: message });
}
function isRecord(input) {
  return !!input && typeof input === "object";
}
function snapshotsEqual(a, b) {
  if (Object.is(a, b)) return true;
  if (a == null || b == null) return a === b;
  if (typeof a !== typeof b) return false;
  if (typeof a !== "object") return false;
  if (Array.isArray(a) !== Array.isArray(b)) return false;
  if (Array.isArray(a) && Array.isArray(b)) {
    if (a.length !== b.length) return false;
    return a.every((value, index) => snapshotsEqual(value, b[index]));
  }
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;
  return keysA.every(
    (key) => snapshotsEqual(a[key], b[key])
  );
}
const AUTHOR_UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
function normalizeAuthorUserId(explicitAuthorUserId, auth) {
  if (explicitAuthorUserId && auth?.isSuperAdmin === true && auth.isApiKey !== true && AUTHOR_UUID_REGEX.test(explicitAuthorUserId)) {
    return explicitAuthorUserId;
  }
  const authSub = auth?.isApiKey ? null : auth?.sub ?? null;
  if (!authSub) return null;
  return AUTHOR_UUID_REGEX.test(authSub) ? authSub : null;
}
export {
  buildChanges,
  emitCrudSideEffects,
  emitCrudUndoSideEffects,
  flushCrudSideEffects,
  normalizeAuthorUserId,
  normalizeCustomFieldValues2 as normalizeCustomFieldValues,
  parseWithCustomFields,
  requireId,
  requireTenantScope,
  setCustomFieldsIfAny,
  snapshotsEqual
};
//# sourceMappingURL=helpers.js.map
