<?php
/***************************************************
 * send_bulk_mail.php (complete)
 * - Header-safe (no BOM/whitespace before <?php)
 * - Preprocess images/PDFs ONCE (no per-email Imagick)
 * - Per-email live updates (SSE) + polling fallback
 * - Fresh SMTP per email, strict timeouts, detailed logging
 * - Recipients selector (search + select all), Send to Selected / Send to All
 * - Polished UI (sticky progress/feed, toasts, modern styles)
 ***************************************************/

session_start();
error_reporting(0);
include('config.php');
require_once('auth_guard.php');
set_time_limit(0);
if (!ini_get('memory_limit') || ini_get('memory_limit') === '-1') { ini_set('memory_limit','512M'); }
gc_enable();

require 'config.php'; // MUST provide $conn (PDO)
require 'phpmailer/vendor/autoload.php';

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

/* ------------------------- Helpers ------------------------- */
function json_out($arr, $code=200) {
  // Make sure no previous buffered output leaks before headers.
  while (ob_get_level()) { ob_end_clean(); }
  if (!headers_sent()) {
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    header('Cache-Control: no-store, no-cache, must-revalidate');
  }
  echo json_encode($arr);
  exit();
}
function sse_event($event, $data) {
  echo "event: {$event}\n";
  echo "data: ".json_encode($data)."\n\n";
  @flush();
}
function safe_filename($name) { return preg_replace('/[^a-zA-Z0-9_\.-]+/','_', $name); }

/* ================= MODE: emails (AJAX - list recipients) ================= */
if (($_GET['mode'] ?? '') === 'emails') {
  if (strlen($_SESSION['alogin'] ?? '') == 0) { json_out(['ok'=>false,'error'=>'Unauthorized'], 401); }
  try {
    $sql = "SELECT DISTINCT email
            FROM aspnetusers
            WHERE email IS NOT NULL AND email != '' 
            ORDER BY email ASC";
    $stmt = $conn->prepare($sql);
    $stmt->execute();
    $emails = $stmt->fetchAll(PDO::FETCH_COLUMN) ?: [];
    json_out(['ok'=>true,'emails'=>$emails,'count'=>count($emails)]);
  } catch (Throwable $e) {
    json_out(['ok'=>false,'error'=>$e->getMessage()], 500);
  }
}

