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

const { findUnique, sendMail, createTransport } = vi.hoisted(() => {
  const sendMail = vi.fn().mockResolvedValue({ messageId: "test" });
  return {
    findUnique: vi.fn(),
    sendMail,
    createTransport: vi.fn(() => ({ sendMail })),
  };
});

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() },
}));

// Re-import after mocks are set up
const { sendEmail } = await import("../lib/email.js");

describe("SMTP ENV overrides", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    // Default DB row — used as fallback
    findUnique.mockResolvedValue({
      smtpHost: "db-smtp.example.com",
      smtpPort: 587,
      smtpUser: "db-user@example.com",
      smtpPassword: "db-password",
      smtpFrom: "db-from@example.com",
      smtpTls: true,
    });
    sendMail.mockResolvedValue({ messageId: "ok" });
  });

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

  it("SMTP_HOST env overrides DB smtpHost", async () => {
    vi.stubEnv("SMTP_HOST", "env-smtp.example.com");

    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

    expect(nodemailer.createTransport).toHaveBeenCalledWith(
      expect.objectContaining({ host: "env-smtp.example.com" }),
    );
  });

  it("SMTP_PORT env overrides DB smtpPort (parsed as integer)", async () => {
    vi.stubEnv("SMTP_PORT", "1025");

    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

    expect(nodemailer.createTransport).toHaveBeenCalledWith(
      expect.objectContaining({ port: 1025 }),
    );
  });

  it("SMTP_TLS=false sets secure: false", async () => {
    vi.stubEnv("SMTP_TLS", "false");

    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

    expect(nodemailer.createTransport).toHaveBeenCalledWith(
      expect.objectContaining({ secure: false }),
    );
  });

  it("SMTP_TLS=true sets secure: true", async () => {
    vi.stubEnv("SMTP_TLS", "true");

    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

    expect(nodemailer.createTransport).toHaveBeenCalledWith(
      expect.objectContaining({ secure: true }),
    );
  });

  it("no SMTP_USER → auth uses DB user; with SMTP_USER env → auth uses env user", async () => {
    vi.stubEnv("SMTP_USER", "env-user@example.com");

    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

    expect(nodemailer.createTransport).toHaveBeenCalledWith(
      expect.objectContaining({
        auth: expect.objectContaining({ user: "env-user@example.com" }),
      }),
    );
  });

  it("no SMTP_USER and no SMTP_PASSWORD → auth is undefined (Mailhog scenario)", async () => {
    // Clear all user/password from both ENV and DB
    vi.stubEnv("SMTP_HOST", "mailhog");
    vi.stubEnv("SMTP_PORT", "1025");
    vi.stubEnv("SMTP_TLS", "false");
    // Explicitly no SMTP_USER / SMTP_PASSWORD
    findUnique.mockResolvedValue({
      smtpHost: null,
      smtpPort: null,
      smtpUser: null,
      smtpPassword: null,
      smtpFrom: "noreply@capakraken.app",
      smtpTls: null,
    });

    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

    expect(nodemailer.createTransport).toHaveBeenCalledWith(
      expect.objectContaining({ auth: undefined }),
    );
  });

  it("DB values are used when no ENV overrides are set", async () => {
    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

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

  it("ENV overrides take priority over DB for all SMTP fields simultaneously", async () => {
    vi.stubEnv("SMTP_HOST", "mailhog");
    vi.stubEnv("SMTP_PORT", "1025");
    vi.stubEnv("SMTP_USER", "");        // empty string = no override
    vi.stubEnv("SMTP_TLS", "false");
    vi.stubEnv("SMTP_PASSWORD", "");    // empty = no override

    findUnique.mockResolvedValue({
      smtpHost: "db-smtp.example.com",
      smtpPort: 587,
      smtpUser: "db-user@example.com",
      smtpPassword: "db-password",
      smtpFrom: "from@example.com",
      smtpTls: true,
    });

    await sendEmail({ to: "user@test.com", subject: "Test", text: "Hello" });

    expect(nodemailer.createTransport).toHaveBeenCalledWith(
      expect.objectContaining({
        host: "mailhog",
        port: 1025,
        secure: false,
      }),
    );
  });
});
