import {
  CustomerUserAcl,
  CustomerRoleAcl,
  CustomerUserRole
} from "@open-mercato/core/modules/customer_accounts/data/entities";
import { hasAllFeatures } from "@open-mercato/shared/lib/auth/featureMatch";
function isCustomerAclData(value) {
  if (typeof value !== "object" || value === null) return false;
  const record = value;
  if (typeof record.isPortalAdmin !== "boolean") return false;
  if (!Array.isArray(record.features) || record.features.some((f) => typeof f !== "string")) return false;
  return true;
}
class CustomerRbacService {
  constructor(em, cache) {
    this.em = em;
    this.cacheTtlMs = 5 * 60 * 1e3;
    this.cache = null;
    this.cache = cache || null;
  }
  getCacheKey(userId, scope) {
    return `customer_rbac:${userId}:${scope.tenantId}:${scope.organizationId}`;
  }
  getUserTag(userId) {
    return `customer_rbac:user:${userId}`;
  }
  getTenantTag(tenantId) {
    return `customer_rbac:tenant:${tenantId}`;
  }
  async getFromCache(cacheKey) {
    if (!this.cache) return null;
    const cached = await this.cache.get(cacheKey);
    if (!cached) return null;
    return isCustomerAclData(cached) ? cached : null;
  }
  async setCache(cacheKey, data, userId, scope) {
    if (!this.cache) return;
    const tags = [
      this.getUserTag(userId),
      this.getTenantTag(scope.tenantId),
      "customer_rbac:all"
    ];
    await this.cache.set(cacheKey, data, { ttl: this.cacheTtlMs, tags });
  }
  async loadAcl(userId, scope) {
    const cacheKey = this.getCacheKey(userId, scope);
    const cached = await this.getFromCache(cacheKey);
    if (cached) return cached;
    const em = this.em.fork();
    const userAcl = await em.findOne(CustomerUserAcl, {
      user: userId,
      tenantId: scope.tenantId
    });
    if (userAcl) {
      const result2 = {
        isPortalAdmin: !!userAcl.isPortalAdmin,
        features: Array.isArray(userAcl.featuresJson) ? userAcl.featuresJson : []
      };
      await this.setCache(cacheKey, result2, userId, scope);
      return result2;
    }
    const links = await em.find(CustomerUserRole, {
      user: userId,
      deletedAt: null
    }, { populate: ["role"] });
    const roleIds = links.map((l) => l.role?.id).filter(Boolean);
    let isPortalAdmin = false;
    const features = [];
    if (roleIds.length) {
      const roleAcls = await em.find(CustomerRoleAcl, {
        tenantId: scope.tenantId,
        role: { $in: roleIds }
      });
      for (const acl of roleAcls) {
        isPortalAdmin = isPortalAdmin || !!acl.isPortalAdmin;
        if (Array.isArray(acl.featuresJson)) {
          for (const f of acl.featuresJson) {
            if (!features.includes(f)) features.push(f);
          }
        }
      }
    }
    const result = { isPortalAdmin, features };
    await this.setCache(cacheKey, result, userId, scope);
    return result;
  }
  async userHasAllFeatures(userId, required, scope) {
    if (!required.length) return true;
    const acl = await this.loadAcl(userId, scope);
    if (acl.isPortalAdmin) return true;
    return hasAllFeatures(required, acl.features);
  }
  async invalidateUserCache(userId) {
    if (!this.cache) return;
    await this.cache.deleteByTags([this.getUserTag(userId)]);
  }
  async invalidateRoleCache(roleId) {
    if (!this.cache) return;
    await this.cache.deleteByTags(["customer_rbac:all"]);
  }
  async invalidateTenantCache(tenantId) {
    if (!this.cache) return;
    await this.cache.deleteByTags([this.getTenantTag(tenantId)]);
  }
}
export {
  CustomerRbacService
};
//# sourceMappingURL=customerRbacService.js.map
