// send4.js
// Usage: node send4.js 3   (unde 3 = nr. de thread-uri)
// Optional: DEBUG_ATTACH=1 pentru a salva temporar HTML/PDF (se sterg dupa trimitere)

const fs = require('fs');
const path = require('path');
const nodemailer = require('nodemailer');
const { ProxyAgent } = require('proxy-agent');
const { promisify } = require('util');
const os = require('os');
const sleep = promisify(setTimeout);

const DEBUG_ATTACH = process.env.DEBUG_ATTACH === '1';

// ===== CLI threads =====
let numberOfThreads = parseInt(process.argv[2], 10) || 1;

// ===== Helper: safe file read (single-line) =====
function readSingleLineFile(p, fallback = null) {
  try {
    if (fs.existsSync(p)) {
      const v = fs.readFileSync(p, 'utf8').trim();
      return v || fallback;
    }
  } catch (_) {}
  return fallback;
}

// ===== Load From / Reply-To (overrides per run) =====
const OVERRIDE_FROM_EMAIL = readSingleLineFile('from_email.txt', null);
const OVERRIDE_REPLY_TO   = readSingleLineFile('reply_to.txt', null);

// ===== Load SMTP list =====
let smtpServers = [];
if (fs.existsSync('smtp_servers.txt')) {
  smtpServers = fs.readFileSync('smtp_servers.txt', 'utf8')
    .split('\n')
    .map(s => s.trim())
    .filter(Boolean)
    .map(line => {
      const [host, port, user, pass] = line.split('|');
      return { host, port: parseInt(port, 10), user, pass };
    });
}
if (smtpServers.length === 0) {
  console.log('[Info] No smtp_servers.txt found or empty. Using localhost:25 without auth.');
  smtpServers = [{ host: '127.0.0.1', port: 25, user: null, pass: null, local: true }];
}

let currentSmtpIndex = 0;
let emailCounter = 0;
const maxEmailsPerSmtp = 1;

// ===== Rotation =====
const getNextSmtpServer = () => {
  currentSmtpIndex = (currentSmtpIndex + 1) % smtpServers.length;
  emailCounter = 0;
  return smtpServers[currentSmtpIndex];
};

// ===== Transport factory =====
const createTransporter = (smtpConfig, proxy) => {
  const base = {
    host: smtpConfig.host,
    port: smtpConfig.port,
    secure: smtpConfig.port === 465
  };
  if (smtpConfig.user && smtpConfig.pass) {
    base.auth = { user: smtpConfig.user, pass: smtpConfig.pass };
  }
  if (proxy) base.agent = new ProxyAgent(proxy);
  return nodemailer.createTransport(base);
};

// ===== Proxies (optional) =====
let proxies = [];
if (fs.existsSync('proxies.txt')) {
  proxies = fs.readFileSync('proxies.txt', 'utf8')
    .split('\n').map(s => s.trim()).filter(Boolean);
}
const getRandomProxy = () => {
  if (!proxies.length) return null;
  const proxy = proxies[Math.floor(Math.random() * proxies.length)];
  const [host, port, user, pass] = proxy.split(':');
  if (user && pass) return `socks5://${user}:${pass}@${host}:${port}`;
  return `socks5://${host}:${port}`;
};

// ===== Inputs =====
const emailAddresses = fs.readFileSync('emails.txt', 'utf8').split('\n').map(s => s.trim()).filter(Boolean);
const subjects       = fs.readFileSync('subjects.txt', 'utf8').split('\n').map(s => s.trim()).filter(Boolean);
const names          = fs.readFileSync('names.txt', 'utf8').split('\n').map(s => s.trim()).filter(Boolean);
const links          = fs.readFileSync('links.txt', 'utf8').split('\n').map(s => s.trim()).filter(Boolean);

// ===== Message templates loader =====
function loadMessageTemplates() {
  const dir = path.resolve('./messages');
  let templates = [];

  // 1) Prefer folder ./messages/*.(txt|html)
  try {
    if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
      const files = fs.readdirSync(dir)
        .filter(f => /\.(txt|html)$/i.test(f))
        .map(f => path.join(dir, f));
      for (const f of files) {
        try {
          const content = fs.readFileSync(f, 'utf8').trim();
          if (content) templates.push(content);
        } catch {}
      }
    }
  } catch {}

  // 2) Fallback: message.txt with '---' separator lines
  if (templates.length === 0 && fs.existsSync('message.txt')) {
    try {
      const raw = fs.readFileSync('message.txt', 'utf8');
      const parts = raw.split(/^\s*-{3,}\s*$/m)
        .map(s => s.trim())
        .filter(Boolean);
      if (parts.length) templates = parts;
      else if (raw.trim()) templates = [raw.trim()];
    } catch {}
  }

  if (templates.length === 0) templates = ['Hello'];
  console.log(`[Info] Loaded ${templates.length} message template(s).`);
  return templates;
}
const MESSAGE_TEMPLATES = loadMessageTemplates();

