import fs from 'fs/promises';
import mustache from 'mustache';
import path from 'path';
import { Providers } from "./providers";
import { MailBuilder, MailOptions, Response } from "./build";
import { TemplateConfigManager } from './configs/templateConfigManager ';
/**
* Interfaz para la función de renderizado de plantillas.
*/
interface Render {
/**
* Renderiza una plantilla con los datos proporcionados.
*
* @template T - El tipo de los datos a inyectar en la plantilla.
* @param {T} data - Los datos que se usarán para rellenar los marcadores de posición en la plantilla.
* @param {RegExp} [regex] - Una expresión regular opcional para pre-procesar el contenido de la plantilla
* (ej., para extraer el cuerpo HTML con `/
]*>([\s\S]*?)<\/body>/`).
* @returns {Promise} Una promesa que se resuelve con el contenido HTML renderizado.
*/
render: (data: T, regex?: RegExp) => Promise;
}
/**
* Interfaz para la función de envío de correo.
*/
interface Send {
/**
* Envía un correo electrónico utilizando la plantilla renderizada.
*
* @template T - El tipo de los datos que se utilizaron para la plantilla.
* @param {MailOptions} option - Las opciones básicas del correo (destinatario, remitente, asunto).
* @param {T} data - Los datos originales usados para la plantilla (utilizados internamente por el `build` para renderizar).
* @returns {Promise} Una promesa que se resuelve con el objeto de respuesta del envío del correo.
*/
send: (option: MailOptions, data: T) => Promise;
}
/**
* Clase `SendTrigger` para iniciar el proceso de envío de correos.
* Actúa como un punto de entrada estático para configurar y enviar correos
* a través de diferentes proveedores y plantillas.
*
* @example
* ```typescript
* // Ejemplo de uso para enviar un correo Gmail con una plantilla
* SendTrigger.gmail({
* auth: {
* user: 'tu_usuario@gmail.com',
* pass: 'tu_contraseña_app'
* }
* }, 'bienvenida').send({ // 'bienvenida' es el nombre de tu archivo plantilla .mustache
* to: 'receptor@ejemplo.com',
* from: 'Mi App ',
* subject: '¡Bienvenido a nuestra plataforma!'
* }, {
* userName: 'Alice',
* loginLink: '[https://mi-app.com/login](https://mi-app.com/login)'
* });
* ```
*/
export class SendTrigger {
/**
* Prepara el envío de un correo usando el proveedor **Gmail**.
*
* @template Templates - El tipo del nombre de la plantilla.
* @param {LemurMailGmail} config - La configuración específica para el transportador de Gmail.
* @param {Templates} template - El nombre de la plantilla a utilizar (ej. 'verificacion').
* @returns {Send} Un objeto con un método `send` para ejecutar el envío.
*/
static gmail(config: LemurMailGmail, template: Templates): Send {
console.log({ step: "Gmail" }); // Log para seguimiento
return SendTrigger.build(new Providers.Gmail(config), template);
}
/**
* Prepara el envío de un correo usando el proveedor **Mailgun**.
*
* @template Templates - El tipo del nombre de la plantilla.
* @param {LemurMailMailgun} config - La configuración específica para el transportador de Mailgun.
* @param {Templates} template - El nombre de la plantilla a utilizar (ej. 'restablecer_contraseña').
* @returns {Send} Un objeto con un método `send` para ejecutar el envío.
*/
static mailgun(config: LemurMailMailgun, template: Templates): Send {
console.log({ step: "Mailgun" }); // Log para seguimiento
return SendTrigger.build(new Providers.MailGun(config), template);
}
/**
* Prepara el envío de un correo usando el proveedor **SMTP** genérico.
*
* @template Templates - El tipo del nombre de la plantilla.
* @param {LemurMailSmtp} config - La configuración específica para el transportador SMTP.
* @param {Templates} template - El nombre de la plantilla a utilizar (ej. 'notificacion').
* @returns {Send} Un objeto con un método `send` para ejecutar el envío.
*/
static smtp(config: LemurMailSmtp, template: Templates): Send {
console.log({ step: "Smtp" }); // Log para seguimiento
return SendTrigger.build(new Providers.Smtp(config), template);
}
/**
* Carga y prepara una plantilla para su renderización.
*
* @template Templates - El tipo del nombre de la plantilla.
* @param {Templates} templateName - El nombre del archivo de la plantilla (sin extensión, ej. 'mi_plantilla').
* @returns {Render} Un objeto con un método `render` para generar el HTML de la plantilla.
*/
static template(templateName: Templates): Render {
// Obtiene la ruta base de las plantillas desde el gestor de configuración.
const templatesFolderPath = TemplateConfigManager.getPath();
// Construye la ruta completa al archivo de plantilla .mustache.
const templatePath = path.join(templatesFolderPath, `${templateName}.mustache`);
console.log({ step: "Path" }); // Log para seguimiento
return {
render: async (data: T, regex?: RegExp): Promise => {
let template: string = await fs.readFile(templatePath, 'utf8');
let matches: RegExpMatchArray | null = null;
// Si se proporciona una expresión regular, intenta extraer contenido específico.
if (regex && (matches = template.match(regex)) && matches.length > 0) {
const [_, content] = matches;
template = content.trim(); // Usa la primera captura y elimina espacios en blanco.
}
console.log({ step: "template rendered" }); // Log para seguimiento
return mustache.render(template, data);
}
};
}
/**
* Método interno para construir el proceso de envío.
* Une el proveedor de correo con la funcionalidad de renderización de plantillas.
*
* @template Templates - El tipo del nombre de la plantilla.
* @param {MailBuilder} provider - La instancia del proveedor de correo (Gmail, Mailgun, Smtp).
* @param {Templates} template - El nombre de la plantilla a utilizar.
* @returns {Send} Un objeto con un método `send` que ejecuta el envío final del correo.
*/
private static build(provider: MailBuilder, template: Templates): Send {
// Obtiene la función de renderizado para la plantilla específica.
const { render } = SendTrigger.template(template);
return {
send: async function (option: MailOptions, data: T): Promise {
// Renderiza la plantilla con los datos proporcionados.
const renderedTemplate = await render(data);
console.log({ step: "Send" }); // Log para seguimiento
// Envía el correo usando el proveedor y la plantilla ya renderizada.
// TODO: Reevaluar si el método `sendMail` de `MailBuilder` necesita el parámetro `templateMain`
// dado que el HTML ya está en `option.html` o se pasaría al proveedor directamente.
// Podría ser más limpio `provider.sendMail({ ...option, html: renderedTemplate })`.
return await provider.sendMail(option, renderedTemplate);
}
};
}
}