// src/services/whatsappService.js const { randomDelay, sleep } = require('../utils'); const logger = require('../logger'); const config = require('../config'); let sockInstance = null; /** * Initializes the WhatsApp Service with the Baileys socket instance. * Should be called once after connection is established. * @param {object} sock - The Baileys socket instance. */ function initialize(sock) { if (!sockInstance) { sockInstance = sock; logger.info('WhatsApp Service Initialized.'); } } /** * Sends a presence update (typing, paused, available, unavailable). * @param {'composing' | 'paused' | 'available' | 'unavailable'} status - The presence status. * @param {string} jid - The target JID. */ async function sendPresenceUpdate(status, jid) { if (!sockInstance) return logger.error('WhatsApp Service not initialized for sendPresenceUpdate'); try { await sockInstance.sendPresenceUpdate(status, jid); } catch (err) { logger.error({ err, jid, status }, '[WhatsAppService] Failed to send presence update'); } } /** * Marks specific messages as read. * @param {Array} keys - An array of message key objects. */ async function readReceipt(keys) { if (!sockInstance) return logger.error('WhatsApp Service not initialized for readReceipt'); try { await sockInstance.readMessages(keys); // Log the first key for brevity if needed if (keys && keys[0]) { logger.debug({ jid: keys[0].remoteJid, msgId: keys[0].id }, `[WhatsAppService] Marked message(s) as read`); } } catch (err) { const jid = keys && keys[0] ? keys[0].remoteJid : 'unknown'; logger.warn({ err, jid }, '[WhatsAppService] Failed to mark message(s) as read'); } } /** * Sends a message with simulated typing and random delay. * @param {string} jid - The target JID. * @param {object} message - The Baileys message object (e.g., { text: 'Hello' }). * @param {object} [options={}] - Options object. * @param {number} [options.minDelay] - Minimum delay (defaults to config.defaultMinDelay). * @param {number} [options.maxDelay] - Maximum delay (defaults to config.defaultMaxDelay). * @returns {Promise} - The result from Baileys sendMessage or null on init error. */ async function sendMessageWithTyping(jid, message, options = {}) { if (!sockInstance) { logger.error({ jid, message }, 'WhatsApp Service not initialized for sendMessage'); return null; // Indicate failure } // Use provided delays or fall back to config defaults const minDelayMs = options.minDelay ?? config.defaultMinDelay; const maxDelayMs = options.maxDelay ?? config.defaultMaxDelay; try { await sendPresenceUpdate('composing', jid); await randomDelay(minDelayMs, maxDelayMs); await sendPresenceUpdate('paused', jid); // Clear composing state before sending const result = await sockInstance.sendMessage(jid, message); logger.debug({ jid, msgContent: message.text || '[Non-Text]' }, '[WhatsAppService] Message sent'); return result; } catch (err) { logger.error({ err, jid, msgContent: message.text || '[Non-Text]' }, '[WhatsAppService] Failed to send message'); // Re-throw error for the calling handler to potentially manage // Avoid sending another message from here to prevent loops throw err; } } module.exports = { initialize, sendMessageWithTyping, readReceipt, // Only export specific actions needed by handlers };