import { Injectable, Logger } from '@nestjs/common';
import * as nodemailer from 'nodemailer';
import { EmailSettingsService } from '../email-settings/email-settings.service';
import { EmailSettingsEntity } from '../email-settings/email-settings.entity';

export interface AuditEmailContext {
  /** Recipient name (e.g. 'Manzoor Ahmed' or 'Hi') */
  recipientName: string;
  /** Audit code like 'INI-2026-06-15-000001' */
  auditCode: string;
  /** Company name */
  companyName: string;
  /** Audit date as 'YYYY-MM-DD' or human format */
  auditDate: string;
  /** Audit time label like '09.00AM' (optional) */
  auditTimeLabel?: string;
  /** Auditor full name */
  auditorName?: string;
  /** Standards comma-separated e.g. 'ISO 9001:2015, ISO 14001:2015' */
  standards?: string;
  /** Schedule id for deep-link */
  scheduleId?: number;
  /** Optional: reason / extra context */
  reason?: string;
  /** Optional: notes */
  notes?: string;
  /** Optional (reschedule): old date */
  oldDate?: string;
  /** Optional (reschedule): new date */
  newDate?: string;
  /** User who triggered the action */
  triggeredByName?: string;
}

@Injectable()
export class MailsService {
  private readonly logger = new Logger(MailsService.name);
  private transporter: nodemailer.Transporter;

  // per-user transporters, keyed by config id
  private readonly userTransportCache = new Map<
    number,
    { transporter: nodemailer.Transporter; from: string; signature: string }
  >();

  // 🆕 CHANGE #1 — inject EmailSettingsService (was: constructor() {})
  constructor(private readonly emailSettings: EmailSettingsService) {
    this.transporter = this.createTransporter();
  }

  private createTransporter(): nodemailer.Transporter {
    const provider = process.env.MAIL_PROVIDER || 'gmail';

    switch (provider) {
      case 'gmail':
        return nodemailer.createTransport({
          service: 'gmail',
          auth: {
            user: process.env.GMAIL_USER,
            pass: process.env.GMAIL_PASS,
          },
        });

      case 'outlook':
        return nodemailer.createTransport({
          host: 'smtp.office365.com',
          port: 587,
          secure: false,
          auth: {
            user: process.env.OUTLOOK_USER,
            pass: process.env.OUTLOOK_PASS,
          },
        });

      case 'zoho':
        return nodemailer.createTransport({
          host: 'smtp.zoho.com',
          port: 587,
          secure: false,
          auth: {
            user: process.env.ZOHO_USER,
            pass: process.env.ZOHO_PASS,
          },
        });

      case 'sendgrid':
        return nodemailer.createTransport({
          host: 'smtp.sendgrid.net',
          port: 587,
          secure: false,
          auth: {
            user: 'apikey',
            pass: process.env.SENDGRID_API_KEY,
          },
        });

      default:
        return nodemailer.createTransport({
          service: 'gmail',
          auth: {
            user: process.env.GMAIL_USER,
            pass: process.env.GMAIL_PASS,
          },
        });
    }
  }

  private getFromAddress(): string {
    const provider = process.env.MAIL_PROVIDER || 'gmail';
    const name = 'QRS';
    switch (provider) {
      case 'gmail':
        return `${name} <${process.env.GMAIL_USER}>`;
      case 'outlook':
        return `${name} <${process.env.OUTLOOK_USER}>`;
      case 'zoho':
        return `${name} <${process.env.ZOHO_USER}>`;
      case 'sendgrid':
        return `${name} <${process.env.SENDGRID_FROM}>`;
      default:
        return `${name} <noreply@qrs.ae>`;
    }
  }

  // ═══════════════════════════════════════════════════════════════
  // EXISTING METHODS — unchanged
  // ═══════════════════════════════════════════════════════════════