/* ================= MODE: start (AJAX - create job) ================= */
if (($_GET['mode'] ?? '') === 'start') {
  if (strlen($_SESSION['alogin'] ?? '') == 0) { json_out(['ok'=>false,'error'=>'Unauthorized'], 401); }

  $subject = trim($_POST['subject'] ?? '');
  $body    = trim($_POST['body'] ?? '');
  $news    = $_POST['news_points'] ?? [];
  $ads     = $_POST['ads_points'] ?? [];
  if ($subject === '' || $body === '') {
    json_out(['ok'=>false,'error'=>'Subject and body are required'], 422);
  }

  // ---- recipients: selected vs all ----
  $sendScope = $_POST['send_scope'] ?? 'all'; // 'all' | 'selected'
  $emails = [];
  if ($sendScope === 'selected') {
    $incoming = $_POST['selected_emails'] ?? [];
    if (is_string($incoming)) { $incoming = array_map('trim', explode(',', $incoming)); }
    $emails = array_values(array_unique(array_filter($incoming, fn($e)=> filter_var($e, FILTER_VALIDATE_EMAIL))));
    if (!$emails) { json_out(['ok'=>false,'error'=>'No valid selected emails provided'], 422); }
  } else {
    $sql = "SELECT DISTINCT email
            FROM aspnetusers
            WHERE email IS NOT NULL 
              AND email != '' ";
    $stmt = $conn->prepare($sql);
    $stmt->execute();
    $emails = $stmt->fetchAll(PDO::FETCH_COLUMN);
  }
  if (!$emails) json_out(['ok'=>false,'error'=>'No valid email addresses found'], 400);

  // ---- job workspace in system temp ----
  $jobId = uniqid('mail_', true);
  $dir   = sys_get_temp_dir().DIRECTORY_SEPARATOR.$jobId;
  $assetsDir = $dir.'/assets';
  if (!mkdir($dir, 0777, true) && !is_dir($dir))     { json_out(['ok'=>false,'error'=>'Failed to create job dir'], 500); }
  if (!mkdir($assetsDir, 0777, true) && !is_dir($assetsDir)) { json_out(['ok'=>false,'error'=>'Failed to create assets dir'], 500); }
  $logFile = $dir.'/email_log_'.date('Y-m-d').'.log';
  file_put_contents($logFile, date('Y-m-d H:i:s')." [START] Job $jobId\n");

  // ---- preprocess uploads ONCE (avoid per-email Imagick) ----
  $imagickAvailable = extension_loaded('imagick');
  $embedImages = []; // file paths
  $embedPdfs   = []; // jpg previews from PDFs

  // helper: watermark + resize image once
  $prep_image = function($src, $dest) use ($imagickAvailable, $logFile) {
    try {
      if ($imagickAvailable) {
        $im = new Imagick($src);
        if ($im->getImageOrientation()) { $im->autoOrient(); }
        $w = $im->getImageWidth(); $h = $im->getImageHeight();
        $maxW = 1200; $maxH = 1200;
        if ($w > $maxW || $h > $maxH) { $im->thumbnailImage($maxW, $maxH, true); }
        $draw = new ImagickDraw();
        $draw->setFillColor('rgba(0,0,0,0.35)');
        $draw->setGravity(Imagick::GRAVITY_CENTER);
        $draw->setFontSize(min($im->getImageWidth()/10, 48));
        $draw->annotation(0,0,'Demo Markets');
        $im->drawImage($draw);
        $im->setImageCompressionQuality(82);
        $im->setImageFormat('jpeg');
        $im->writeImage($dest);
        $im->clear(); $im->destroy();
      } else {
        copy($src, $dest);
      }
      return true;
    } catch (Throwable $e) {
      file_put_contents($logFile, "[IMG PREP ERROR] ".$e->getMessage()."\n", FILE_APPEND);
      return false;
    }
  };

  // helper: pdf first-page preview -> jpg
  $prep_pdf = function($pdf, $dest) use ($imagickAvailable, $logFile) {
    if (!$imagickAvailable) { return false; }
    try {
      $im = new Imagick();
      $im->setResolution(144,144);
      $im->readImage($pdf.'[0]');
      $im->setImageFormat('jpeg');
      $w = $im->getImageWidth(); $h = $im->getImageHeight();
      if ($w > 1400 || $h > 1400) { $im->thumbnailImage(1400, 1400, true); }
      $draw = new ImagickDraw();
      $draw->setFillColor('rgba(0,0,0,0.15)');
      $draw->setGravity(Imagick::GRAVITY_CENTER);
      $draw->setFontSize(52);
      $draw->annotation(0,0,'Demo Markets');
      $im->drawImage($draw);
      $im->setImageCompressionQuality(80);
      file_put_contents($dest, $im->getImageBlob());
      $im->clear(); $im->destroy();
      return true;
    } catch (Throwable $e) {
      file_put_contents($logFile, "[PDF PREP ERROR] ".$e->getMessage()."\n", FILE_APPEND);
      return false;
    }
  };

  // ---- save + preprocess IMAGES ----
  if (!empty($_FILES['images']['name'][0])) {
    foreach ($_FILES['images']['tmp_name'] as $i => $tmp) {
      if (($_FILES['images']['error'][$i] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_OK) {
        $name = safe_filename($_FILES['images']['name'][$i]);
        $ext  = strtolower(pathinfo($name, PATHINFO_EXTENSION));
        if (in_array($ext, ['jpg','jpeg','png','gif'], true)) {
          $src = $assetsDir."/orig_img_$i.$ext";
          if (@move_uploaded_file($tmp, $src)) {
            $dest = $assetsDir."/embed_img_$i.jpg";
            if ($prep_image($src, $dest)) { $embedImages[] = $dest; }
          }
        }
      }
    }
  }

  // ---- save + preprocess PDFs (first page preview) ----
  if (!empty($_FILES['attachments']['name'][0])) {
    foreach ($_FILES['attachments']['tmp_name'] as $i => $tmp) {
      if (($_FILES['attachments']['error'][$i] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_OK) {
        $name = safe_filename($_FILES['attachments']['name'][$i]);
        $ext  = strtolower(pathinfo($name, PATHINFO_EXTENSION));
        if ($ext === 'pdf') {
          $src = $assetsDir."/orig_pdf_$i.pdf";
          if (@move_uploaded_file($tmp, $src)) {
            $dest = $assetsDir."/embed_pdf_$i.jpg";
            if ($prep_pdf($src, $dest)) { $embedPdfs[] = $dest; }
          }
        }
      }
    }
  }

  // Build static sections once (HTML without CIDs; we’ll insert per email)
  $newsHTML = '';
  $news = array_values(array_filter(array_map('trim',$news)));
  if ($news) {
    $newsHTML .= '<div class="section-box"><h3><i class="fas fa-newspaper"></i> News Highlights</h3><ul>';
    foreach ($news as $p) $newsHTML .= '<li><i class="fas fa-check-circle"></i> '.htmlspecialchars($p).'</li>';
    $newsHTML .= '</ul></div>';
  }
  $adsHTML = '';
  $ads = array_values(array_filter(array_map('trim',$ads)));
  if ($ads) {
    $adsHTML .= '<div class="section-box"><h3><i class="fas fa-bullhorn"></i> Announcements</h3><ul>';
    foreach ($ads as $p) $adsHTML .= '<li><i class="fas fa-bolt"></i> '.htmlspecialchars($p).'</li>';
    $adsHTML .= '</ul></div>';
  }

  $payload = [
    'subject'=>$subject,
    'body'=>$body,
    'newsHTML'=>$newsHTML,
    'adsHTML'=>$adsHTML,
    'emails'=>$emails,
    'embedImages'=>$embedImages,
    'embedPdfs'=>$embedPdfs,
    'createdAt'=>time()
  ];
  file_put_contents($dir.'/payload.json', json_encode($payload, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
  file_put_contents($dir.'/progress.json', json_encode(['total'=>count($emails),'sent'=>0,'failed'=>0,'done'=>false]));
  file_put_contents($dir.'/feed.ndjson', ''); // for polling fallback

  json_out(['ok'=>true,'jobId'=>$jobId,'total'=>count($emails)]);
}

/* ============ MODE: run (SSE stream; fresh SMTP per email) ============ */
if (($_GET['mode'] ?? '') === 'run') {
  if (strlen($_SESSION['alogin'] ?? '') == 0) { http_response_code(401); exit('Unauthorized'); }

  // Ensure absolutely no buffered output before headers.
  if (session_status() === PHP_SESSION_ACTIVE) { session_write_close(); }
  while (ob_get_level()) { ob_end_clean(); }
  @ini_set('output_buffering','off');
  @ini_set('zlib.output_compression', 0);
  @ini_set('implicit_flush', 1);
  ob_implicit_flush(true);

  header('Content-Type: text/event-stream; charset=utf-8');
  header('Cache-Control: no-cache, no-transform');
  header('X-Accel-Buffering: no');
  header('Connection: keep-alive');

  echo str_repeat(' ', 2048) . "\n"; @flush();

  $jobId = $_GET['job'] ?? '';
  $dir   = $jobId ? (sys_get_temp_dir().DIRECTORY_SEPARATOR.$jobId) : '';
  if (!$jobId || !is_dir($dir) || !file_exists($dir.'/payload.json')) { http_response_code(404); echo "data: ".json_encode(['error'=>'Job not found'])."\n\n"; exit(); }
  $payload = json_decode(file_get_contents($dir.'/payload.json'), true);
  $progressPath = $dir.'/progress.json';
  $logFile = $dir.'/email_log_'.date('Y-m-d').'.log';

  // ---- toggles ----
  $PER_EMAIL_SLEEP_MS  = 300;
  $BATCH_SLEEP_MS      = 500;
  $BATCH_SIZE          = 10;

  // ---- SMTP config (adjust) ----
  $SMTP_HOST   = 'send.smtp.com';
  $SMTP_PORT   = 587;
  $SMTP_USER   = 'support@mykfmarkets.com';
  $SMTP_PASS   = 'support@mykfmarkets.com'; // <-- replace with the real password/SMTP token
  $SMTP_SECURE = PHPMailer::ENCRYPTION_STARTTLS;
  // For SSL/465:
  // $SMTP_PORT = 465; $SMTP_SECURE = PHPMailer::ENCRYPTION_SMTPS;

  @ini_set('default_socket_timeout', 12);
  $SMTP_TIMEOUT = 12;

  $subject     = $payload['subject'] ?? '';
  $body        = $payload['body'] ?? '';
  $newsHTML    = $payload['newsHTML'] ?? '';
  $adsHTML     = $payload['adsHTML'] ?? '';
  $emails      = $payload['emails'] ?? [];
  $embedImages = $payload['embedImages'] ?? [];
  $embedPdfs   = $payload['embedPdfs'] ?? [];

  $total = count($emails);
  $sent = 0; $failed = 0;

  $makeEmailHTML = function($body, $newsHTML, $adsHTML, $imgCids, $pdfCids) {
    $imageHTML = '';
    if ($imgCids) {
      $imageHTML .= '<div style="margin:20px 0;border-top:1px solid #eee;padding-top:20px;"><div style="display:flex;flex-wrap:wrap;gap:15px;">';
      foreach ($imgCids as $cid) {
        $imageHTML .= '<div style="flex:1 0 200px;max-width:300px;"><img src="cid:'.$cid.'" style="max-width:100%;border:1px solid #ddd;box-shadow:0 2px 5px rgba(0,0,0,0.1);pointer-events:none;user-select:none;"></div>';
      }
      $imageHTML .= '</div></div>';
    }
    $pdfHTML = '';
    if ($pdfCids) {
      $pdfHTML .= '<div style="margin:20px 0;border-top:1px solid #eee;padding-top:20px;">';
      foreach ($pdfCids as $cid) {
        $pdfHTML .= '<div style="margin-bottom:15px;text-align:center;"><img src="cid:'.$cid.'" style="max-width:100%;border:1px solid #ddd;box-shadow:0 2px 5px rgba(0,0,0,0.1);pointer-events:none;user-select:none;"></div>';
      }
      $pdfHTML .= '</div>';
    }
    return '<!DOCTYPE html><html><head><meta charset="utf-8"><style>
      body{font-family:Arial,sans-serif;line-height:1.6;color:#333}
      .header{background:#002e5f;color:#fff;padding:25px;text-align:center}
      .content{padding:25px}
      .footer{background:#f5f5f5;padding:15px;text-align:center;font-size:12px;color:#666}
      ul{padding-left:20px}.section-box{background:#f9f9f9;border-left:4px solid #002e5f;padding:15px;margin:15px 0}
      a{color:#0d6efd;text-decoration:none}
    </style></head><body>
    <div class="header"><h2>Demo Markets Update</h2></div>
    <div class="content">'.nl2br($body).$newsHTML.$adsHTML.$imageHTML.$pdfHTML.'</div>
    <div class="footer">
      <p>© '.date('Y').' Demo Markets. All rights reserved.</p>
      <p>Need assistance? <a href="mailto:support@mykfmarkets.com">support@mykfmarkets.com</a></p>
      <p>Risk Disclaimer: Trading involves substantial risk of loss and is not suitable for every investor.</p>
      <p>Physical Address: Suite 405, Harbour View Tower, 25 Ocean Boulevard, George Town, United Kingdom</p>
    </div></body></html>';
  };

  sse_event('stats', ['total'=>$total,'sent'=>0,'failed'=>0,'remaining'=>$total,'progress'=>0]);

  $batches = $total ? (int)ceil($total / $BATCH_SIZE) : 0;
  for ($b=0; $b<$batches; $b++) {
    $batch = array_slice($emails, $b*$BATCH_SIZE, $BATCH_SIZE);

    foreach ($batch as $email) {
      $lastStatus = 'SENT'; $lastError = null;

      // New CID per email; reuse preprocessed files
      $imgCidMap = [];
      foreach ($embedImages as $i => $path) {
        $imgCidMap['imgcid_'.$i.'_'.substr(md5($email.microtime(true)),0,8)] = $path;
      }
      $pdfCidMap = [];
      foreach ($embedPdfs as $i => $path) {
        $pdfCidMap['pdfcid_'.$i.'_'.substr(md5($email.microtime(true)),0,8)] = $path;
      }

      $html = $makeEmailHTML($body, $newsHTML, $adsHTML, array_keys($imgCidMap), array_keys($pdfCidMap));

      $mail = new PHPMailer(true);
      try {
        $mail->isSMTP();
        $mail->SMTPDebug = 0;
        $mail->Host = $SMTP_HOST;
        $mail->Port = $SMTP_PORT;
        $mail->SMTPAuth = true;
        $mail->Username = $SMTP_USER;
        $mail->Password = $SMTP_PASS;
        $mail->SMTPSecure = $SMTP_SECURE;
        $mail->SMTPAutoTLS = ($SMTP_SECURE === PHPMailer::ENCRYPTION_STARTTLS);
        $mail->Timeout = $SMTP_TIMEOUT;
        $mail->CharSet = 'UTF-8';
        // Optionally relax SSL checks:
        // $mail->SMTPOptions = ['ssl' => ['verify_peer' => false, 'verify_peer_name'=> false, 'allow_self_signed' => true]];

        $mail->setFrom('updates@mykfmarkets.com','Demo Markets Updates');
        $mail->addReplyTo('support@mykfmarkets.com','Demo Markets Support');
        $mail->addAddress($email);

        $mail->isHTML(true);
        $mail->Subject = $subject;
        $mail->Body    = $html;
        $mail->AltBody = strip_tags($body);

        foreach ($imgCidMap as $cid => $path) { if (is_file($path)) { $mail->addEmbeddedImage($path, $cid); } }
        foreach ($pdfCidMap as $cid => $path) { if (is_file($path)) { $mail->addEmbeddedImage($path, $cid); } }

        // retry/backoff
        $ok = false; $attempt = 0; $maxAttempts = 3;
        while (!$ok && $attempt < $maxAttempts) {
          $attempt++;
          try { $ok = $mail->send(); if (!$ok) $lastError = $mail->ErrorInfo; }
          catch (Throwable $e) { $ok = false; $lastError = $e->getMessage(); }
          if (!$ok) { usleep($attempt * 500000); }
        }

        if ($ok) {
          $sent++; $lastStatus='SENT';
          file_put_contents($logFile, date('Y-m-d H:i:s')." - Sent to $email\n", FILE_APPEND);
          try {
            $ins = $GLOBALS['conn']->prepare("INSERT INTO sent_emails (recipient, subject, ip_address) VALUES (?, ?, ?)");
            $ins->execute([$email, $subject, $_SERVER['REMOTE_ADDR'] ?? '']);
          } catch (Throwable $e) { /* non-fatal */ }
        } else {
          $failed++; $lastStatus='FAILED';
          file_put_contents($logFile, date('Y-m-d H:i:s')." - FAILED to $email: ".$lastError."\n", FILE_APPEND);
        }
      } catch (Throwable $e) {
        $failed++; $lastStatus='FAILED'; $lastError = $e->getMessage();
        file_put_contents($logFile, date('Y-m-d H:i:s')." - FAILED to $email: ".$e->getMessage()."\n", FILE_APPEND);
      } finally {
        try { $mail->smtpClose(); } catch (Throwable $e) {}
        unset($mail);
      }

      gc_collect_cycles();

      $remaining = max(0, $total - ($sent + $failed));
      $progress  = $total ? round((($sent + $failed) / $total) * 100, 2) : 100;

      file_put_contents($progressPath, json_encode(['total'=>$total,'sent'=>$sent,'failed'=>$failed,'done'=>false]));
      file_put_contents($dir.'/feed.ndjson', json_encode([
        'email'=>$email, 'status'=>$lastStatus, 'error'=>$lastError,
        'sent'=>$sent, 'failed'=>$failed, 'total'=>$total, 'ts'=>time()
      ])."\n", FILE_APPEND);

      sse_event('stats', [
        'total'=>$total,'sent'=>$sent,'failed'=>$failed,
        'remaining'=>$remaining,'progress'=>$progress,
        'lastEmail'=>$email,'lastStatus'=>$lastStatus,'lastError'=>$lastError
      ]);

      @flush();
      usleep($PER_EMAIL_SLEEP_MS * 1000);
    }
    usleep($BATCH_SLEEP_MS * 1000);
  }

  file_put_contents($progressPath, json_encode(['total'=>$total,'sent'=>$sent,'failed'=>$failed,'done'=>true]));
  sse_event('done', ['total'=>$total,'sent'=>$sent,'failed'=>$failed,'remaining'=>0,'progress'=>100]);
  exit();
}

/* ============== MODE: progress (polling fallback) ============== */
if (($_GET['mode'] ?? '') === 'progress') {
  if (strlen($_SESSION['alogin'] ?? '') == 0) { json_out(['ok'=>false,'error'=>'Unauthorized'], 401); }
  $jobId = $_GET['job'] ?? '';
  $dir   = $jobId ? (sys_get_temp_dir().DIRECTORY_SEPARATOR.$jobId) : '';
  $progressPath = $dir.'/progress.json';
  $feedPath     = $dir.'/feed.ndjson';

  // Use json_out to avoid header issues
  $progress = file_exists($progressPath) ? json_decode(file_get_contents($progressPath), true) : null;

  // tail last line from feed
  $lastLine = null;
  if (file_exists($feedPath)) {
    $fh = fopen($feedPath, 'r');
    if ($fh) {
      fseek($fh, 0, SEEK_END);
      $pos = ftell($fh); $line = '';
      while ($pos > 0) {
        $pos--;
        fseek($fh, $pos, SEEK_SET);
        $char = fgetc($fh);
        if ($char === "\n" && $line !== '') break;
        $line = $char . $line;
      }
      fclose($fh);
      $lastLine = trim($line) ?: null;
    }
  }

  json_out([
    'ok' => (bool)$progress,
    'progress' => $progress ?: ['total'=>0,'sent'=>0,'failed'=>0,'done'=>false],
    'last' => $lastLine ? json_decode($lastLine, true) : null
  ]);
}

/* ================= DEFAULT: UI PAGE ================= */

$imagickAvailable = extension_loaded('imagick');
$message = '';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bulk Mailer</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
  :root{
    --brand:#0d6efd; --ink:#1f2937; --sub:#6b7280; --card:#ffffff; --soft:#f8fafc; --line:#e5e7eb;
    --success:#198754; --danger:#dc3545;
  }
  body{background:var(--soft); color:var(--ink);}
  .page-header{
    background:linear-gradient(135deg, #0d6efd, #5b7bff);
    color:#fff; padding:28px 20px; border-radius:16px;
    box-shadow:0 10px 20px rgba(13,110,253,.15); position:sticky; top:0; z-index:2;
  }
  .page-header h3{margin:0; font-weight:800; letter-spacing:.2px}
  .page-header .sub{opacity:.9}
  .pro-card{border:1px solid var(--line); border-radius:16px; background:var(--card);}
  .pro-card:not(.no-shadow){box-shadow:0 8px 18px rgba(2,8,20,.04)}
  .pro-card .card-header{background:transparent; border-bottom:1px dashed var(--line); padding:18px 20px}
  .pro-card .card-body{padding:20px}
  .section-title{font-weight:700; margin-bottom:10px}
  .form-label{font-weight:600; color:var(--ink)}
  .help{color:var(--sub)} .tiny{font-size:.8rem}
  #recipientsBox{
    max-height:300px; overflow:auto; background:#fbfdff; border:1px solid var(--line);
    border-radius:12px; padding:8px;
  }
  #recipientsBox .list-group-item{
    border:0; border-bottom:1px dashed var(--line); padding:.45rem .25rem; display:flex; gap:.5rem; align-items:center;
  }
  #recipientsBox .list-group-item:last-child{border-bottom:0}
  .pill{display:inline-flex; align-items:center; gap:.4rem; border:1px solid var(--line);
    padding:.25rem .55rem; border-radius:999px; background:#fff; font-size:.82rem;}
  .progress{height:14px; background:#eef2ff}
  .progress .progress-bar{font-size:.75rem; font-weight:700}
  #emailList{max-height:420px; overflow:auto; border:1px solid var(--line); border-radius:12px; padding:.5rem; background:#fff;}
  .feed-item{display:flex; align-items:center; justify-content:space-between; gap:.5rem; padding:.5rem .25rem; border-bottom:1px dashed var(--line)}
  .feed-item:last-child{border-bottom:0}
  .badge-soft{border:1px solid transparent; padding:.3rem .55rem; border-radius:999px; font-weight:600}
  .badge-soft-success{color:var(--success); border-color:#19875424; background:#19875414}
  .badge-soft-danger{color:var(--danger); border-color:#dc354524; background:#dc354514}
  .sticky-panel{position:sticky; top:84px}
  .btn-xl{padding:.85rem 1.2rem; border-radius:12px; font-weight:700}
  .btn-soft{background:#eef2ff; border:1px solid #dbe3ff}
  .btn-icon{display:inline-flex; align-items:center; gap:.5rem}
  .preview-container{display:flex;flex-wrap:wrap;gap:10px}
  .preview-container img{max-width:150px;max-height:150px;object-fit:contain;border:1px solid #ddd}
  .form-control, .form-select{border-radius:12px}
  textarea.form-control{min-height:160px}
  .form-control:focus, .form-select:focus{border-color:#b9ccff; box-shadow:0 0 0 .25rem rgba(13,110,253,.15)}
  .stats-row{display:flex; gap:12px; flex-wrap:wrap}
  .stat-chip{background:#f3f4f6; border:1px solid #e5e7eb; border-radius:10px; padding:.35rem .6rem; font-weight:600}
  .fade-in{animation:fade .25s ease-out both}
  @keyframes fade{from{opacity:0; transform:translateY(6px)} to{opacity:1; transform:none}}
</style>
</head>

<body class="bg-gray-100">
<?php include "header.php"; ?>
<div class="flex h-screen">
  <?php include "side_bar.php"; ?>
  <main class="flex-1 p-6 md:ml-64">
    <div class="dashboard-content-one">
      <div class="container py-4">
      

        <?php if ($message) { echo '<div class="alert alert-info">'.$message.'</div>'; } ?>
        <?php if ($imagickAvailable): ?>
          <div class="alert alert-secondary tiny">
            <i class="fas fa-file-pdf text-danger me-2"></i><strong>Document Preview:</strong>
            PDFs will be converted to watermarked images and inlined.
          </div>
        <?php else: ?>
          <div class="alert alert-warning tiny">
            <i class="fas fa-triangle-exclamation me-2"></i><strong>Imagick not installed.</strong> PDF previews will be skipped.
          </div>
        <?php endif; ?>

        <div class="row g-4">
          <!-- LEFT: Composer -->
          <div class="col-lg-7">
            <div class="pro-card">
              <div class="card-header">
                <div class="d-flex align-items-center justify-content-between">
                  <div class="section-title"><i class="fa-solid fa-users me-2"></i>Recipients</div>
                  <div class="stats-row tiny">
                    <span class="stat-chip">Total: <span id="statTotal">0</span></span>
                    <span class="stat-chip text-success">Sent: <span id="statSent">0</span></span>
                    <span class="stat-chip text-danger">Failed: <span id="statFailed">0</span></span>
                    <span class="stat-chip">Remaining: <span id="statRemain">0</span></span>
                  </div>
                </div>
              </div>
              <div class="card-body">
                <form id="mailForm" enctype="multipart/form-data" class="fade-in">
                  <!-- Recipients selector -->
                  <div class="mb-3">
                    <div class="d-flex flex-wrap gap-2 mb-2">
                      <button type="button" class="btn btn-soft btn-sm btn-icon" id="loadEmailsBtn">
                        <i class="fa-solid fa-download"></i><span>Load Emails</span>
                      </button>
                      <input type="text" class="form-control form-control-sm" id="emailSearch"
                             placeholder="Search email…" style="max-width:260px">
                      <div class="ms-auto tiny help">
                        Choose recipients then use <strong>Send to Selected</strong> or click <strong>Send to All</strong>.
                      </div>
                    </div>

                    <div id="recipientsBox">
                      <div class="tiny help px-2 py-2">Click “Load Emails” to fetch the list…</div>
                    </div>

                    <div class="d-flex align-items-center justify-content-between mt-2">
                      <label class="tiny d-flex align-items-center gap-2">
                        <input type="checkbox" id="selectAllToggle" disabled>
                        <span>Select All</span>
                      </label>
                      <div class="tiny help">
                        <span id="selCount">0</span> selected
                      </div>
                    </div>

                    <!-- Hidden scope -->
                    <input type="hidden" name="send_scope" id="send_scope" value="all">
                    <input type="hidden" name="selected_emails" id="selected_emails" value="">
                  </div>

                  <hr class="my-4">

                  <!-- Composer -->
                  <div class="mb-3">
                    <label class="form-label" for="subject">Email Subject</label>
                    <input class="form-control" id="subject" name="subject" placeholder="Write a compelling subject…" required>
                  </div>

                  <div class="mb-3">
                    <label class="form-label" for="body">Email Content</label>
                    <textarea class="form-control" id="body" name="body" placeholder="Write your message…" required></textarea>
                    <div class="tiny help mt-1">Tip: Keep it short. Add highlights & promos below. Images/PDFs will be embedded nicely.</div>
                  </div>

                  <div class="row g-3">
                    <div class="col-md-6">
                      <label class="form-label">News Highlights</label>
                      <div id="newsContainer">
                        <div class="input-group mb-2">
                          <input type="text" name="news_points[]" class="form-control" placeholder="e.g., New feature launched">
                          <button class="btn btn-outline-danger" type="button" onclick="this.closest('.input-group').remove()">
                            <i class="fas fa-times"></i>
                          </button>
                        </div>
                      </div>
                      <button type="button" class="btn btn-sm btn-outline-primary"
                              onclick="addField('newsContainer','news_points[]','News item')">
                        <i class="fas fa-plus me-1"></i>Add News
                      </button>
                    </div>

                    <div class="col-md-6">
                      <label class="form-label">Announcements</label>
                      <div id="adsContainer">
                        <div class="input-group mb-2">
                          <input type="text" name="ads_points[]" class="form-control" placeholder="e.g., 20% off for July">
                          <button class="btn btn-outline-danger" type="button" onclick="this.closest('.input-group').remove()">
                            <i class="fas fa-times"></i>
                          </button>
                        </div>
                      </div>
                      <button type="button" class="btn btn-sm btn-outline-success"
                              onclick="addField('adsContainer','ads_points[]','Announcement')">
                        <i class="fas fa-plus me-1"></i>Add Announcement
                      </button>
                    </div>
                  </div>

                  <hr class="my-4">

                  <div class="row g-3">
                    <div class="col-md-6">
                      <label for="images" class="form-label">Images</label>
                      <input class="form-control" type="file" id="images" name="images[]" accept="image/*" multiple>
                      <div id="imagePreview" class="preview-container mt-2 d-flex gap-2 flex-wrap"></div>
                    </div>
                    <div class="col-md-6">
                      <label for="attachments" class="form-label">PDF Documents</label>
                      <input class="form-control" type="file" id="attachments" name="attachments[]" accept=".pdf" multiple>
                      <div class="tiny help mt-1">Max ~ 15MB each (first page will be previewed & watermarked)</div>
                    </div>
                  </div>

                  <div class="d-flex flex-wrap gap-2 mt-4">
                    <button class="btn btn-success btn-xl btn-icon" id="sendSelectedBtn" type="button">
                      <i class="fas fa-paper-plane"></i><span>Send to Selected</span>
                    </button>
                    <button class="btn btn-primary btn-xl btn-icon" id="sendAllBtn" type="submit">
                      <i class="fas fa-paper-plane"></i><span>Send to All</span>
                    </button>
                  </div>
                </form>
              </div>
            </div>
          </div>

          <!-- RIGHT: Live panel -->
          <div class="col-lg-5">
            <div class="sticky-panel">
              <div class="pro-card mb-3">
                <div class="card-header d-flex align-items-center justify-content-between">
                  <div class="section-title d-flex align-items-center gap-2">
                    <i class="fa-solid fa-gauge-high"></i> Status & Progress
                  </div>
                  <span id="statusPill" class="pill"><i class="fa-regular fa-circle-dot"></i> Ready</span>
                </div>
                <div class="card-body">
                  <div class="progress mb-2">
                    <div id="bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width:0%">0%</div>
                  </div>
                  <div class="tiny help">Live per-email updates appear below. Streaming first, polling if needed.</div>
                </div>
              </div>

              <div class="pro-card no-shadow">
                <div class="card-header d-flex align-items-center gap-2">
                  <i class="fa-solid fa-list-check"></i>
                  <div class="section-title mb-0">Live Delivery Feed</div>
                </div>
                <div class="card-body">
                  <ul id="emailList" class="list-unstyled mb-0"></ul>
                </div>
              </div>

            </div>
          </div>
        </div> <!-- /row -->
      </div>
    </div><br><br></div>
<?php include 'footer.php'; ?>
  </main>
</div>


<!-- Toast container -->
<div class="position-fixed bottom-0 end-0 p-3" style="z-index:1080">
  <div id="toast" class="toast align-items-center text-bg-dark border-0" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="d-flex">
      <div class="toast-body" id="toastBody">Status</div>
      <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
  </div>
</div>

<script>
function addField(containerId, name, placeholder='') {
  const c = document.getElementById(containerId);
  const div = document.createElement('div');
  div.className = 'input-group mb-2';
  div.innerHTML = `
    <input type="text" name="${name}" class="form-control" placeholder="${placeholder}">
    <button class="btn btn-outline-danger" type="button" onclick="this.closest('.input-group').remove()"><i class="fas fa-times"></i></button>
  `;
  c.appendChild(div);
}

document.getElementById('images')?.addEventListener('change', (e) => {
  const p = document.getElementById('imagePreview'); if (!p) return; p.innerHTML = '';
  for (const f of e.target.files) {
    if (f.type.match('image.*')) {
      const r = new FileReader();
      r.onload = ev => { const img = document.createElement('img'); img.src = ev.target.result; p.appendChild(img); };
      r.readAsDataURL(f);
    }
  }
});

// Stats + elements
const statTotal = document.getElementById('statTotal');
const statSent  = document.getElementById('statSent');
const statFail  = document.getElementById('statFailed');
const statRem   = document.getElementById('statRemain');
const bar       = document.getElementById('bar');
const emailList = document.getElementById('emailList');

// Recipients selector elems
const loadBtn = document.getElementById('loadEmailsBtn');
const recipientsBox = document.getElementById('recipientsBox');
const emailSearch = document.getElementById('emailSearch');
const selectAllToggle = document.getElementById('selectAllToggle');
const selCountEl = document.getElementById('selCount');
const hiddenScope = document.getElementById('send_scope');
const hiddenSelected = document.getElementById('selected_emails');
const sendSelectedBtn = document.getElementById('sendSelectedBtn');
const sendAllBtn = document.getElementById('sendAllBtn');

let EMAIL_LIST = [];
let FILTERED_LIST = [];

// Status pill + toast
const statusPill = document.getElementById('statusPill');
function showToast(msg){
  const el = document.getElementById('toast');
  document.getElementById('toastBody').textContent = msg;
  const t = new bootstrap.Toast(el, {delay:2200});
  t.show();
}
function setStatus(msg, kind='info') {
  statusPill.innerHTML = `<i class="fa-regular fa-circle-dot"></i> ${msg}`;
  statusPill.style.borderColor = ({
    info:'#dbe3ff', success:'#b9f0cf', warning:'#ffe9b3', danger:'#ffc9c9'
  }[kind] || '#dbe3ff');
  showToast(msg);
}

function renderRecipients(list) {
  if (!list.length) {
    recipientsBox.innerHTML = '<div class="text-muted tiny px-2 py-2">No emails found.</div>';
    selectAllToggle.disabled = true;
    selCountEl.textContent = '0';
    return;
  }
  const html = [
    '<div class="list-group list-group-flush">',
    ...list.map(e=>`
      <label class="list-group-item d-flex align-items-center py-1">
        <input type="checkbox" class="form-check-input me-2 email-check" data-email="${e}">
        <span class="tiny">${e}</span>
      </label>
    `),
    '</div>'
  ].join('');
  recipientsBox.innerHTML = html;
  selectAllToggle.disabled = false;
  updateSelectedCount();
}
function updateSelectedCount() {
  const checks = recipientsBox.querySelectorAll('.email-check');
  const selected = Array.from(checks).filter(c => c.checked).length;
  selCountEl.textContent = String(selected);
}
function getSelectedEmails() {
  const checks = recipientsBox.querySelectorAll('.email-check:checked');
  return Array.from(checks).map(c => c.getAttribute('data-email'));
}

loadBtn?.addEventListener('click', async ()=>{
  loadBtn.disabled = true;
  loadBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin me-1"></i>Loading...';
  try {
    const r = await fetch('?mode=emails', {cache:'no-store'});
    const j = await r.json();
    if (!j.ok) throw new Error(j.error || 'Fetch failed');
    EMAIL_LIST = j.emails || [];
    FILTERED_LIST = EMAIL_LIST.slice();
    renderRecipients(FILTERED_LIST);
  } catch (e) {
    recipientsBox.innerHTML = `<div class="text-danger tiny px-2 py-2">Error: ${e.message||e}</div>`;
  } finally {
    loadBtn.disabled = false;
    loadBtn.innerHTML = '<i class="fa-solid fa-download me-1"></i>Load Emails';
  }
});

emailSearch?.addEventListener('input', ()=>{
  const q = emailSearch.value.trim().toLowerCase();
  FILTERED_LIST = !q ? EMAIL_LIST.slice() : EMAIL_LIST.filter(e => e.toLowerCase().includes(q));
  renderRecipients(FILTERED_LIST);
});

recipientsBox?.addEventListener('change', (e)=>{
  if (e.target.classList.contains('email-check')) { updateSelectedCount(); }
});

selectAllToggle?.addEventListener('change', ()=>{
  const checks = recipientsBox.querySelectorAll('.email-check');
  checks.forEach(c => c.checked = selectAllToggle.checked);
  updateSelectedCount();
});

sendSelectedBtn?.addEventListener('click', ()=>{
  const selected = getSelectedEmails();
  if (!selected.length) { alert('Please select at least one recipient.'); return; }
  hiddenScope.value = 'selected';
  hiddenSelected.value = selected.join(',');
  document.getElementById('mailForm').dispatchEvent(new Event('submit', {cancelable:true}));
});
sendAllBtn?.addEventListener('click', ()=>{
  hiddenScope.value = 'all';
  hiddenSelected.value = '';
});

const mailForm = document.getElementById('mailForm');

mailForm.addEventListener('submit', async (e) => {
  e.preventDefault();
  setStatus('Preparing job…','info');

  emailList.innerHTML = '';
  const fd = new FormData(e.target);
  try {
    const res = await fetch('?mode=start', { method:'POST', body:fd });
    const data = await res.json();
    if (!data.ok) throw new Error(data.error || 'Failed to start');

    statTotal.textContent = data.total;
    statSent.textContent  = 0;
    statFail.textContent  = 0;
    statRem.textContent   = data.total;
    bar.style.width = '0%';
    bar.textContent = '0%';
    sendAllBtn.disabled = true;
    sendSelectedBtn.disabled = true;
    setStatus('Sending emails… updating live.','info');

    let lastShownCount = 0;
    let es;
    let pollTimer = null;

    function appendFeed(email, status, error) {
      const li = document.createElement('li');
      li.className = 'feed-item';
      const left = document.createElement('div');
      left.className = 'tiny';
      left.textContent = email;
      const right = document.createElement('div');
      const badge = document.createElement('span');
      badge.className = 'badge-soft ' + (status === 'SENT' ? 'badge-soft-success' : 'badge-soft-danger');
      badge.textContent = status;
      right.appendChild(badge);
      if (error) {
        const small = document.createElement('small');
        small.className = 'text-danger ms-2';
        small.textContent = '(' + error + ')';
        right.appendChild(small);
      }
      li.appendChild(left); li.appendChild(right);
      emailList.appendChild(li);
      emailList.scrollTop = emailList.scrollHeight;
    }

    function startPolling() {
      if (pollTimer) return;
      setStatus('Streaming not available — switched to live polling.','warning');
      pollTimer = setInterval(async () => {
        const r = await fetch(`?mode=progress&job=${encodeURIComponent(data.jobId)}`, {cache:'no-store'});
        const j = await r.json();
        const s = j.progress || {};
        statTotal.textContent = s.total ?? 0;
        statSent.textContent  = s.sent ?? 0;
        statFail.textContent  = s.failed ?? 0;
        statRem.textContent   = Math.max(0, (s.total||0) - ((s.sent||0)+(s.failed||0)));
        const pct = s.total ? Math.round(((s.sent + s.failed)/s.total)*100) : 0;
        bar.style.width = pct + '%'; bar.textContent = pct + '%';

        const currentCount = (s.sent||0) + (s.failed||0);
        if (j.last && currentCount > lastShownCount) {
          appendFeed(j.last.email, j.last.status, j.last.error);
          lastShownCount = currentCount;
        }
        if (s.done) {
          clearInterval(pollTimer); pollTimer = null;
          setStatus('Completed','success');
          sendAllBtn.disabled = false;
          sendSelectedBtn.disabled = false;
        }
      }, 1000);
    }

    try {
      es = new EventSource(`?mode=run&job=${encodeURIComponent(data.jobId)}`);
      es.addEventListener('stats', (ev) => {
        const s = JSON.parse(ev.data);
        statTotal.textContent = s.total;
        statSent.textContent  = s.sent;
        statFail.textContent  = s.failed;
        statRem.textContent   = s.remaining;
        bar.style.width = s.progress + '%';
        bar.textContent = s.progress + '%';
        const count = (s.sent || 0) + (s.failed || 0);
        if (s.lastEmail && count > lastShownCount) {
          appendFeed(s.lastEmail, s.lastStatus || 'SENT', s.lastError || '');
          lastShownCount = count;
        }
      });
      es.addEventListener('done', (ev) => {
        const s = JSON.parse(ev.data);
        statTotal.textContent = s.total;
        statSent.textContent  = s.sent;
        statFail.textContent  = s.failed;
        statRem.textContent   = 0;
        bar.style.width = '100%';
        bar.textContent = '100%';
        setStatus('Completed','success');
        es.close();
        sendAllBtn.disabled = false;
        sendSelectedBtn.disabled = false;
      });
      es.onerror = () => { try { es.close(); } catch(e) {} startPolling(); };
    } catch (e2) {
      startPolling();
    }
  } catch (err) {
    console.error(err);
    setStatus(err.message || 'Failed to start job','danger');
    sendAllBtn.disabled = false;
    sendSelectedBtn.disabled = false;
  }
});
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
