import type { EmailChannelConfig } from '../types.js';

// ── Email Channel Adapter ────────────────────────────────────
// Abstracts email sending behind a common interface.
// Phase 1: console provider (logs to stdout for dev/testing).
// Phase 2: SendGrid/Postmark adapters.

export interface EmailMessage {
  to: string;
  from: string;
  fromName: string;
  subject: string;
  bodyHtml: string;
  bodyText: string;
}

export interface SendResult {
  success: boolean;
  messageId?: string;
  error?: string;
}

/**
 * Send an email using the configured provider.
 */
export async function sendEmail(
  message: EmailMessage,
  config: EmailChannelConfig,
  log: { info: (...a: unknown[]) => void; error: (...a: unknown[]) => void }
): Promise<SendResult> {
  switch (config.provider) {
    case 'smtp':
      return sendViaSmtp(message, config);
    case 'console':
      return sendViaConsole(message, log);
    case 'bytelyst':
      return sendViaBytelyst(message, log);
    case 'sendgrid':
      return sendViaSendGrid(message, config);
    case 'postmark':
      return sendViaPostmark(message, config);
    default:
      return { success: false, error: `Unknown email provider: ${config.provider}` };
  }
}

// ── SMTP Provider (self-hosted) ──────────────────────────────

async function sendViaSmtp(message: EmailMessage, config: EmailChannelConfig): Promise<SendResult> {
  if (!config.smtpHost) {
    return { success: false, error: 'SMTP host not configured' };
  }

  const { createTransport } = await import('nodemailer');
  const port = config.smtpPort ?? 587;
  const secure = config.smtpSecure ?? port === 465;
  const auth =
    config.smtpUser || config.smtpPassword
      ? {
          user: config.smtpUser,
          pass: config.smtpPassword,
        }
      : undefined;

  try {
    const transport = createTransport({
      host: config.smtpHost,
      port,
      secure,
      auth,
    });

    const info = await transport.sendMail({
      from: `${message.fromName} <${message.from}>`,
      to: message.to,
      subject: message.subject,
      text: message.bodyText,
      html: message.bodyHtml,
    });

    return {
      success: true,
      messageId:
        typeof info.messageId === 'string' ? info.messageId : `smtp_${crypto.randomUUID()}`,
    };
  } catch (err: unknown) {
    return { success: false, error: err instanceof Error ? err.message : String(err) };
  }
}

// ── Console Provider (dev/testing) ───────────────────────────

async function sendViaConsole(
  message: EmailMessage,
  log: { info: (...a: unknown[]) => void }
): Promise<SendResult> {
  const messageId = `console_${crypto.randomUUID()}`;
  log.info(
    {
      messageId,
      to: message.to,
      from: message.from,
      subject: message.subject,
    },
    `[delivery/email] Console email sent to ${message.to}: "${message.subject}"`
  );
  return { success: true, messageId };
}

// ── ByteLyst Provider (custom email bridge) ───────────────────

const BYTELYST_EMAIL_URL = process.env.BYTELYST_EMAIL_URL;

async function sendViaBytelyst(
  message: EmailMessage,
  log: { info: (...a: unknown[]) => void; error: (...a: unknown[]) => void }
): Promise<SendResult> {
  if (!BYTELYST_EMAIL_URL) {
    return {
      success: false,
      error: 'BYTELYST_EMAIL_URL is not configured for the bytelyst email provider',
    };
  }

  try {
    const response = await fetch(BYTELYST_EMAIL_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        email: message.to,
        subject: message.subject,
        email_body: message.bodyHtml,
      }),
    });

    if (response.ok) {
      const messageId = `bl_${crypto.randomUUID()}`;
      log.info(
        { messageId, to: message.to, subject: message.subject },
        `[delivery/email] ByteLyst email sent to ${message.to}`
      );
      return { success: true, messageId };
    }

    const errorText = await response.text();
    log.error(
      { status: response.status, error: errorText },
      `[delivery/email] ByteLyst email failed for ${message.to}`
    );
    return { success: false, error: `ByteLyst email error ${response.status}: ${errorText}` };
  } catch (err: unknown) {
    return { success: false, error: err instanceof Error ? err.message : String(err) };
  }
}

// ── SendGrid Provider ────────────────────────────────────────

async function sendViaSendGrid(
  message: EmailMessage,
  config: EmailChannelConfig
): Promise<SendResult> {
  if (!config.apiKey) {
    return { success: false, error: 'SendGrid API key not configured' };
  }

  try {
    const response = await fetch('https://api.sendgrid.com/v3/mail/send', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${config.apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        personalizations: [{ to: [{ email: message.to }] }],
        from: { email: message.from, name: message.fromName },
        subject: message.subject,
        content: [
          { type: 'text/plain', value: message.bodyText },
          { type: 'text/html', value: message.bodyHtml },
        ],
      }),
    });

    if (response.ok || response.status === 202) {
      const messageId = response.headers.get('x-message-id') || `sg_${crypto.randomUUID()}`;
      return { success: true, messageId };
    }

    const errorText = await response.text();
    return { success: false, error: `SendGrid error ${response.status}: ${errorText}` };
  } catch (err: unknown) {
    return { success: false, error: err instanceof Error ? err.message : String(err) };
  }
}

// ── Postmark Provider ────────────────────────────────────────

async function sendViaPostmark(
  message: EmailMessage,
  config: EmailChannelConfig
): Promise<SendResult> {
  if (!config.apiKey) {
    return { success: false, error: 'Postmark API key not configured' };
  }

  try {
    const response = await fetch('https://api.postmarkapp.com/email', {
      method: 'POST',
      headers: {
        'X-Postmark-Server-Token': config.apiKey,
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
      body: JSON.stringify({
        From: `${message.fromName} <${message.from}>`,
        To: message.to,
        Subject: message.subject,
        HtmlBody: message.bodyHtml,
        TextBody: message.bodyText,
      }),
    });

    if (response.ok) {
      const data = (await response.json()) as { MessageID?: string };
      return { success: true, messageId: data.MessageID || `pm_${crypto.randomUUID()}` };
    }

    const errorText = await response.text();
    return { success: false, error: `Postmark error ${response.status}: ${errorText}` };
  } catch (err: unknown) {
    return { success: false, error: err instanceof Error ? err.message : String(err) };
  }
}
