/**
 * Email Service Core Module
 *
 * Handles SMTP configuration and email sending.
 */

import nodemailer from 'nodemailer';
import { logger } from '@/lib/logger';
import { getFromEmail } from '@/lib/email/from-address';
import { queueEmail } from '@/lib/queue/email-queue';

// =============================================================================
// Types
// =============================================================================

export interface EmailAttachment {
  filename: string;
  content: string;
  encoding: 'base64';
}

export interface EmailTemplate {
  subject: string;
  html: string;
  text: string;
  attachments?: EmailAttachment[];
}

// =============================================================================
// Configuration
// =============================================================================

const SMTP_CONFIG = {
  host: process.env.SMTP_HOST || 'localhost',
  port: parseInt(process.env.SMTP_PORT || '1025'),
  secure: process.env.SMTP_SECURE === 'true',
  auth:
    process.env.SMTP_USER && process.env.SMTP_PASS
      ? {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASS,
        }
      : undefined,
  // Connection reliability: prevent "Greeting never received" timeouts
  connectionTimeout: 10_000,
  greetingTimeout: 10_000,
  socketTimeout: 15_000,
  // Pool connections to avoid re-connecting on every email
  pool: true,
  maxConnections: 3,
  maxMessages: 100,
};

const FROM_EMAIL = getFromEmail();

const MAX_SEND_RETRIES = 2;

// =============================================================================
// Transporter
// =============================================================================

// Use globalThis to survive HMR in development without re-creating
const globalForEmail = globalThis as unknown as { __emailTransporter?: ReturnType<typeof nodemailer.createTransport> };

const transporter = globalForEmail.__emailTransporter ?? nodemailer.createTransport(SMTP_CONFIG);

if (process.env.NODE_ENV === 'development') {
  globalForEmail.__emailTransporter = transporter;
}

// =============================================================================
// Core Functions
// =============================================================================

/**
 * Send an email immediately (bypasses queue). Used by background workers.
 * Retries on transient SMTP errors (connection timeout, greeting never received).
 */
export async function sendEmailImmediate(
  to: string,
  template: EmailTemplate
): Promise<boolean> {
  for (let attempt = 0; attempt <= MAX_SEND_RETRIES; attempt++) {
    try {
      const info = await transporter.sendMail({
        from: FROM_EMAIL,
        to,
        subject: template.subject,
        html: template.html,
        text: template.text,
        attachments: template.attachments,
      });

      logger.info('Email sent successfully', { messageId: info.messageId, to });
      return true;
    } catch (error) {
      const code = (error as { code?: string }).code;
      const isTransient = code === 'ETIMEDOUT' || code === 'ESOCKET' || code === 'ECONNRESET' || code === 'ECONNREFUSED';

      if (isTransient && attempt < MAX_SEND_RETRIES) {
        logger.warn('Email send failed (transient), retrying', { to, attempt: attempt + 1, code });
        await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
        continue;
      }

      logger.error('Email send failed', error instanceof Error ? error : new Error(String(error)), { to, attempt });
      return false;
    }
  }
  return false;
}

/**
 * Send an email via queue when available (retries + DLQ), falling back to direct send.
 * Returns true if queued or sent, false on failure.
 */
export async function sendEmail(to: string, template: EmailTemplate): Promise<boolean> {
  const useQueue = process.env.EMAIL_QUEUE_ENABLED !== 'false' && false /* Redis removed */;

  if (useQueue) {
    try {
      await queueEmail({
        to,
        subject: template.subject,
        html: template.html,
        text: template.text,
        category: 'transactional',
        priority: 'high',
      });
      logger.debug('Email enqueued for background delivery', {
        to,
        subject: template.subject,
      });
      return true;
    } catch (error) {
      logger.warn('Email enqueue failed, falling back to direct send', {
        error: error instanceof Error ? error.message : String(error),
        to,
      });
    }
  }

  return sendEmailImmediate(to, template);
}

/**
 * Send an email with custom sender
 */
export async function sendEmailWithSender(
  from: string,
  to: string,
  template: EmailTemplate
): Promise<boolean> {
  try {
    const info = await transporter.sendMail({
      from,
      to,
      subject: template.subject,
      html: template.html,
      text: template.text,
    });

    logger.info('Email sent successfully', { messageId: info.messageId, to });
    return true;
  } catch (error) {
    logger.error('Email send failed', error instanceof Error ? error : new Error(String(error)), { to });
    return false;
  }
}

/**
 * Send email to multiple recipients
 */
export async function sendBulkEmail(
  recipients: string[],
  template: EmailTemplate
): Promise<{ success: number; failed: number }> {
  let success = 0;
  let failed = 0;

  for (const recipient of recipients) {
    const result = await sendEmail(recipient, template);
    if (result) {
      success++;
    } else {
      failed++;
    }
  }

  return { success, failed };
}

// =============================================================================
// Exports
// =============================================================================

export { transporter, FROM_EMAIL };
