import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import nodemailer from "nodemailer";
import { logger } from "../lib/logger.js";
import { testSmtpConnection } from "../lib/email.js";

const { findUnique, verify, createTransport } = vi.hoisted(() => {
  const verify = vi.fn();
  return {
    findUnique: vi.fn(),
    verify,
    createTransport: vi.fn(() => ({
      verify,
      sendMail: vi.fn(),
    })),
  };
});

vi.mock("@capakraken/db", () => ({
  prisma: {
    systemSettings: {
      findUnique,
    },
  },
}));

vi.mock("nodemailer", () => ({
  default: {
    createTransport,
  },
}));

vi.mock("../lib/logger.js", () => ({
  logger: {
    error: vi.fn(),
    warn: vi.fn(),
    info: vi.fn(),
    debug: vi.fn(),
  },
}));

describe("email runtime config hardening", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    findUnique.mockResolvedValue({
      smtpHost: "smtp.secret.internal",
      smtpPort: 587,
      smtpUser: "alice@example.com",
      smtpPassword: "super-secret",
      smtpTls: true,
    });
  });

  afterEach(() => {
    vi.unstubAllEnvs();
  });

  it("returns a classified SMTP auth error without leaking diagnostics", async () => {
    verify.mockRejectedValueOnce(
      new Error("Invalid login for alice@example.com against smtp.secret.internal"),
    );

    const result = await testSmtpConnection();

    expect(result).toEqual({
      ok: false,
      error: "SMTP authentication failed — check username and password.",
    });

    expect(nodemailer.createTransport).toHaveBeenCalledWith({
      host: "smtp.secret.internal",
      port: 587,
      secure: true,
      auth: {
        user: "alice@example.com",
        pass: "super-secret",
      },
    });

    expect(logger.warn).toHaveBeenCalledWith(
      expect.objectContaining({
        diagnostic: expect.any(String),
      }),
      "SMTP connection test failed",
    );

    const diagnostic = vi.mocked(logger.warn).mock.calls[0]?.[0];
    expect(JSON.stringify(diagnostic)).toContain("<redacted-email>");
    expect(JSON.stringify(diagnostic)).toContain("<redacted-host>");
    expect(JSON.stringify(diagnostic)).not.toContain("alice@example.com");
    expect(JSON.stringify(diagnostic)).not.toContain("smtp.secret.internal");
  });

  it("prefers SMTP_PASSWORD from the environment at runtime", async () => {
    vi.stubEnv("SMTP_PASSWORD", "env-smtp-password");
    findUnique.mockResolvedValue({
      smtpHost: "smtp.secret.internal",
      smtpPort: 587,
      smtpUser: "alice@example.com",
      smtpPassword: "db-password",
      smtpTls: true,
    });
    verify.mockResolvedValueOnce(true);

    const result = await testSmtpConnection();

    expect(result).toEqual({ ok: true });
    expect(nodemailer.createTransport).toHaveBeenCalledWith({
      host: "smtp.secret.internal",
      port: 587,
      secure: true,
      auth: {
        user: "alice@example.com",
        pass: "env-smtp-password",
      },
    });
  });
});
