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

// Mock tls to simulate an SMTP server over implicit TLS
let lastWrites: string[] = []
vi.mock("tls", () => {
  type Listener = (...args: unknown[]) => void

  class MockSocket {
    listeners: Record<string, Listener[]> = {}
    writes: string[] = []
    // very small state machine of server responses
    private step = 0
    private enqueue(messages: string | string[], type: "data" | "end" = "data") {
      const chunks = Array.isArray(messages) ? messages : [messages]
      chunks.forEach((chunk, index) => {
        const delay = index === 0 ? 0 : 1
        setTimeout(() => {
          if (type === "end") {
            void chunk
            this.emit("end")
            return
          }
          this.emit("data", Buffer.from(chunk))
        }, delay)
      })
    }
    on(event: string, cb: Listener) {
      this.listeners[event] = this.listeners[event] || []
      this.listeners[event].push(cb)
      return this
    }
    removeListener(event: string, cb: Listener) {
      if (!this.listeners[event]) return this
      this.listeners[event] = this.listeners[event].filter((f) => f !== cb)
      return this
    }
    emit(event: string, data?: unknown) {
      for (const cb of this.listeners[event] || []) cb(data)
    }
    write(chunk: string) {
      this.writes.push(chunk)
      const line = chunk.replace(/\r?\n/g, "")
      // Respond depending on client command
      if (this.step === 0 && line.startsWith("EHLO")) {
        this.step = 1
        this.enqueue(["250-local\r\n", "250 OK\r\n"])
      } else if (this.step === 1 && line === "AUTH LOGIN") {
        this.step = 2
        this.enqueue("334 VXNlcm5hbWU6\r\n")
      } else if (this.step === 2) {
        this.step = 3
        this.enqueue("334 UGFzc3dvcmQ6\r\n")
      } else if (this.step === 3) {
        this.step = 4
        this.enqueue("235 Auth OK\r\n")
      } else if (this.step === 4 && line.startsWith("MAIL FROM:")) {
        this.step = 5
        this.enqueue("250 FROM OK\r\n")
      } else if (this.step === 5 && line.startsWith("RCPT TO:")) {
        this.step = 6
        this.enqueue("250 RCPT OK\r\n")
      } else if (this.step === 6 && line === "DATA") {
        this.step = 7
        this.enqueue("354 End data with <CR><LF>.<CR><LF>\r\n")
      } else if (this.step === 7 && line.endsWith(".")) {
        this.step = 8
        this.enqueue("250 Queued\r\n")
      } else if (this.step === 8 && line === "QUIT") {
        this.enqueue("", "end")
      }
    }
    end() {}
  }

  function connect(_port: number, _host: string, _opts: unknown, cb?: () => void) {
    const socket = new MockSocket()
    lastWrites = socket.writes
    // initial server greeting
    setTimeout(() => {
      cb?.()
      socket.emit("data", Buffer.from("220 Mock SMTP Ready\r\n"))
    }, 0)
    return socket as unknown as NodeJS.WritableStream & { on: MockSocket["on"] }
  }

  return { default: { connect }, connect, __getLastWrites: () => lastWrites }
})

describe("sendSmtpMail", () => {
  it("performs AUTH LOGIN and sends a message", async () => {
    const { sendSmtpMail } = await import("@/server/email-smtp")
    await expect(
      sendSmtpMail(
        {
          host: "smtp.mock",
          port: 465,
          username: "user@example.com",
          password: "secret",
          from: "Sender <sender@example.com>",
        },
        "rcpt@example.com",
        "Subject here",
        "<p>Hello</p>"
      )
    ).resolves.toBeUndefined()
  })

  it("extracts envelope address from parentheses or raw email", async () => {
    const { sendSmtpMail } = await import("@/server/email-smtp")
    const tlsMock = (await import("tls")) as unknown as { __getLastWrites: () => string[] }
    await sendSmtpMail(
      {
        host: "smtp.mock",
        port: 465,
        username: "user@example.com",
        password: "secret",
        from: "Chatwoot chat@esdrasrenan.com.br (chat@esdrasrenan.com.br)",
      },
      "rcpt@example.com",
      "Subject",
      "<p>Hi</p>"
    )
    const writes = tlsMock.__getLastWrites()
    expect(writes.some((w) => /MAIL FROM:<chat@esdrasrenan.com.br>\r\n/.test(w))).toBe(true)
  })
})