  async sendOtpEmail(
    email: string,
    otp: string,
    name: string,
    type: 'verify' | 'reset',
  ): Promise<void> {
    const isVerify = type === 'verify';
    const subject = isVerify
      ? 'Verify your QRS ERP account'
      : 'Reset your QRS ERP password';
    const title = isVerify ? 'Email Verification' : 'Password Reset';
    const message = isVerify
      ? 'Use the code below to verify your email address.'
      : 'Use the code below to reset your password.';

    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to: email,
      subject,
      html: `
        <div style="font-family:'Segoe UI',sans-serif;max-width:520px;margin:0 auto;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,0.08);">
          <div style="background:linear-gradient(135deg,#8b14d4,#4a0080);padding:32px;text-align:center;">
            <h1 style="color:#fff;font-size:20px;margin:0;">Quality Registrar Systems</h1>
            <p style="color:rgba(255,255,255,0.7);margin:6px 0 0;font-size:13px;">${title}</p>
          </div>
          <div style="padding:36px 32px;text-align:center;">
            <p style="color:#555;font-size:15px;margin:0 0 8px;">Hello, <strong>${name}</strong> 👋</p>
            <p style="color:#777;font-size:14px;line-height:1.7;margin:0 0 32px;">
              ${message} This code expires in <strong>10 minutes</strong>.
            </p>
            <div style="background:#f8f5ff;border:2px dashed #c084fc;border-radius:12px;padding:24px;display:inline-block;min-width:200px;">
              <p style="color:#888;font-size:11px;margin:0 0 8px;letter-spacing:1px;text-transform:uppercase;">Your code</p>
              <p style="color:#4a0080;font-size:42px;font-weight:800;letter-spacing:12px;margin:0;font-family:'Courier New',monospace;">${otp}</p>
            </div>
            <p style="color:#aaa;font-size:12px;margin:24px 0 0;line-height:1.7;">
              One-time use only. If you didn't request this, ignore this email.
            </p>
          </div>
          <div style="background:#f8f5ff;padding:16px 32px;text-align:center;border-top:1px solid #ede8ff;">
            <p style="color:#bbb;font-size:11px;margin:0;">© ${new Date().getFullYear()} Quality Registrar Systems.</p>
          </div>
        </div>
      `,
    });

    this.logger.log(`OTP [${type}] sent to ${email}`);
  }

  async sendApprovalEmail(email: string, name: string): Promise<void> {
    const loginUrl = `${process.env.APP_URL}/login`;

    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to: email,
      subject: '🎉 Your QRS ERP account has been approved!',
      html: `
        <div style="font-family:'Segoe UI',sans-serif;max-width:520px;margin:0 auto;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,0.08);">
          <div style="background:linear-gradient(135deg,#8b14d4,#4a0080);padding:32px;text-align:center;">
            <h1 style="color:#fff;font-size:20px;margin:0;">Quality Registrar Systems</h1>
            <p style="color:rgba(255,255,255,0.7);margin:6px 0 0;font-size:13px;">Account Approved</p>
          </div>
          <div style="padding:36px 32px;text-align:center;">
            <div style="font-size:48px;margin-bottom:16px;">🎉</div>
            <h2 style="color:#1a0440;font-size:20px;margin:0 0 12px;">Welcome aboard, ${name}!</h2>
            <p style="color:#666;font-size:14px;line-height:1.7;margin:0 0 28px;">
              Your QRS ERP account has been approved by the administrator.<br/>
              You can now log in and start using the system.
            </p>
            <a href="${loginUrl}" style="display:inline-block;padding:13px 32px;background:linear-gradient(135deg,#8b14d4,#4a0080);color:#fff;text-decoration:none;border-radius:8px;font-weight:700;font-size:15px;">
              Login to ERP →
            </a>
          </div>
          <div style="background:#f8f5ff;padding:16px 32px;text-align:center;border-top:1px solid #ede8ff;">
            <p style="color:#bbb;font-size:11px;margin:0;">© ${new Date().getFullYear()} Quality Registrar Systems.</p>
          </div>
        </div>
      `,
    });

    this.logger.log(`Approval email sent to ${email}`);
  }

  async sendPasswordChangedEmail(email: string, name: string): Promise<void> {
    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to: email,
      subject: '✅ Your QRS ERP password has been changed',
      html: `
      <div style="font-family:'Segoe UI',sans-serif;max-width:520px;margin:0 auto;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,0.08);">
        <div style="background:linear-gradient(135deg,#8b14d4,#4a0080);padding:32px;text-align:center;">
          <h1 style="color:#fff;font-size:20px;margin:0;">Quality Registrar Systems</h1>
          <p style="color:rgba(255,255,255,0.7);margin:6px 0 0;font-size:13px;">Password Changed</p>
        </div>
        <div style="padding:36px 32px;text-align:center;">
          <div style="font-size:48px;margin-bottom:16px;">🔐</div>
          <h2 style="color:#1a0440;font-size:20px;margin:0 0 12px;">Password Changed Successfully</h2>
          <p style="color:#666;font-size:14px;line-height:1.7;margin:0 0 28px;">
            Hello <strong>${name}</strong>,<br/><br/>
            Your QRS ERP account password has been successfully changed.<br/>
            You can now login with your new password.
          </p>
          <a href="${process.env.APP_URL}/login"
            style="display:inline-block;padding:13px 32px;background:linear-gradient(135deg,#8b14d4,#4a0080);color:#fff;text-decoration:none;border-radius:8px;font-weight:700;font-size:15px;">
            Login to ERP →
          </a>
          <p style="color:#e53e3e;font-size:12px;margin:24px 0 0;line-height:1.7;">
            ⚠️ If you did not make this change, please contact your administrator immediately.
          </p>
        </div>
        <div style="background:#f8f5ff;padding:16px 32px;text-align:center;border-top:1px solid #ede8ff;">
          <p style="color:#bbb;font-size:11px;margin:0;">© ${new Date().getFullYear()} Quality Registrar Systems.</p>
        </div>
      </div>
    `,
    });
    this.logger.log(`Password changed email sent to ${email}`);
  }

  // ═══════════════════════════════════════════════════════════════
  // 🆕 NEW METHODS — generic + audit-specific
  // ═══════════════════════════════════════════════════════════════

  /**
   * Generic helper — for use by NotificationsService when caller has
   * already built the HTML themselves. Wraps any HTML inside the
   * QRS shell (header + footer) if it doesn't already start with `<div`.
   */
  async sendCustom(to: string, subject: string, html: string): Promise<void> {
    const trimmed = html.trim().toLowerCase();
    const looksWrapped =
      trimmed.startsWith('<div') ||
      trimmed.startsWith('<!doctype') ||
      trimmed.startsWith('<html');
    const finalHtml = looksWrapped ? html : this.wrapInQrsShell(subject, html);

    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to,
      subject,
      html: finalHtml,
    });

    this.logger.log(`Custom email sent to ${to} — "${subject}"`);
  }

  /** Used by audit-schedules when a schedule moves from DRAFT to PUBLISHED. */
  async sendAuditPublishedEmail(
    to: string,
    ctx: AuditEmailContext,
  ): Promise<void> {
    const subject = `📅 Audit Scheduled: ${ctx.auditCode}`;
    const link = ctx.scheduleId
      ? `${process.env.APP_URL || 'https://web.qrsyst.com'}/audit-schedules/${ctx.scheduleId}`
      : null;

    const html = this.wrapInQrsShell(
      'Audit Schedule Published',
      `
        <div style="font-size:48px;margin-bottom:8px;">📅</div>
        <h2 style="color:#1a0440;font-size:20px;margin:0 0 12px;">Audit Scheduled</h2>
        <p style="color:#666;font-size:14px;line-height:1.7;margin:0 0 24px;">
          Hello <strong>${ctx.recipientName}</strong>,<br/>
          An audit has been scheduled and you have been assigned as a recipient.
        </p>
        ${this.buildAuditDetailBlock(ctx)}
        ${link
        ? `<a href="${link}" style="display:inline-block;padding:13px 32px;background:linear-gradient(135deg,#8b14d4,#4a0080);color:#fff;text-decoration:none;border-radius:8px;font-weight:700;font-size:15px;margin-top:24px;">View Schedule →</a>`
        : ''
      }
      `,
    );

    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to,
      subject,
      html,
    });
    this.logger.log(`Audit-published email sent to ${to} (${ctx.auditCode})`);
  }

  /** Used by audit-schedules when a row is cancelled. */
  async sendAuditCancelledEmail(
    to: string,
    ctx: AuditEmailContext,
  ): Promise<void> {
    const subject = `❌ Audit Cancelled: ${ctx.auditCode}`;
    const link = ctx.scheduleId
      ? `${process.env.APP_URL || 'https://web.qrsyst.com'}/audit-schedules/${ctx.scheduleId}`
      : null;

    const html = this.wrapInQrsShell(
      'Audit Cancelled',
      `
        <div style="font-size:48px;margin-bottom:8px;">❌</div>
        <h2 style="color:#1a0440;font-size:20px;margin:0 0 12px;">Audit Cancelled</h2>
        <p style="color:#666;font-size:14px;line-height:1.7;margin:0 0 24px;">
          Hello <strong>${ctx.recipientName}</strong>,<br/>
          An audit assigned to you has been <strong>cancelled</strong>.
        </p>
        ${this.buildAuditDetailBlock(ctx)}
        <div style="background:#fee2e2;border-left:4px solid #dc2626;padding:14px 18px;border-radius:8px;text-align:left;margin-top:20px;">
          <p style="margin:0;color:#991b1b;font-size:13px;"><strong>Reason:</strong> ${ctx.reason || '—'}</p>
          ${ctx.notes ? `<p style="margin:6px 0 0;color:#991b1b;font-size:13px;"><strong>Notes:</strong> ${ctx.notes}</p>` : ''}
          ${ctx.triggeredByName ? `<p style="margin:6px 0 0;color:#991b1b;font-size:12px;"><strong>Cancelled by:</strong> ${ctx.triggeredByName}</p>` : ''}
        </div>
        ${link
        ? `<a href="${link}" style="display:inline-block;padding:13px 32px;background:linear-gradient(135deg,#8b14d4,#4a0080);color:#fff;text-decoration:none;border-radius:8px;font-weight:700;font-size:15px;margin-top:24px;">View Schedule →</a>`
        : ''
      }
      `,
    );

    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to,
      subject,
      html,
    });
    this.logger.log(`Audit-cancelled email sent to ${to} (${ctx.auditCode})`);
  }

  /** Used by audit-schedules when a row is rescheduled. */
  async sendAuditRescheduledEmail(
    to: string,
    ctx: AuditEmailContext,
  ): Promise<void> {
    const subject = `🔄 Audit Rescheduled: ${ctx.auditCode}`;
    const link = ctx.scheduleId
      ? `${process.env.APP_URL || 'https://web.qrsyst.com'}/audit-schedules/${ctx.scheduleId}`
      : null;

    const html = this.wrapInQrsShell(
      'Audit Rescheduled',
      `
        <div style="font-size:48px;margin-bottom:8px;">🔄</div>
        <h2 style="color:#1a0440;font-size:20px;margin:0 0 12px;">Audit Rescheduled</h2>
        <p style="color:#666;font-size:14px;line-height:1.7;margin:0 0 24px;">
          Hello <strong>${ctx.recipientName}</strong>,<br/>
          An audit has been rescheduled to a new date.
        </p>
        ${this.buildAuditDetailBlock(ctx)}
        <div style="background:#fef3c7;border-left:4px solid #f59e0b;padding:14px 18px;border-radius:8px;text-align:left;margin-top:20px;">
          <p style="margin:0;color:#92400e;font-size:13px;"><strong>Original date:</strong> ${ctx.oldDate || '—'}</p>
          <p style="margin:6px 0;color:#92400e;font-size:13px;"><strong>New date:</strong> ${ctx.newDate || '—'} ${ctx.auditTimeLabel ? `at ${ctx.auditTimeLabel}` : ''}</p>
          ${ctx.reason ? `<p style="margin:6px 0 0;color:#92400e;font-size:13px;"><strong>Reason:</strong> ${ctx.reason}</p>` : ''}
          ${ctx.triggeredByName ? `<p style="margin:6px 0 0;color:#92400e;font-size:12px;"><strong>Rescheduled by:</strong> ${ctx.triggeredByName}</p>` : ''}
        </div>
        ${link
        ? `<a href="${link}" style="display:inline-block;padding:13px 32px;background:linear-gradient(135deg,#8b14d4,#4a0080);color:#fff;text-decoration:none;border-radius:8px;font-weight:700;font-size:15px;margin-top:24px;">View Schedule →</a>`
        : ''
      }
      `,
    );

    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to,
      subject,
      html,
    });
    this.logger.log(`Audit-rescheduled email sent to ${to} (${ctx.auditCode})`);
  }

  /** Used by audit-schedules when bulk cancel hits an entire schedule. */
  async sendAuditBulkCancelledEmail(
    to: string,
    ctx: AuditEmailContext & { affectedCount?: number },
  ): Promise<void> {
    const subject = `❌ All Audits Cancelled on ${ctx.auditDate}`;
    const link = ctx.scheduleId
      ? `${process.env.APP_URL || 'https://web.qrsyst.com'}/audit-schedules/${ctx.scheduleId}`
      : null;

    const html = this.wrapInQrsShell(
      'Audits Cancelled',
      `
        <div style="font-size:48px;margin-bottom:8px;">🚫</div>
        <h2 style="color:#1a0440;font-size:20px;margin:0 0 12px;">All Audits Cancelled</h2>
        <p style="color:#666;font-size:14px;line-height:1.7;margin:0 0 24px;">
          Hello <strong>${ctx.recipientName}</strong>,<br/>
          All <strong>${ctx.affectedCount ?? ''} audits</strong> scheduled for <strong>${ctx.auditDate}</strong> have been cancelled.
        </p>
        <div style="background:#fee2e2;border-left:4px solid #dc2626;padding:14px 18px;border-radius:8px;text-align:left;">
          <p style="margin:0;color:#991b1b;font-size:13px;"><strong>Reason:</strong> ${ctx.reason || '—'}</p>
          ${ctx.notes ? `<p style="margin:6px 0 0;color:#991b1b;font-size:13px;"><strong>Notes:</strong> ${ctx.notes}</p>` : ''}
          ${ctx.triggeredByName ? `<p style="margin:6px 0 0;color:#991b1b;font-size:12px;"><strong>Cancelled by:</strong> ${ctx.triggeredByName}</p>` : ''}
        </div>
        ${link
        ? `<a href="${link}" style="display:inline-block;padding:13px 32px;background:linear-gradient(135deg,#8b14d4,#4a0080);color:#fff;text-decoration:none;border-radius:8px;font-weight:700;font-size:15px;margin-top:24px;">View Schedule →</a>`
        : ''
      }
      `,
    );

    await this.transporter.sendMail({
      from: this.getFromAddress(),
      to,
      subject,
      html,
    });
    this.logger.log(`Audit-bulk-cancelled email sent to ${to}`);
  }

  // ═══════════════════════════════════════════════════════════════
  // PRIVATE HELPERS (used by audit emails)
  // ═══════════════════════════════════════════════════════════════

  private wrapInQrsShell(headerLabel: string, innerHtml: string): string {
    return `
      <div style="font-family:'Segoe UI',sans-serif;max-width:560px;margin:0 auto;background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,0.08);">
        <div style="background:linear-gradient(135deg,#8b14d4,#4a0080);padding:32px;text-align:center;">
          <h1 style="color:#fff;font-size:20px;margin:0;">Quality Registrar Systems</h1>
          <p style="color:rgba(255,255,255,0.7);margin:6px 0 0;font-size:13px;">${headerLabel}</p>
        </div>
        <div style="padding:36px 32px;text-align:center;">
          ${innerHtml}
        </div>
        <div style="background:#f8f5ff;padding:16px 32px;text-align:center;border-top:1px solid #ede8ff;">
          <p style="color:#bbb;font-size:11px;margin:0;">© ${new Date().getFullYear()} Quality Registrar Systems.</p>
        </div>
      </div>
    `;
  }

  private buildAuditDetailBlock(ctx: AuditEmailContext): string {
    return `
      <div style="background:#f8f5ff;border:1px solid #ede8ff;border-radius:12px;padding:18px 22px;text-align:left;margin:0 auto;">
        <table style="width:100%;border-collapse:collapse;font-size:13px;color:#555;">
          <tr>
            <td style="padding:5px 0;color:#888;width:40%;">Audit Code:</td>
            <td style="padding:5px 0;color:#1a0440;font-weight:700;font-family:'Courier New',monospace;">${ctx.auditCode}</td>
          </tr>
          <tr>
            <td style="padding:5px 0;color:#888;">Company:</td>
            <td style="padding:5px 0;color:#1a0440;font-weight:600;">${ctx.companyName}</td>
          </tr>
          <tr>
            <td style="padding:5px 0;color:#888;">Date:</td>
            <td style="padding:5px 0;color:#1a0440;font-weight:600;">${ctx.auditDate}${ctx.auditTimeLabel ? ` · ${ctx.auditTimeLabel}` : ''}</td>
          </tr>
          ${ctx.auditorName
        ? `<tr><td style="padding:5px 0;color:#888;">Auditor:</td><td style="padding:5px 0;color:#1a0440;font-weight:600;">${ctx.auditorName}</td></tr>`
        : ''
      }
          ${ctx.standards
        ? `<tr><td style="padding:5px 0;color:#888;">Standards:</td><td style="padding:5px 0;color:#1a0440;font-weight:600;">${ctx.standards}</td></tr>`
        : ''
      }
        </table>
      </div>
    `;
  }

  // ═══════════════════════════════════════════════════════════════
  // 🆕 CHANGE #2 — PER-USER SENDING (added at the bottom of the class)
  //    Uses email_settings via EmailSettingsService. Everything above
  //    is untouched and still sends from the default env sender.
  // ═══════════════════════════════════════════════════════════════

  /**
   * Send FROM the SMTP account assigned to `userId`.
   * If the user has no email_settings row, falls back to the DEFAULT env
   * transporter — i.e. the existing generic sender.
   */
  async sendAsUser(
    userId: number | null,
    opts: {
      to: string | string[];
      subject: string;
      html?: string;
      text?: string;
      cc?: string | string[];
      bcc?: string | string[];
      replyTo?: string;
      attachments?: nodemailer.SendMailOptions['attachments'];
      scheme?: 'QRS' | 'TQS';   // 👈 NEW — optional brand hint
    },
  ): Promise<void> {
    // 👇 NEW — separate scheme from mail options
    const { scheme, ...mailOpts } = opts;

    // 👇 CHANGED — scheme-aware lookup when scheme provided, else old behavior
    const cfg = userId
      ? scheme
        ? await this.emailSettings.getRawForUserAndScheme(userId, scheme)
        : await this.emailSettings.getRawForUser(userId)
      : null;

    if (!cfg) {
      // 👇 NEW — STRICT: if scheme was requested, refuse (would leak wrong brand)
      if (scheme) {
        const errorMsg = `No email_settings row for user_id=${userId} scheme=${scheme} — refusing to send (would leak wrong brand).`;
        this.logger.error(`[MAIL] ${errorMsg}`);
        throw new Error(errorMsg);
      }
      // Fallback ONLY for internal/system emails (no scheme requested)
      this.logger.warn(
        `[MAIL] No email_settings row for user_id=${userId} — falling back to DEFAULT sender (${this.getFromAddress()}).`,
      );
      await this.transporter.sendMail({ from: this.getFromAddress(), ...mailOpts });
      return;
    }

    const { transporter, from } = this.getUserTransport(cfg);
    try {
      await transporter.sendMail({ from, ...mailOpts });
      this.logger.log(
        `Email sent as ${cfg.from_email} (user_id=${userId} scheme=${cfg.scheme ?? 'none'}) — "${opts.subject}"`,
      );
    } catch (err: any) {
      this.userTransportCache.delete(cfg.id);
      this.logger.error(
        `sendAsUser failed via ${cfg.from_email}: ${err.message}`,
      );
      throw err;
    }
  }

  /** Build/cache a transporter from an email_settings row. */
  private getUserTransport(cfg: EmailSettingsEntity) {
    const signature = `${cfg.smtp_host}|${cfg.smtp_port}|${cfg.smtp_username}|${cfg.updated_at ? new Date(cfg.updated_at).getTime() : 0
      }`;
    const cached = this.userTransportCache.get(cfg.id);
    if (cached && cached.signature === signature) return cached;

    const port = Number(cfg.smtp_port);
    const enc = (cfg.smtp_encryption || '').toLowerCase();
    const secure = port === 465 || enc === 'ssl'; // 465=SSL, 587=STARTTLS

    const transporter = nodemailer.createTransport({
      host: cfg.smtp_host,
      port,
      secure,
      auth: { user: cfg.smtp_username, pass: cfg.smtp_password },
      ...(secure ? {} : { requireTLS: true }),
    });

    const name = (cfg.from_name || '').trim();
    const from = name ? `"${name}" <${cfg.from_email}>` : cfg.from_email;

    const entry = { transporter, from, signature };
    this.userTransportCache.set(cfg.id, entry);
    return entry;
  }
}