import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { RoleAcl, Session, User, UserAcl, UserRole } from "@open-mercato/core/modules/auth/data/entities";
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
const INVALID_SCOPE = /* @__PURE__ */ Symbol("invalid-scope");
function normalizeScopeId(value) {
  if (value === null || value === void 0) return null;
  if (typeof value !== "string") return INVALID_SCOPE;
  const trimmed = value.trim();
  if (!trimmed) return null;
  return UUID_RE.test(trimmed) ? trimmed : INVALID_SCOPE;
}
function resolveActorTenantId(auth) {
  const actorTenantId = auth.actorTenantId;
  return normalizeScopeId(actorTenantId ?? auth.tenantId ?? null);
}
function resolveActorOrganizationId(auth) {
  const actorOrgId = auth.actorOrgId;
  return normalizeScopeId(actorOrgId ?? auth.orgId ?? null);
}
async function resolveCanonicalStaffAuthContext(em, auth) {
  if (!auth) return null;
  if (auth.isApiKey) return auth;
  const subjectId = normalizeScopeId(auth.sub);
  const actorTenantId = resolveActorTenantId(auth);
  const actorOrganizationId = resolveActorOrganizationId(auth);
  if (subjectId === INVALID_SCOPE || actorTenantId === INVALID_SCOPE || actorOrganizationId === INVALID_SCOPE) {
    return null;
  }
  const sessionId = normalizeScopeId(typeof auth.sid === "string" ? auth.sid : null);
  if (sessionId === INVALID_SCOPE) return null;
  if (sessionId === null) {
    if (auth._legacyToken === true) {
    } else {
      return null;
    }
  }
  const sessionPromise = sessionId !== null ? findOneWithDecryption(em, Session, { id: sessionId, user: subjectId, deletedAt: null }) : Promise.resolve(null);
  const userPromise = findOneWithDecryption(
    em,
    User,
    { id: subjectId, deletedAt: null },
    void 0,
    { tenantId: actorTenantId, organizationId: actorOrganizationId }
  );
  const [session, user] = await Promise.all([sessionPromise, userPromise]);
  if (sessionId !== null) {
    if (!session) return null;
    if (resolveSessionUserId(session) !== subjectId) return null;
    if (session.expiresAt.getTime() < Date.now()) return null;
  }
  if (!user) return null;
  const currentTenantId = normalizeScopeId(user.tenantId ?? null);
  const currentOrganizationId = normalizeScopeId(user.organizationId ?? null);
  if (currentTenantId === INVALID_SCOPE || currentOrganizationId === INVALID_SCOPE || currentTenantId !== actorTenantId || currentOrganizationId !== actorOrganizationId) {
    return null;
  }
  const linksPromise = currentTenantId ? findWithDecryption(
    em,
    UserRole,
    {
      user: user.id,
      deletedAt: null,
      role: { tenantId: currentTenantId, deletedAt: null }
    },
    { populate: ["role"] },
    { tenantId: currentTenantId, organizationId: currentOrganizationId }
  ) : Promise.resolve([]);
  const userAclSuperAdminPromise = currentTenantId ? userAclGrantsSuperAdmin(em, user.id, currentTenantId, currentOrganizationId) : Promise.resolve(false);
  const [links, userAclSuperAdmin] = await Promise.all([linksPromise, userAclSuperAdminPromise]);
  const linkedRoles = links.map((link) => link.role).filter((role) => !!role);
  const roles = linkedRoles.map((role) => role.name).filter((name) => typeof name === "string" && name.trim().length > 0);
  const isSuperAdmin = currentTenantId ? userAclSuperAdmin || await roleAclGrantsSuperAdmin(em, linkedRoles, currentTenantId, currentOrganizationId) : false;
  return {
    ...auth,
    sub: user.id,
    tenantId: currentTenantId,
    orgId: currentOrganizationId,
    roles,
    isSuperAdmin
  };
}
function resolveSessionUserId(session) {
  const owner = session.user;
  if (typeof owner === "string") return owner;
  if (owner && typeof owner === "object") {
    const ownerId = owner.id;
    if (typeof ownerId === "string") return ownerId;
  }
  return null;
}
async function userAclGrantsSuperAdmin(em, userId, tenantId, organizationId) {
  const userAcl = await findOneWithDecryption(
    em,
    UserAcl,
    {
      user: userId,
      tenantId,
      isSuperAdmin: true,
      deletedAt: null
    },
    void 0,
    { tenantId, organizationId }
  );
  return !!(userAcl && userAcl.isSuperAdmin === true);
}
async function roleAclGrantsSuperAdmin(em, linkedRoles, tenantId, organizationId) {
  const roleIds = Array.from(
    new Set(
      linkedRoles.map((role) => role?.id ? String(role.id) : null).filter((id) => typeof id === "string" && id.length > 0)
    )
  );
  if (!roleIds.length) return false;
  const roleAcl = await findOneWithDecryption(
    em,
    RoleAcl,
    {
      tenantId,
      isSuperAdmin: true,
      deletedAt: null,
      role: { $in: roleIds }
    },
    void 0,
    { tenantId, organizationId }
  );
  return !!(roleAcl && roleAcl.isSuperAdmin === true);
}
async function isAuthContextValid(em, auth) {
  return await resolveCanonicalStaffAuthContext(em, auth) !== null;
}
export {
  isAuthContextValid,
  resolveCanonicalStaffAuthContext
};
//# sourceMappingURL=sessionIntegrity.js.map