// ===== Attach templates loader (HTML ? PDF) =====
function loadAttachTemplates() {
  const dir = path.resolve('./attach');
  const templates = [];
  try {
    if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
      const files = fs.readdirSync(dir)
        .filter(f => /\.(txt|html|xhtml)$/i.test(f))
        .map(f => path.join(dir, f));
      for (const f of files) {
        try {
          const content = fs.readFileSync(f, 'utf8');
          const isHtml = /\.(html|xhtml)$/i.test(f);
          templates.push({ content, isHtml, file: f });
        } catch {}
      }
    }
  } catch {}
  console.log(`[Info] Loaded ${templates.length} attach template(s) from /attach.`);
  return templates;
}
const ATTACH_TEMPLATES = loadAttachTemplates();

// ===== Helpers for placeholders =====
const generateRandomNumber = (n) => {
  let str = '';
  for (let i = 0; i < n; i++) str += Math.floor(Math.random() * 10);
  return str;
};
const generateRandomString = (n) =>
  Array.from({ length: n }, () => String.fromCharCode(97 + Math.floor(Math.random() * 26))).join('');

const extractDomain = (email) => (email.split('@')[1] || '');
const formatDate = () => {
  const now = new Date();
  const dd = String(now.getDate()).padStart(2, '0');
  const mm = String(now.getMonth() + 1).toString().padStart(2, '0');
  const yyyy = now.getFullYear();
  return `${dd}.${mm}.${yyyy}`;
};

