/**
 * Email sending utility using nodemailer.
 * Non-blocking — errors are logged, not thrown.
 */
import nodemailer from "nodemailer";
import { prisma as db } from "@capakraken/db";
import { logger } from "./logger.js";
import { resolveSystemSettingsRuntime } from "./system-settings-runtime.js";

interface EmailPayload {
  to: string | string[];
  subject: string;
  text: string;
  html?: string;
}

function sanitizeSmtpDiagnostic(err: unknown): string {
  const message = err instanceof Error ? err.message : String(err);
  return message
    .replace(/https?:\/\/[^\s)\]}]+/gi, "<redacted-url>")
    .replace(/\b[^\s@]+@[^\s@]+\.[^\s@]+\b/g, "<redacted-email>")
    .replace(/\b(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,}\b/g, "<redacted-host>")
    .replace(/^Error:\s*/, "")
    .slice(0, 300);
}

export function parseSmtpError(err: unknown): string {
  const message = err instanceof Error ? err.message : String(err);
  const lower = message.toLowerCase();

  if (lower.includes("auth") || lower.includes("invalid login") || lower.includes("535")) {
    return "SMTP authentication failed — check username and password.";
  }
  if (lower.includes("certificate") || lower.includes("tls") || lower.includes("ssl")) {
    return "SMTP TLS negotiation failed — verify port and TLS settings.";
  }
  if (
    lower.includes("econnrefused")
    || lower.includes("enotfound")
    || lower.includes("etimedout")
    || lower.includes("timeout")
  ) {
    return "Cannot reach the SMTP server — check host, port, and network access.";
  }

  return "SMTP connection failed — review host, port, TLS, and credentials.";
}

async function getSmtpConfig() {
  const settings = resolveSystemSettingsRuntime(
    await db.systemSettings.findUnique({ where: { id: "singleton" } }),
  );
  if (!settings.smtpHost) return null;
  const port = typeof settings.smtpPort === "number"
    ? settings.smtpPort
    : settings.smtpPort !== null && settings.smtpPort !== undefined
      ? parseInt(String(settings.smtpPort), 10)
      : 587;
  return {
    host: settings.smtpHost,
    port,
    secure: settings.smtpTls === false ? false : true,
    auth:
      settings.smtpUser && settings.smtpPassword
        ? { user: settings.smtpUser, pass: settings.smtpPassword }
        : undefined,
    from: settings.smtpFrom ?? settings.smtpUser ?? "noreply@capakraken.app",
  };
}

/**
 * Send an email. Swallows errors so calling code is never blocked.
 * Returns true if sent successfully.
 */
export async function sendEmail(payload: EmailPayload): Promise<boolean> {
  try {
    const config = await getSmtpConfig();
    if (!config) return false;

    const transporter = nodemailer.createTransport({
      host: config.host,
      port: config.port,
      secure: config.secure,
      auth: config.auth,
    });

    await transporter.sendMail({
      from: config.from,
      to: Array.isArray(payload.to) ? payload.to.join(", ") : payload.to,
      subject: payload.subject,
      text: payload.text,
      html: payload.html,
    });

    return true;
  } catch (err) {
    logger.warn({ diagnostic: sanitizeSmtpDiagnostic(err) }, "Email send failed");
    return false;
  }
}

/**
 * Test SMTP connection. Returns { ok: boolean; error?: string }.
 */
export async function testSmtpConnection(): Promise<{ ok: boolean; error?: string }> {
  try {
    const config = await getSmtpConfig();
    if (!config) return { ok: false, error: "SMTP not configured" };

    const transporter = nodemailer.createTransport({
      host: config.host,
      port: config.port,
      secure: config.secure,
      auth: config.auth,
    });

    await transporter.verify();
    return { ok: true };
  } catch (err) {
    logger.warn({ diagnostic: sanitizeSmtpDiagnostic(err) }, "SMTP connection test failed");
    return { ok: false, error: parseSmtpError(err) };
  }
}
