import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { enforceCommandOptimisticLockWithGuards } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
import { assertFound } from "@open-mercato/shared/lib/crud/errors";
import { ensureOrganizationScope, ensureSameScope, ensureTenantScope } from "@open-mercato/shared/lib/commands/scope";
import { extractUndoPayload } from "@open-mercato/shared/lib/commands/undo";
const SALES_RESOURCE_KIND_ORDER = "sales.order";
const SALES_RESOURCE_KIND_QUOTE = "sales.quote";
const SALES_RESOURCE_KIND_RETURN = "sales.return";
async function enforceSalesDocumentOptimisticLock(ctx, document, resourceKind) {
  if (!document) return;
  await enforceCommandOptimisticLockWithGuards(ctx.container, {
    resourceKind,
    resourceId: document.id,
    current: document.updatedAt ?? null,
    request: ctx.request ?? null
  });
}
function cloneJson(value) {
  if (value === null || value === void 0) return value;
  return JSON.parse(JSON.stringify(value));
}
function toNumericString(value) {
  if (value === void 0 || value === null) return null;
  return value.toString();
}
const LINE_AMOUNT_SCALE = 4;
function parseLineAmount(value) {
  if (typeof value === "number") return Number.isFinite(value) ? value : 0;
  if (typeof value === "string" && value.trim().length) {
    const parsed = Number(value);
    if (!Number.isNaN(parsed)) return parsed;
  }
  return 0;
}
function roundLineAmount(value) {
  const factor = 10 ** LINE_AMOUNT_SCALE;
  return Math.round((value + Number.EPSILON) * factor) / factor;
}
function deriveLineNetFromGross(net, gross, taxRate) {
  const netValue = parseLineAmount(net);
  const grossValue = parseLineAmount(gross);
  if (grossValue > 0 && netValue <= 0) {
    const rate = parseLineAmount(taxRate);
    const fraction = rate > 0 ? rate / 100 : 0;
    return roundLineAmount(fraction > 0 ? grossValue / (1 + fraction) : grossValue);
  }
  return netValue;
}
function reconcileLinePersistedTotals(payload) {
  const gross = parseLineAmount(payload.totalGrossAmount);
  const net = parseLineAmount(payload.totalNetAmount);
  if (gross <= 0 || net > 0) return payload;
  const derivedNet = toNumericString(deriveLineNetFromGross(net, gross, payload.taxRate));
  if (derivedNet == null) return payload;
  return { ...payload, totalNetAmount: derivedNet };
}
async function requireScopedEntity(em, entityClass, id, message, scope = { organizationId: null, tenantId: null }) {
  const where = { id, deletedAt: null };
  if (scope.organizationId) where.organizationId = scope.organizationId;
  if (scope.tenantId) where.tenantId = scope.tenantId;
  const entity = await findOneWithDecryption(em, entityClass, where, {}, scope);
  if (!entity) throw new CrudHttpError(404, { error: message });
  return entity;
}
export {
  SALES_RESOURCE_KIND_ORDER,
  SALES_RESOURCE_KIND_QUOTE,
  SALES_RESOURCE_KIND_RETURN,
  assertFound,
  cloneJson,
  deriveLineNetFromGross,
  enforceSalesDocumentOptimisticLock,
  ensureOrganizationScope,
  ensureSameScope,
  ensureTenantScope,
  extractUndoPayload,
  reconcileLinePersistedTotals,
  requireScopedEntity,
  toNumericString
};
//# sourceMappingURL=shared.js.map