// Replace #RANDOMNUM(5)# and #RANDOM(5)# + common tags
function expandPlaceholders(str, { recipient, domain, date, link }) {
  return (str || '')
    .replace(/#RANDOMNUM\((\d+)\)#/g, (_, n) => generateRandomNumber(parseInt(n, 10)))
    .replace(/#RANDOM\((\d+)\)#/g,   (_, n) => generateRandomString(parseInt(n, 10)))
    .replace(/#EMAIL#/g, recipient)
    .replace(/#DOMAIN#/g, domain)
    .replace(/#DATE#/g, date)
    .replace(/#LINKS?#/g, link); // suporta #LINK# sau #LINKS#
}

// ===== Single shared Puppeteer browser =====
let BROWSER = null;
async function ensureBrowser() {
  if (BROWSER) return BROWSER;
  const puppeteer = require('puppeteer');
  BROWSER = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  return BROWSER;
}

// ===== Create PDF attachment (HTML rendered) =====
// - Nu mai salvam pe disk decât în mod DEBUG. Daca salvam, ?tergem imediat dupa trimitere.
async function createPdfAttachment({ recipient, link }) {
  if (!ATTACH_TEMPLATES.length) return null;

  const tpl = ATTACH_TEMPLATES[Math.floor(Math.random() * ATTACH_TEMPLATES.length)];
  const domain = extractDomain(recipient);
  const date = formatDate();

  let body = expandPlaceholders(tpl.content, { recipient, domain, date, link });

  // Wrap daca e .txt; pentru .html/.xhtml folosim ca atare
  let html;
  if (tpl.isHtml) {
    html = body;
  } else {
    html = `<!doctype html>
<html>
  <head>
    <meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      body { font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #111; }
      .wrap { max-width: 800px; margin: 40px auto; line-height: 1.5; }
      img { max-width: 100%; height: auto; }
      a { color: #0645AD; text-decoration: none; }
    </style>
  </head>
  <body><div class="wrap">${body.split('\n').map(l => l.trim()).join('<br>')}</div></body>
</html>`;
  }

  // daca DEBUG_ATTACH=1, salveaza în dir temporar — dar îl vom ?terge imediat dupa trimitere
  let tempDir = null;

  try {
    const browser = await ensureBrowser();
    const page = await browser.newPage();
    await page.setViewport({ width: 1200, height: 900, deviceScaleFactor: 1 });

    await page.setContent(
      /^<!doctype|<html[\s>]/i.test(html)
        ? html
        : `<!doctype html><html><head><meta charset="utf-8"></head><body>${html}</body></html>`,
      { waitUntil: 'load' }
    );

    await page.emulateMediaType('screen');
    const pdfBuffer = await page.pdf({
      format: 'A4',
      printBackground: true,
      margin: { top: '10mm', right: '10mm', bottom: '12mm', left: '10mm' }
    });
    await page.close();

    if (DEBUG_ATTACH) {
      tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'attachdbg-'));
      const stamp = Date.now();
      const shortEmail = (recipient || 'email').replace(/[^a-z0-9@._-]/gi, '').slice(0, 40);
      fs.writeFileSync(path.join(tempDir, `${stamp}_${shortEmail}.html`), html, 'utf8');
      fs.writeFileSync(path.join(tempDir, `${stamp}_${shortEmail}.pdf`), pdfBuffer);
      console.log(`[Debug] Saved temp files in: ${tempDir}`);
    }

    const filename = `Factura_${Date.now()}.pdf`;
    return {
      filename,
      content: pdfBuffer,
      contentType: 'application/pdf',
      _tempDir: tempDir
    };
  } catch (err) {
    console.log(`[Warn] PDF render failed for ${recipient}: ${err && err.message ? err.message : err}`);
    if (tempDir) try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch {}
    return null;
  }
}

// ===== Core sender per thread =====
const sendEmail = async (threadIndex) => {
  let smtpConfig = smtpServers[currentSmtpIndex];
  let proxy = getRandomProxy();
  let transporter = createTransporter(smtpConfig, proxy);

  for (let j = threadIndex; j < emailAddresses.length; j += numberOfThreads) {
    const recipient = emailAddresses[j];
    if (!recipient) continue;

    const domain = extractDomain(recipient);
    const date = formatDate();
    const link = links[Math.floor(Math.random() * links.length)] || '';

    // Subject / name
    let subject = subjects[Math.floor(Math.random() * subjects.length)] || '(no subject)';
    subject = expandPlaceholders(subject, { recipient, domain, date, link });

    let name = names[Math.floor(Math.random() * names.length)] || 'Support';
    name = expandPlaceholders(name, { recipient, domain, date, link });

    // === SPOOF From: root@<domain destinat> (sau override din fi?ier)
    const spoofFrom = `root@${domain}`;
    const fromEmail = OVERRIDE_FROM_EMAIL || spoofFrom;          // ex: root@gmail.com pt. user@gmail.com
    const replyToEmail = OVERRIDE_REPLY_TO || fromEmail;

    // Pick a random message template per email
    const messageTemplate = MESSAGE_TEMPLATES[Math.floor(Math.random() * MESSAGE_TEMPLATES.length)];
    const message = expandPlaceholders(messageTemplate, { recipient, domain, date, link });

    const mailOptions = {
      from: `${name} <${fromEmail}>`,
      to: recipient,
      subject: subject,
      html: message,
      replyTo: replyToEmail,
      // IMPORTANT: envelope controleaza MAIL FROM / Return-Path trimis prin SMTP
      envelope: {
        from: fromEmail,
        to: recipient
      },
      headers: {
        'List-Unsubscribe':
          `<mailto:${fromEmail}?subject=unsubscribe>, <https://arsys.es/unsubscribe?email=${encodeURIComponent(recipient)}>`
      }
    };

    // Build PDF attachment from /attach template(s)
    let attachPdf = await createPdfAttachment({ recipient, link });
    if (attachPdf) {
      mailOptions.attachments = [{
        filename: attachPdf.filename,
        content: attachPdf.content,
        contentType: attachPdf.contentType
      }];
    }

    try {
      await transporter.sendMail(mailOptions);
      const via = smtpConfig.local ? 'localhost' : (smtpConfig.host || 'SMTP');
      console.log(`[Sent] Email sent to ${recipient} by thread ${threadIndex} using ${via}`);
      fs.appendFileSync('sent.txt', recipient + '\n');
      emailCounter++;

      if (emailCounter >= maxEmailsPerSmtp) {
        smtpConfig = getNextSmtpServer();
        proxy = getRandomProxy();
        transporter = createTransporter(smtpConfig, proxy);
        console.log(`[Info] Switched SMTP to ${smtpConfig.host || 'localhost'} after ${maxEmailsPerSmtp} emails`);
      }
    } catch (error) {
      console.log(`[Error] Error sending email to ${recipient}: ${error && error.message ? error.message : error}`);
      fs.appendFileSync('failed.txt', recipient + '\n');
      smtpConfig = getNextSmtpServer();
      proxy = getRandomProxy();
      transporter = createTransporter(smtpConfig, proxy);
      console.log(`[Info] Switched SMTP to ${smtpConfig.host || 'localhost'} due to an error`);
    } finally {
      // STERGEM imediat orice folder temporar creat pentru attach (NUMAI daca DEBUG_ATTACH=1)
      if (attachPdf && attachPdf._tempDir) {
        try { fs.rmSync(attachPdf._tempDir, { recursive: true, force: true }); } catch {}
      }
      attachPdf = null;
    }

    // mic delay pentru a nu agresa SMTP-ul
    await sleep(500);
  }
};

// ===== Kick off threads =====
(async () => {
  // initialize Puppeteer upfront ca sa nu fie delay la primul mail
  try { await ensureBrowser(); } catch (e) { console.log('[Warn] Cannot launch Puppeteer now:', e.message || e); }

  const workers = [];
  for (let i = 0; i < numberOfThreads; i++) {
    workers.push(sendEmail(i));
  }
  await Promise.all(workers);

  // închidem browserul la final
  try {
    if (BROWSER) { await BROWSER.close(); BROWSER = null; }
  } catch {}
})();
