import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { isOrganizationAccessAllowed } from "@open-mercato/shared/lib/auth/organizationAccess";
import { parseBooleanWithDefault } from "@open-mercato/shared/lib/boolean";
import { env } from "process";
import { createLogger } from "../logger/index.js";
const logger = createLogger("shared").child({ component: "scope" });
function buildScopeLogContext(ctx) {
  const requestInfo = ctx.request && typeof ctx.request === "object" ? {
    method: ctx.request.method ?? void 0,
    url: ctx.request.url ?? void 0
  } : null;
  const scope = ctx.organizationScope ? {
    selectedId: ctx.organizationScope.selectedId ?? null,
    tenantId: ctx.organizationScope.tenantId ?? null,
    allowedIdsCount: Array.isArray(ctx.organizationScope.allowedIds) ? ctx.organizationScope.allowedIds.length : null,
    filterIdsCount: Array.isArray(ctx.organizationScope.filterIds) ? ctx.organizationScope.filterIds.length : null
  } : null;
  return {
    userId: ctx.auth?.sub ?? null,
    actorTenantId: ctx.auth?.tenantId ?? null,
    actorOrganizationId: ctx.auth?.orgId ?? null,
    selectedOrganizationId: ctx.selectedOrganizationId ?? null,
    organizationIdsCount: Array.isArray(ctx.organizationIds) ? ctx.organizationIds.length : null,
    scope,
    request: requestInfo
  };
}
function isStrictOrganizationScopeEnforced() {
  return parseBooleanWithDefault(env.OM_ENFORCE_ORG_SCOPE_STRICT, false);
}
function logScopeViolation(ctx, expected, actual) {
  try {
    if (env.NODE_ENV !== "test") {
      logger.warn("Forbidden organization scope mismatch detected", {
        expectedId: expected,
        actualId: actual,
        ...buildScopeLogContext(ctx)
      });
    }
  } catch {
  }
}
function logUnscopedOrganizationAccess(ctx, organizationId) {
  try {
    if (env.NODE_ENV !== "test") {
      logger.warn("Unscoped organization command executed without organization context", {
        targetOrganizationId: organizationId,
        strictEnforcement: isStrictOrganizationScopeEnforced(),
        ...buildScopeLogContext(ctx)
      });
    }
  } catch {
  }
}
function logTenantScopeViolation(ctx, expectedTenantId, actualTenantId) {
  try {
    if (env.NODE_ENV !== "test") {
      logger.warn("Forbidden tenant scope mismatch detected", {
        expectedTenantId,
        actualTenantId,
        ...buildScopeLogContext(ctx)
      });
    }
  } catch {
  }
}
function ensureOrganizationScope(ctx, organizationId) {
  const isSuperAdmin = ctx.auth?.isSuperAdmin === true;
  const scope = ctx.organizationScope;
  if (!scope) {
    if (isSuperAdmin) return;
    const currentOrg2 = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
    if (currentOrg2) {
      if (currentOrg2 !== organizationId) {
        logScopeViolation(ctx, organizationId, currentOrg2);
        throw new CrudHttpError(403, { error: "Forbidden" });
      }
      return;
    }
    if (organizationId) {
      logUnscopedOrganizationAccess(ctx, organizationId);
      if (isStrictOrganizationScopeEnforced()) {
        throw new CrudHttpError(403, { error: "Forbidden" });
      }
    }
    return;
  }
  if (!scope.tenantId && organizationId && ctx.auth && !isSuperAdmin) {
    const currentOrg2 = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
    logScopeViolation(ctx, organizationId, currentOrg2);
    throw new CrudHttpError(403, { error: "Forbidden" });
  }
  if (isOrganizationAccessAllowed({
    isSuperAdmin,
    allowedOrganizationIds: scope.allowedIds,
    targetOrganizationId: organizationId
  })) {
    return;
  }
  const currentOrg = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
  logScopeViolation(ctx, organizationId, currentOrg);
  throw new CrudHttpError(403, { error: "Forbidden" });
}
function ensureTenantScope(ctx, tenantId) {
  const isSuperAdmin = ctx.auth?.isSuperAdmin === true;
  const currentTenant = ctx.auth?.tenantId ?? null;
  if (!currentTenant) {
    if (tenantId && ctx.auth && !isSuperAdmin) {
      logTenantScopeViolation(ctx, tenantId, currentTenant);
      throw new CrudHttpError(403, { error: "Forbidden" });
    }
    return;
  }
  if (currentTenant !== tenantId) {
    logTenantScopeViolation(ctx, tenantId, currentTenant);
    throw new CrudHttpError(403, { error: "Forbidden" });
  }
}
function ensureSameScope(entity, organizationId, tenantId) {
  if (entity.organizationId !== organizationId || entity.tenantId !== tenantId) {
    throw new CrudHttpError(403, { error: "Cross-tenant relation forbidden" });
  }
}
export {
  ensureOrganizationScope,
  ensureSameScope,
  ensureTenantScope
};
//# sourceMappingURL=scope.js.map
