import nodemailer, { type SendMailOptions } from "nodemailer";

import { getMailSettings } from "@/lib/app-config";
import type { AppLocale } from "@/lib/locale";
import type { MailSettings } from "@/lib/mail-settings";

type MailTransportOptions = {
  host: string;
  port: number;
  secure: boolean;
  auth: {
    user: string;
    pass: string;
  };
};

type MailTransport = {
  sendMail: (options: SendMailOptions) => Promise<unknown>;
};

type CreateTransport = (options: MailTransportOptions) => MailTransport;

type SendMailDeps = {
  settings?: MailSettings;
  createTransport?: CreateTransport;
};

type SendMailInput = {
  to: string;
  subject: string;
  text: string;
  replyTo?: string;
};

type ContactMessageInput = {
  name: string;
  email: string;
  phone?: string;
  company?: string;
  message: string;
  locale: AppLocale;
};

function requireValue(value: string, message: string) {
  if (!value.trim()) {
    throw new Error(message);
  }

  return value.trim();
}

function getConfiguredTransportSettings(settings: MailSettings) {
  const smtpHost = requireValue(settings.smtp.host, "SMTP host is required.");
  const smtpUsername = requireValue(settings.smtp.username, "SMTP username is required.");
  const smtpPassword = requireValue(settings.smtp.password, "SMTP password is required.");
  const fromEmail = requireValue(settings.sender.email, "From email is required.");

  return {
    smtpHost,
    smtpUsername,
    smtpPassword,
    fromEmail,
  };
}

function getConfiguredRecipient(settings: MailSettings, recipientKey: "contact" | "test") {
  if (recipientKey === "contact") {
    return requireValue(
      settings.recipients.contact || settings.recipients.test,
      "Contact recipient email is required.",
    );
  }

  return requireValue(
    settings.recipients.test || settings.recipients.contact,
    "Test recipient email is required.",
  );
}

export function createSmtpTransport(
  settings: MailSettings,
  createTransport: CreateTransport = nodemailer.createTransport,
) {
  const { smtpHost, smtpUsername, smtpPassword } = getConfiguredTransportSettings(settings);

  return createTransport({
    host: smtpHost,
    port: settings.smtp.port,
    secure: settings.smtp.secure,
    auth: {
      user: smtpUsername,
      pass: smtpPassword,
    },
  });
}

export async function sendMail(
  input: SendMailInput,
  deps: SendMailDeps = {},
) {
  const settings = deps.settings ?? await getMailSettings();
  const { fromEmail } = getConfiguredTransportSettings(settings);
  const transport = createSmtpTransport(settings, deps.createTransport);

  await transport.sendMail({
    from: settings.sender.name ? `${settings.sender.name} <${fromEmail}>` : fromEmail,
    to: input.to,
    subject: input.subject,
    text: input.text,
    replyTo: input.replyTo,
  });
}

export async function sendContactMessage(
  input: ContactMessageInput,
  deps: SendMailDeps = {},
) {
  const settings = deps.settings ?? await getMailSettings();
  const recipient = getConfiguredRecipient(settings, "contact");

  await sendMail(
    {
      to: recipient,
      subject: "New contact message",
      replyTo: input.email,
      text: [
        "A new contact message was submitted.",
        "",
        `Name: ${input.name}`,
        `Email: ${input.email}`,
        `Phone: ${input.phone?.trim() || "-"}`,
        `Company: ${input.company?.trim() || "-"}`,
        `Locale: ${input.locale}`,
        `Submitted at: ${new Date().toISOString()}`,
        "",
        "Message:",
        input.message,
      ].join("\n"),
    },
    {
      settings,
      createTransport: deps.createTransport,
    },
  );
}

export async function sendTestEmail(
  deps: SendMailDeps = {},
) {
  const settings = deps.settings ?? await getMailSettings();
  const recipient = getConfiguredRecipient(settings, "test");
  const { fromEmail } = getConfiguredTransportSettings(settings);

  await sendMail(
    {
      to: recipient,
      subject: "SMTP test email",
      text: [
        "This is a backend SMTP test email.",
        "",
        `Timestamp: ${new Date().toISOString()}`,
        `Configured from email: ${fromEmail}`,
        `Configured recipient: ${recipient}`,
        `Environment: ${process.env.NODE_ENV ?? "development"}`,
      ].join("\n"),
    },
    {
      settings,
      createTransport: deps.createTransport,
    },
  );
}
