// Minimal SMTP client — zero dependencies. Supports implicit TLS (port 465),
// STARTTLS (port 587), and plain (for local testing). AUTH LOGIN.
//
// .env:
//   SMTP_HOST=smtp.example.com
//   SMTP_PORT=465
//   SMTP_SECURE=tls        # tls | starttls | plain
//   SMTP_USER=you@example.com
//   SMTP_PASS=app-password
//   MAIL_FROM="LAV Pulse <you@example.com>"

import net from 'node:net';
import tls from 'node:tls';

export function mailConfigured() {
  return Boolean(process.env.SMTP_HOST);
}

function makeReader(socket) {
  let buffer = '';
  const waiters = [];
  const feed = (chunk) => {
    buffer += chunk.toString('utf8');
    tryFlush();
  };
  function tryFlush() {
    // A complete SMTP reply ends with a line "NNN<space>..."
    const lines = buffer.split(/\r?\n/);
    for (let i = 0; i < lines.length; i++) {
      if (/^\d{3} /.test(lines[i])) {
        const reply = lines.slice(0, i + 1).join('\n');
        buffer = lines.slice(i + 1).join('\n');
        const w = waiters.shift();
        if (w) w.resolve(reply);
        else pending.push(reply);
        return tryFlush();
      }
    }
  }
  const pending = [];
  socket.on('data', feed);
  return {
    read() {
      if (pending.length) return Promise.resolve(pending.shift());
      return new Promise((resolve, reject) => {
        waiters.push({ resolve, reject });
        socket.once('error', reject);
      });
    },
    detach() { socket.off('data', feed); },
  };
}

function expectCode(reply, codes) {
  const code = Number(reply.slice(0, 3));
  if (!codes.includes(code)) throw new Error(`SMTP unexpected reply: ${reply.split('\n')[0]}`);
  return reply;
}

export async function sendMail({ to, subject, html }) {
  const host = process.env.SMTP_HOST;
  if (!host) throw new Error('SMTP not configured (set SMTP_HOST etc. in .env)');
  const mode = (process.env.SMTP_SECURE || 'tls').toLowerCase();
  const port = Number(process.env.SMTP_PORT || (mode === 'tls' ? 465 : 587));
  const user = process.env.SMTP_USER || '';
  const pass = process.env.SMTP_PASS || '';
  const from = process.env.MAIL_FROM || user;
  const fromAddr = /<([^>]+)>/.exec(from)?.[1] || from;
  const toList = String(to).split(',').map((s) => s.trim()).filter(Boolean);

  let socket = mode === 'tls'
    ? tls.connect({ host, port, servername: host })
    : net.connect({ host, port });
  await new Promise((resolve, reject) => {
    socket.once(mode === 'tls' ? 'secureConnect' : 'connect', resolve);
    socket.once('error', reject);
  });
  let reader = makeReader(socket);
  const send = (line) => socket.write(line + '\r\n');

  expectCode(await reader.read(), [220]);
  send('EHLO lav-pulse.local');
  expectCode(await reader.read(), [250]);

  if (mode === 'starttls') {
    send('STARTTLS');
    expectCode(await reader.read(), [220]);
    reader.detach();
    socket = await new Promise((resolve, reject) => {
      const t = tls.connect({ socket, servername: host }, () => resolve(t));
      t.once('error', reject);
    });
    reader = makeReader(socket);
    socket.write('EHLO lav-pulse.local\r\n');
    expectCode(await reader.read(), [250]);
  }

  if (user) {
    send('AUTH LOGIN');
    expectCode(await reader.read(), [334]);
    send(Buffer.from(user).toString('base64'));
    expectCode(await reader.read(), [334]);
    send(Buffer.from(pass).toString('base64'));
    expectCode(await reader.read(), [235]);
  }

  send(`MAIL FROM:<${fromAddr}>`);
  expectCode(await reader.read(), [250]);
  for (const rcpt of toList) {
    send(`RCPT TO:<${rcpt}>`);
    expectCode(await reader.read(), [250, 251]);
  }
  send('DATA');
  expectCode(await reader.read(), [354]);

  const body = [
    `From: ${from}`,
    `To: ${toList.join(', ')}`,
    `Subject: ${subject}`,
    'MIME-Version: 1.0',
    'Content-Type: text/html; charset=utf-8',
    '',
    html.replace(/\r?\n\./g, '\n..'), // dot-stuffing
    '.',
  ].join('\r\n');
  socket.write(body + '\r\n');
  expectCode(await reader.read(), [250]);
  send('QUIT');
  socket.end();
  return true;
}
