import { describe, expect, it, vi } from "vitest";

import type { MailSettings } from "../lib/mail-settings";
import { sendContactMessage, sendTestEmail } from "../lib/mail";

function createMailSettings(overrides: Partial<MailSettings> = {}): MailSettings {
  return {
    smtp: {
      host: "smtp.example.com",
      port: 587,
      secure: false,
      username: "mailer@example.com",
      password: "secret",
      ...overrides.smtp,
    },
    sender: {
      email: "hello@example.com",
      name: "Studio Moh",
      ...overrides.sender,
    },
    recipients: {
      contact: "contact@example.com",
      test: "test@example.com",
      ...overrides.recipients,
    },
  };
}

describe("mail delivery", () => {
  it("sends contact messages with reply-to", async () => {
    const sendMailMock = vi.fn().mockResolvedValue({});
    const createTransport = vi.fn().mockReturnValue({
      sendMail: sendMailMock,
    });

    await sendContactMessage(
      {
        locale: "en",
        name: "Jane Doe",
        email: "jane@example.com",
        message: "Hello from the website contact form.",
      },
      {
        settings: createMailSettings(),
        createTransport,
      },
    );

    expect(createTransport).toHaveBeenCalledWith({
      host: "smtp.example.com",
      port: 587,
      secure: false,
      auth: {
        user: "mailer@example.com",
        pass: "secret",
      },
    });
    expect(sendMailMock).toHaveBeenCalledWith(
      expect.objectContaining({
        to: "contact@example.com",
        subject: "New contact message",
        replyTo: "jane@example.com",
      }),
    );
    expect(sendMailMock.mock.calls[0]?.[0].text).toContain("Hello from the website contact form.");
  });

  it("falls back to the test recipient when contact recipient is empty", async () => {
    const sendMailMock = vi.fn().mockResolvedValue({});
    const createTransport = vi.fn().mockReturnValue({
      sendMail: sendMailMock,
    });

    await sendContactMessage(
      {
        locale: "de",
        name: "Jane Doe",
        email: "jane@example.com",
        message: "Fallback recipient should still work.",
      },
      {
        settings: createMailSettings({
          recipients: {
            contact: "",
            test: "fallback@example.com",
          },
        }),
        createTransport,
      },
    );

    expect(sendMailMock).toHaveBeenCalledWith(
      expect.objectContaining({
        to: "fallback@example.com",
      }),
    );
  });

  it("sends backend test emails to the configured recipient", async () => {
    const sendMailMock = vi.fn().mockResolvedValue({});
    const createTransport = vi.fn().mockReturnValue({
      sendMail: sendMailMock,
    });

    await sendTestEmail({
      settings: createMailSettings(),
      createTransport,
    });

    expect(sendMailMock).toHaveBeenCalledWith(
      expect.objectContaining({
        to: "test@example.com",
        subject: "SMTP test email",
      }),
    );
  });

  it("fails when the transport rejects the test email", async () => {
    const createTransport = vi.fn().mockReturnValue({
      sendMail: vi.fn().mockRejectedValue(new Error("Authentication failed.")),
    });

    await expect(
      sendTestEmail({
        settings: createMailSettings(),
        createTransport,
      }),
    ).rejects.toThrow("Authentication failed.");
  });
});
