'use strict'; const AppError = require('../../utils/AppError'); const { Setting, SETTINGS_KEY } = require('./settingModel'); const { SMS_TEMPLATE_DEFS, envFallbackFor, sanitizeTemplateId } = require('./smsTemplates'); const emptyTemplateMap = () => { const map = {}; SMS_TEMPLATE_DEFS.forEach((def) => { map[def.key] = ''; }); return map; }; const readStoredMap = (doc) => { const stored = doc?.smsTemplates || {}; if (stored instanceof Map) { return Object.fromEntries(stored.entries()); } return { ...stored }; }; const resolveTemplateId = (storedMap, def) => { const fromDb = String(storedMap[def.key] || '').trim(); if (fromDb) return fromDb; return envFallbackFor(def); }; const toPublicTemplates = (storedMap) => { return SMS_TEMPLATE_DEFS.map((def) => ({ key: def.key, label: def.label, variables: def.variables, templateId: resolveTemplateId(storedMap, def) })); }; const getSettings = async () => { const doc = await Setting.findOne({ key: SETTINGS_KEY }).lean(); const storedMap = readStoredMap(doc); return { smsTemplates: toPublicTemplates(storedMap) }; }; const getSmsTemplateId = async (key) => { const def = SMS_TEMPLATE_DEFS.find((item) => item.key === key); if (!def) return ''; const doc = await Setting.findOne({ key: SETTINGS_KEY }).lean(); return resolveTemplateId(readStoredMap(doc), def); }; const saveSettings = async (body = {}) => { const incoming = body.smsTemplates || {}; const incomingMap = Array.isArray(incoming) ? Object.fromEntries(incoming.map((item) => [item.key, item.templateId])) : incoming; const existing = await Setting.findOne({ key: SETTINGS_KEY }); const storedMap = existing ? readStoredMap(existing) : emptyTemplateMap(); const nextMap = emptyTemplateMap(); for (const def of SMS_TEMPLATE_DEFS) { const hasIncoming = Object.prototype.hasOwnProperty.call(incomingMap, def.key); if (hasIncoming) { const sanitized = sanitizeTemplateId(incomingMap[def.key]); if (sanitized === null) { throw new AppError('VALIDATION_FAILED', { field: def.key }, `Invalid SMS template ID for ${def.key}`); } nextMap[def.key] = sanitized; } else if (storedMap[def.key]) { nextMap[def.key] = String(storedMap[def.key]).trim(); } else { nextMap[def.key] = envFallbackFor(def); } } const doc = await Setting.findOneAndUpdate( { key: SETTINGS_KEY }, { $set: { smsTemplates: nextMap } }, { upsert: true, new: true, setDefaultsOnInsert: true } ); return { smsTemplates: toPublicTemplates(readStoredMap(doc)) }; }; module.exports = { getSettings, saveSettings, getSmsTemplateId };