"use strict";Object.defineProperty(exports,"__esModule",{value:!0});exports.notificationService=exports.NotificationService=void 0;const db_1=require("@b/db"),RedisCache_1=require("./cache/RedisCache"),preferences_1=require("./utils/preferences");class NotificationService{constructor(){this.channels=new Map;this.initializeChannels()}static getInstance(){NotificationService.instance||(NotificationService.instance=new NotificationService);return NotificationService.instance}initializeChannels(){}registerChannel(e,t){this.channels.set(e,t)}getRegisteredChannels(){return Array.from(this.channels.keys())}getChannel(e){return this.channels.get(e)||null}async send(e){const t=async t=>{try{const i=await RedisCache_1.redisCache.checkIdempotency(e.idempotencyKey);if(i){console.log(`[NotificationService] Duplicate notification detected: ${e.idempotencyKey}`);return{success:!0,notificationId:i,channelsDelivered:[],channelsFailed:[],timestamp:new Date}}const s=await(0,preferences_1.filterChannelsByPreferencesAndType)(e.userId,e.channels,e.type);if(0===s.length){console.log(`[NotificationService] All channels blocked by user preferences for user ${e.userId}`);return{success:!1,channelsDelivered:[],channelsFailed:e.channels,errors:{ALL:"All channels blocked by user preferences"},timestamp:new Date}}const a=await Promise.allSettled(s.map(i=>this.sendToChannel(i,e,t))),n=[],r=[],c={};let o;a.forEach((e,t)=>{var i;const a=s[t];if("fulfilled"===e.status&&e.value.success){n.push(a);o=o||e.value.externalId;e.value.externalId&&RedisCache_1.redisCache.trackDelivery(e.value.externalId,a,{status:"DELIVERED",provider:e.value.messageId?e.value.messageId.split("-")[0]:void 0,messageId:e.value.messageId})}else{r.push(a);const t="rejected"===e.status?e.reason.message:(null===(i=e.value)||void 0===i?void 0:i.error)||"Unknown error";c[a]=t;o&&RedisCache_1.redisCache.trackDelivery(o,a,{status:"FAILED",error:t})}});o&&await RedisCache_1.redisCache.setIdempotency(e.idempotencyKey,o);await RedisCache_1.redisCache.incrementStat("sent",n.length);await RedisCache_1.redisCache.incrementStat("failed",r.length);for(const e of n)await RedisCache_1.redisCache.incrementStat(`channels:${e}`,1);console.log(`[NotificationService] Notification sent - ID: ${o}, Delivered: ${n.join(", ")}, Failed: ${r.join(", ")}`);return{success:n.length>0,notificationId:o,channelsDelivered:n,channelsFailed:r,errors:Object.keys(c).length>0?c:void 0,timestamp:new Date}}catch(e){console.error("[NotificationService] Error sending notification:",e);throw e}};return e.transaction?t(e.transaction):await db_1.sequelize.transaction(t)}async sendToChannel(e,t,i){const s=this.channels.get(e);if(!s){console.warn(`[NotificationService] Channel ${e} not implemented yet`);throw new Error(`Channel ${e} not implemented`)}return await s.send(t,i)}async sendBatch(e){const t=await Promise.allSettled(e.userIds.map(t=>this.send({userId:t,type:e.type,channels:e.channels,template:e.template,data:e.data,priority:e.priority,idempotencyKey:`batch-${t}-${Date.now()}`,metadata:e.metadata}))),i=[],s=[],a={};t.forEach((t,n)=>{const r=e.userIds[n];if("fulfilled"===t.status&&t.value.success)i.push(r);else{s.push(r);a[r]="rejected"===t.status?t.reason.message:"Unknown error"}});return{total:e.userIds.length,successful:i,failed:s,errors:Object.keys(a).length>0?a:void 0,timestamp:new Date}}async sendToPermission(e){try{const t=(await db_1.models.user.findAll({include:[{model:db_1.models.role,as:"role",include:[{model:db_1.models.permission,as:"permissions",through:{attributes:[]},where:{name:e.permissionName}}],required:!0}],attributes:["id"]})).map(e=>e.id);return await this.sendBatch({userIds:t,type:e.type,channels:e.channels,template:e.template,data:e.data,priority:e.priority,metadata:e.metadata})}catch(t){console.error(`[NotificationService] Failed to send to permission ${e.permissionName}:`,t);throw t}}async getDeliveryStatus(e){return await RedisCache_1.redisCache.getDeliveryStatus(e)}async getMetrics(){return await RedisCache_1.redisCache.getFormattedMetrics()}async healthCheck(){const e=await RedisCache_1.redisCache.isConnected(),t=await this.getMetrics();return{status:e?"healthy":"degraded",redis:e,channels:Array.from(this.channels.keys()),metrics:t}}}exports.NotificationService=NotificationService;exports.notificationService=NotificationService.getInstance();