<?php
// public/api/disparos_oficial.php
require_once __DIR__ . '/../../app/config.php';
require_once __DIR__ . '/../../app/db.php';
require_once __DIR__ . '/../../app/helpers.php';

header('Content-Type: application/json; charset=utf-8');

function jexit(array $payload, int $status = 200){
  http_response_code($status);
  echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
  exit;
}

if (empty($_SESSION['user']['id']) || empty($_SESSION['user']['email'])) {
  jexit(['ok' => false, 'error' => 'Não autenticado'], 401);
}

$pdo = db();

/* =========================================================
 * Helpers
 * ======================================================= */

function getOrCreateUsersId(PDO $pdo, string $sessionId, string $email, ?string $name = null): string {
  $q = $pdo->prepare('SELECT id FROM users WHERE email = :e LIMIT 1');
  $q->execute([':e' => $email]);
  $id = $q->fetchColumn();
  if ($id) return $id;

  $ins = $pdo->prepare('
    INSERT INTO users (id, email, name)
    VALUES (:id, :e, :n)
    ON CONFLICT (email) DO NOTHING
  ');
  $ins->execute([':id' => $sessionId, ':e' => $email, ':n' => $name]);

  $q->execute([':e' => $email]);
  $id = $q->fetchColumn();
  if (!$id) throw new RuntimeException('Falha ao sincronizar usuário em `users`.');
  return $id;
}

function fetchJSON(string $url, array $opts = []): array {
  $ctx = stream_context_create([
    'http' => [
      'method'  => $opts['method'] ?? 'GET',
      'header'  => $opts['header'] ?? "Content-Type: application/json\r\n",
      'content' => $opts['body'] ?? null,
      'timeout' => $opts['timeout'] ?? 15,
    ]
  ]);
  $res = @file_get_contents($url, false, $ctx);
  $status = 0;
  if (!empty($http_response_header[0]) && preg_match('/\s(\d{3})\s/', $http_response_header[0], $m)) {
    $status = (int)$m[1];
  }
  $json = $res ? json_decode($res, true) : null;
  return [
    'ok' => is_array($json),
    'status' => $status ?: null,
    'data' => is_array($json) ? $json : null,
    'raw' => $res,
  ];
}

/* ====== schedule helpers ====== */

function sch_now_local(array $schedule): DateTimeImmutable {
  $tzId = $schedule['tz'] ?? 'America/Sao_Paulo';
  try { $tz = new DateTimeZone($tzId); } catch (Throwable $e) { $tz = new DateTimeZone('America/Sao_Paulo'); }
  $nowUtc = new DateTimeImmutable('now', new DateTimeZone('UTC'));
  return $nowUtc->setTimezone($tz);
}

function sch_is_within_window(array $schedule, DateTimeImmutable $nowLocal): bool {
  $start = $schedule['start'] ?? null;
  $end   = $schedule['end']   ?? null;
  if (!$start || !$end) return true;

  [$sh,$sm] = array_map('intval', explode(':', $start));
  [$eh,$em] = array_map('intval', explode(':', $end));

  $today   = $nowLocal->format('Y-m-d');
  $startAt = new DateTimeImmutable("$today $sh:$sm:00", $nowLocal->getTimezone());
  $endAt   = new DateTimeImmutable("$today $eh:$em:00", $nowLocal->getTimezone());

  if ($startAt->getTimestamp() === $endAt->getTimestamp()) return true;

  if ($startAt < $endAt) return ($nowLocal >= $startAt && $nowLocal <= $endAt);

  // atravessa meia-noite
  return ($nowLocal >= $startAt) || ($nowLocal <= $endAt);
}

function sch_is_blocked(array $schedule, DateTimeImmutable $nowLocal): bool {
  $w = (int)$nowLocal->format('w'); // 0..6
  $bw = array_map('intval', (array)($schedule['blocked_weekdays'] ?? []));
  if (in_array($w, $bw, true)) return true;

  $today = $nowLocal->format('Y-m-d');
  $bd = (array)($schedule['blocked_dates'] ?? []);
  if (in_array($today, $bd, true)) return true;

  return false;
}

/* ====== evolua chat templates helpers ====== */

function getEvoluaChatToken(PDO $pdo, string $authUserId): ?string {
  $st = $pdo->prepare("SELECT wa_evolua_chat_token FROM auth_users WHERE id = :id LIMIT 1");
  $st->execute([':id' => $authUserId]);
  $tk = $st->fetchColumn();
  $tk = is_string($tk) ? trim($tk) : '';
  return $tk !== '' ? $tk : null;
}

function http_get_json_bearer(string $url, string $bearer, int $timeout = 20): array {
  $ch = curl_init($url);
  curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_TIMEOUT => $timeout,
    CURLOPT_HTTPHEADER => [
      "Authorization: Bearer {$bearer}",
      "Accept: application/json",
    ],
  ]);

  $raw = curl_exec($ch);
  $err = curl_error($ch);
  $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);

  $json = $raw ? json_decode($raw, true) : null;

  return [
    'ok' => ($raw !== false && !$err && is_array($json)),
    'status' => $status ?: null,
    'data' => is_array($json) ? $json : null,
    'error' => $err ?: null,
    'raw' => $raw,
  ];
}

function extractBodyPreview(array $tpl): string {
  $components = $tpl['components'] ?? [];
  if (!is_array($components)) return '';
  foreach ($components as $c) {
    if (($c['type'] ?? '') === 'BODY' && !empty($c['text'])) {
      $txt = trim((string)$c['text']);
      if (mb_strlen($txt) > 120) $txt = mb_substr($txt, 0, 120) . '…';
      return $txt;
    }
  }
  return '';
}

/* ====== template vars ====== */

function normalizeTemplateVars($templateVars): ?array {
  if ($templateVars === null) return null;
  if (!is_array($templateVars)) return null;

  $fmt = strtoupper((string)($templateVars['format'] ?? ''));
  $vals = $templateVars['values'] ?? null;

  if (!in_array($fmt, ['POSITIONAL','NAMED'], true)) return null;
  if (!is_array($vals)) return null;

  $clean = [];
  foreach ($vals as $k => $v) {
    $k = trim((string)$k);
    if ($k === '') continue;
    $clean[$k] = trim((string)$v);
  }

  return ['format' => $fmt, 'values' => $clean];
}

function templateSnapshotHasVars($templateSnapshot): bool {
  if (!is_array($templateSnapshot)) return false;

  $pf = strtoupper((string)($templateSnapshot['parameter_format'] ?? ''));
  $components = $templateSnapshot['components'] ?? [];
  $txt = '';

  if (is_array($components)) {
    foreach ($components as $c) {
      if (!is_array($c)) continue;
      $type = (string)($c['type'] ?? '');
      if ($type === 'BODY' || $type === 'HEADER' || $type === 'FOOTER') {
        $txt .= "\n" . (string)($c['text'] ?? '');
      }
    }
  }

  $hasPos   = (bool)preg_match('/\{\{\s*\d+\s*\}\}/', $txt);
  $hasNamed = (bool)preg_match('/\{\{\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\}\}/', $txt);

  if ($pf === 'POSITIONAL') return $hasPos;
  if ($pf === 'NAMED') return $hasNamed;

  // fallback
  return $hasPos || $hasNamed;
}

/* ====== load campaign ====== */

function loadCampaign(PDO $pdo, int $id, string $userId): array {
  $st = $pdo->prepare("
    SELECT
      id, user_id, nome, min_delay, max_delay, status, total, enviados, erros, sem_whatsapp,
      created_at, leads,
      schedule::text AS schedule_text,
      template_id,
      template_snapshot::text AS template_snapshot_text,
      template_vars::text AS template_vars_text,
      started_webhook_at, paused_webhook_at, auto_paused,
      synced_evolua_chat, synced_evolua_chat_at
    FROM disparos_oficial
    WHERE id=:id AND user_id=:u
    LIMIT 1
  ");
  $st->execute([':id'=>$id, ':u'=>$userId]);
  $c = $st->fetch(PDO::FETCH_ASSOC);
  if (!$c) throw new RuntimeException('Campanha não encontrada.');

  $leads = [];
  if (!empty($c['leads'])) {
    $leads = is_string($c['leads'])
      ? (json_decode($c['leads'], true) ?: [])
      : (is_array($c['leads']) ? $c['leads'] : []);
  }

  $schedule = $c['schedule_text'] ? (json_decode($c['schedule_text'], true) ?: null) : null;
  $templateSnapshot = $c['template_snapshot_text'] ? (json_decode($c['template_snapshot_text'], true) ?: null) : null;
  $templateVars = $c['template_vars_text'] ? (json_decode($c['template_vars_text'], true) ?: null) : null;

  return [
    'camp'=>$c,
    'leads'=>$leads,
    'schedule'=>$schedule,
    'template_snapshot'=>$templateSnapshot,
    'template_vars'=>$templateVars
  ];
}

/* ====== webhook payload ====== */

function buildWebhookPayload(PDO $pdo, array $campBundle, array $userRow): array {
  $c = $campBundle['camp'];
  $snap = $campBundle['template_snapshot'] ?? null;
  $tvars = $campBundle['template_vars'] ?? null;

  return [
    'event' => 'official_campaign.started',
    'campaign' => [
      'id'        => (int)$c['id'],
      'name'      => $c['nome'],
      'min_delay' => (int)$c['min_delay'],
      'max_delay' => (int)$c['max_delay'],
      'total'     => (int)$c['total'],
      'status'    => 'running',
      'created_at'=> $c['created_at'],
      'schedule'  => $campBundle['schedule'],

      'template'  => [
        'id' => $c['template_id'] ?? null,

        // atalhos
        'name' => is_array($snap) ? ($snap['name'] ?? null) : null,
        'language' => is_array($snap) ? ($snap['language'] ?? null) : null,
        'category' => is_array($snap) ? ($snap['category'] ?? null) : null,
        'parameter_format' => is_array($snap) ? ($snap['parameter_format'] ?? null) : null,

        // snapshot inteiro
        'snapshot' => $snap,

        // variáveis escolhidas no front
        'vars' => $tvars,
      ],
    ],
    'user' => [
      'id'    => $userRow['id'] ?? null,
      'email' => $userRow['email'] ?? null,
      'name'  => $userRow['name'] ?? null,
    ],
    'meta'  => $userRow['meta'] ?? null,
    'leads' => $campBundle['leads'],
  ];
}

function sendOfficialWebhook(array $payload): array {
  $url = N8N_OFFICIAL_WEBHOOK_URL ?: '';
  if (!$url) return ['configured'=>false];

  $r = http_post_json($url, $payload); // vem do helpers.php
  return [
    'configured'=>true,
    'ok'     => $r['ok'] ?? null,
    'status' => $r['status'] ?? null,
    'error'  => $r['error'] ?? null,
  ];
}

function buildSyncLeadsPayload(array $campBundle, array $userRow): array {
  $c = $campBundle['camp'];

  return [
    'event' => 'official_campaign.sync_leads',
    'campaign' => [
      'id' => (int)$c['id'],
      'name' => $c['nome'],
      'status' => $c['status'],
      'created_at' => $c['created_at'] ?? null,
      'template_id' => $c['template_id'] ?? null,
      'schedule' => $campBundle['schedule'] ?? null,
      'template_snapshot' => $campBundle['template_snapshot'] ?? null,
      'template_vars' => $campBundle['template_vars'] ?? null,
      'total' => (int)($c['total'] ?? 0),
    ],
    'user' => [
      'id'    => $userRow['id'] ?? null,
      'email' => $userRow['email'] ?? null,
      'name'  => $userRow['name'] ?? null,
      'meta'  => $userRow['meta'] ?? null,
    ],
    // Leads selecionados (o que você precisa sincronizar no Evolua Chat)
    'leads' => $campBundle['leads'] ?? [],
  ];
}

function sendSyncWebhook(array $payload): array {
  $url = defined('N8N_OFFICIAL_SYNC_WEBHOOK_URL') ? (N8N_OFFICIAL_SYNC_WEBHOOK_URL ?: '') : '';
  if (!$url) return ['configured' => false];

  $r = http_post_json($url, $payload); // helpers.php
  return [
    'configured' => true,
    'ok' => $r['ok'] ?? null,
    'status' => $r['status'] ?? null,
    'error' => $r['error'] ?? null,
    'data' => $r['data'] ?? null,
    'raw' => $r['raw'] ?? null,
  ];
}

/* =========================================================
 * Auth context
 * ======================================================= */

$authId    = $_SESSION['user']['id'];
$authEmail = $_SESSION['user']['email'];
$authName  = $_SESSION['user']['name'] ?? null;
$userId    = getOrCreateUsersId($pdo, $authId, $authEmail, $authName);

$action = $_GET['action'] ?? '';

try {
  switch ($action) {

    /* =====================================================
     * templates.list
     * =================================================== */
case 'templates.list': {
  $evoluaToken = getEvoluaChatToken($pdo, $authId);
  if (!$evoluaToken) {
    jexit([
      'ok' => false,
      'error' => 'Você precisa cadastrar o Token do Evolua Chat na tela de conexão da API Oficial.'
    ], 422);
  }

  $endpoints = [
    // endpoint antigo
    [
      'url'    => 'https://api.evoluachat.com/api/oficial/templates',
      'parser' => fn($data) => $data['data']['templates'] ?? [],
    ],
    // endpoint novo
    [
      'url'    => 'https://app.evoluachat.com.br/api/message-templates',
      'parser' => fn($data) => $data['data'] ?? ($data['templates'] ?? (isset($data[0]) ? $data : [])),
    ],
  ];

  $templates = null;
  $lastDebug = [];

  foreach ($endpoints as $ep) {
    $r = http_get_json_bearer($ep['url'], $evoluaToken, 25);

    if (!$r['ok'] || empty($r['data'])) {
      $lastDebug = ['url' => $ep['url'], 'status' => $r['status'], 'curl_error' => $r['error']];
      continue;
    }

    $raw = ($ep['parser'])($r['data']);
    if (is_array($raw) && count($raw) > 0) {
      $templates = $raw;
      break;
    }

    $lastDebug = ['url' => $ep['url'], 'status' => $r['status'], 'note' => 'resposta vazia'];
  }

  if ($templates === null) {
    jexit([
      'ok'    => false,
      'error' => 'Falha ao buscar templates no Evolua Chat.',
      'debug' => $lastDebug
    ], 502);
  }

  $out = [];
  foreach ($templates as $t) {
    if (!is_array($t)) continue;

    $status = (string)($t['status'] ?? '');
    if ($status !== 'APPROVED') continue;

    $out[] = [
      'id'               => (string)($t['id'] ?? ''),
      'name'             => (string)($t['name'] ?? ''),
      'language'         => (string)($t['language'] ?? ''),
      'category'         => (string)($t['category'] ?? ''),
      'sub_category'     => (string)($t['sub_category'] ?? ''),
      'status'           => $status,
      'parameter_format' => (string)($t['parameter_format'] ?? ''),
      'body_preview'     => extractBodyPreview($t),
      'snapshot'         => $t,
    ];
  }

  jexit([
    'ok'    => true,
    'data'  => $out,
    'total' => count($out),
  ]);
}
    
    /* =====================================================
     * list
     * =================================================== */
    case 'list': {
      $st = $pdo->prepare("
        SELECT 
          d.id, 
          d.nome, 
          d.status, 
          d.total,
          COALESCE(x.sent,0) AS enviados,
          COALESCE(x.err,0) AS erros,
          COALESCE(x.sem_whats,0) AS sem_whatsapp,
          d.template_id,
          d.template_snapshot::text AS template_snapshot_text,
          d.created_at,
          d.synced_evolua_chat,
          d.synced_evolua_chat_at
        FROM disparos_oficial d
        LEFT JOIN LATERAL (
          SELECT 
            COUNT(*) FILTER (WHERE di.status='sent') AS sent,
            COUNT(*) FILTER (WHERE di.status='error') AS err,
            COUNT(*) FILTER (WHERE di.status='sem_whatsapp') AS sem_whats
          FROM disparos_oficial_itens di
          WHERE di.disparo_id = d.id
        ) x ON TRUE
        WHERE d.user_id = :u
        ORDER BY d.id DESC
        LIMIT 200
      ");
      $st->execute([':u' => $userId]);
      $rows = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];

      jexit([
        'ok' => true,
        'data' => array_map(function($r){
          // Extrair nome do template do snapshot
          $templateName = '—';
          if (!empty($r['template_snapshot_text'])) {
            $snap = json_decode($r['template_snapshot_text'], true);
            if (is_array($snap) && !empty($snap['name'])) {
              $templateName = $snap['name'];
            }
          }
          
          return [
            'id' => (int)$r['id'],
            'nome' => $r['nome'],
            'status' => $r['status'],
            'total' => (int)($r['total'] ?? 0),
            'enviados' => (int)($r['enviados'] ?? 0),
            'erros' => (int)($r['erros'] ?? 0),
            'sem_whatsapp' => (int)($r['sem_whatsapp'] ?? 0),
            'template_id' => $r['template_id'] ?? null,
            'template_name' => $templateName, // NOVO
            'synced_evolua_chat' => (bool)($r['synced_evolua_chat'] ?? false),
            'synced_evolua_chat_at' => $r['synced_evolua_chat_at'] ?? null,
            'created_at' => $r['created_at'] ?? null,
          ];
        }, $rows),
      ]);
    }

    /* =====================================================
     * create
     * =================================================== */
    case 'create': {
      $in = json_decode(file_get_contents('php://input'), true) ?? [];

      $nome     = trim((string)($in['nome'] ?? ''));
      $minDelay = max(1, (int)($in['min_delay'] ?? 1));
      $maxDelay = max($minDelay, (int)($in['max_delay'] ?? $minDelay));

      $leadIds  = $in['lead_ids'] ?? [];
      $templateId = isset($in['template_id']) ? trim((string)$in['template_id']) : '';
      $templateSnapshot = $in['template_snapshot'] ?? null;

      // template vars vindas do front
      $templateVars = normalizeTemplateVars($in['template_vars'] ?? null);

      // schedule
      $schedule = null;
      if (!empty($in['schedule']) && is_array($in['schedule'])) {
        $schedule = [
          'tz' => trim((string)($in['schedule']['tz'] ?? 'America/Sao_Paulo')) ?: 'America/Sao_Paulo',
          'start' => trim((string)($in['schedule']['start'] ?? '')),
          'end'   => trim((string)($in['schedule']['end']   ?? '')),
          'blocked_weekdays' => array_values(array_filter(array_map('intval', (array)($in['schedule']['blocked_weekdays'] ?? [])), fn($n)=>$n>=0 && $n<=6)),
          'blocked_dates'    => array_values(array_filter((array)($in['schedule']['blocked_dates'] ?? []), fn($d)=>preg_match('/^\d{4}-\d{2}-\d{2}$/',(string)$d))),
        ];
        if ($schedule['start']==='' || $schedule['end']==='') $schedule = null;
      }

      if (!is_array($leadIds)) $leadIds = [];
      $leadIds = array_values(array_unique(array_map('intval', $leadIds)));

      if ($nome === '' || empty($leadIds)) {
        jexit(['ok'=>false,'error'=>'Informe nome e selecione leads.'], 422);
      }

      if ($templateId === '') {
        jexit(['ok'=>false,'error'=>'Selecione um template.'], 422);
      }

      // se o template tem variáveis, exige preenchimento
      if (templateSnapshotHasVars($templateSnapshot) && empty($templateVars)) {
        jexit(['ok'=>false,'error'=>'Esse template possui variáveis. Preencha as variáveis antes de criar a campanha.'], 422);
      }

      // Buscar leads
      $inQ = implode(',', array_fill(0, count($leadIds), '?'));
      $sqlLeads = "SELECT id, company_name, phone FROM leads WHERE user_id = ? AND id IN ($inQ)";
      $params = array_merge([$userId], $leadIds);
      $stL = $pdo->prepare($sqlLeads);
      $stL->execute($params);
      $rows = $stL->fetchAll(PDO::FETCH_ASSOC);

      $leadsPayload = [];
      foreach ($rows as $r) {
        $tel = preg_replace('/\D+/', '', $r['phone'] ?? '');
        if ($tel === '') continue;
        $leadsPayload[] = [
          'id'      => (int)$r['id'],
          'company' => $r['company_name'] ?? null,
          'phone'   => $tel,
        ];
      }
      if (!$leadsPayload) jexit(['ok'=>false,'error'=>'Nenhum telefone válido.'], 422);

      $total = count($leadsPayload);

      $sql = "
        INSERT INTO disparos_oficial
          (user_id, nome, min_delay, max_delay, status, total, leads,
           schedule, template_id, template_snapshot, template_vars)
        VALUES
          (:u, :n, :a, :b, 'draft', :tot, :leads::jsonb,
           :schedule::jsonb, :tid, :tsnap::jsonb, :tvars::jsonb)
        RETURNING id
      ";

      $st = $pdo->prepare($sql);
      $st->bindValue(':u', $userId);
      $st->bindValue(':n', $nome);
      $st->bindValue(':a', $minDelay, PDO::PARAM_INT);
      $st->bindValue(':b', $maxDelay, PDO::PARAM_INT);
      $st->bindValue(':tot', $total, PDO::PARAM_INT);
      $st->bindValue(':leads', json_encode($leadsPayload, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
      $st->bindValue(':schedule', $schedule ? json_encode($schedule, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) : null, $schedule ? PDO::PARAM_STR : PDO::PARAM_NULL);
      $st->bindValue(':tid', $templateId !== '' ? $templateId : null, $templateId !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL);
      $st->bindValue(':tsnap', $templateSnapshot ? json_encode($templateSnapshot, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) : null, $templateSnapshot ? PDO::PARAM_STR : PDO::PARAM_NULL);
      $st->bindValue(':tvars', $templateVars ? json_encode($templateVars, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) : null, $templateVars ? PDO::PARAM_STR : PDO::PARAM_NULL);

      $st->execute();

      $id = (int)$st->fetchColumn();
      jexit(['ok'=>true,'id'=>$id,'total'=>$total]);
    }

    /* =====================================================
     * sync_leads
     * =================================================== */
    case 'sync_leads': {
      $id = (int)($_POST['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $bundle = loadCampaign($pdo, $id, $userId);

      // já sincronizou? retorna ok sem chamar n8n
      if (!empty($bundle['camp']['synced_evolua_chat'])) {
        jexit([
          'ok' => true,
          'already' => true,
          'message' => 'Já sincronizado.',
          'campaign_id' => $id
        ]);
      }

      // pega userRow
      $stU = $pdo->prepare("SELECT id, email, name, meta FROM users WHERE id=:u LIMIT 1");
      $stU->execute([':u'=>$userId]);
      $userRow = $stU->fetch(PDO::FETCH_ASSOC) ?: ['id'=>$userId,'email'=>$authEmail,'name'=>$authName];

      // monta payload
      $payload = buildSyncLeadsPayload($bundle, $userRow);

      // chama webhook do n8n e aguarda resposta
      $wh = sendSyncWebhook($payload);

      // se não configurou
      if (empty($wh['configured'])) {
        jexit(['ok'=>false,'error'=>'Webhook de sincronização não configurado no config.php'], 500);
      }

      // se falhou o request
      if (empty($wh['ok'])) {
        // salva debug e retorna erro
        $pdo->prepare("
          UPDATE disparos_oficial
             SET sync_webhook_status = :st,
                 sync_webhook_response = :resp::jsonb
           WHERE id=:id AND user_id=:u
        ")->execute([
          ':st' => (int)($wh['status'] ?? 0),
          ':resp' => json_encode([
            'ok' => $wh['ok'] ?? null,
            'status' => $wh['status'] ?? null,
            'error' => $wh['error'] ?? null,
            'raw' => $wh['raw'] ?? null,
          ], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),
          ':id' => $id,
          ':u' => $userId,
        ]);

        jexit([
          'ok'=>false,
          'error'=>'Falha ao sincronizar leads no webhook.',
          'debug'=>[
            'status'=>$wh['status'] ?? null,
            'error'=>$wh['error'] ?? null,
          ]
        ], 502);
      }

      // sucesso -> marca sincronizado
      $pdo->prepare("
        UPDATE disparos_oficial
           SET synced_evolua_chat = true,
               synced_evolua_chat_at = NOW(),
               sync_webhook_status = :st,
               sync_webhook_response = :resp::jsonb
         WHERE id=:id AND user_id=:u
      ")->execute([
        ':st' => (int)($wh['status'] ?? 200),
        ':resp' => json_encode($wh['data'] ?? ['ok'=>true], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),
        ':id' => $id,
        ':u' => $userId,
      ]);

      jexit([
        'ok'=>true,
        'campaign_id'=>$id,
        'webhook'=>[
          'status'=>$wh['status'] ?? 200,
        ],
        'message'=>'Leads sincronizados com sucesso.'
      ]);
    }

    /* =====================================================
     * start
     * =================================================== */
    case 'start': {
      $id = (int)($_POST['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $bundle = loadCampaign($pdo, $id, $userId);

      // BLOQUEIA start se não sincronizou
      if (empty($bundle['camp']['synced_evolua_chat'])) {
        jexit([
          'ok'=>false,
          'error'=>'Antes de iniciar, sincronize os leads com o Evolua Chat.',
          'needs_sync'=>true
        ], 409);
      }

      if (is_array($bundle['schedule'])) {
        $nowLocal = sch_now_local($bundle['schedule']);
        $inside   = sch_is_within_window($bundle['schedule'], $nowLocal);
        $blocked  = sch_is_blocked($bundle['schedule'], $nowLocal);

        if (!$inside || $blocked) {
          $pdo->prepare("
            UPDATE disparos_oficial
               SET status='paused',
                   paused_webhook_at = NOW(),
                   auto_paused = true
             WHERE id=:id AND user_id=:u
          ")->execute([':id'=>$id, ':u'=>$userId]);

          jexit([
            'ok'=>true,
            'scheduled'=>true,
            'status'=>'paused',
            'auto_paused'=>true,
            'message'=>'Campanha programada para retomar na próxima janela.'
          ]);
        }
      }

      $u = $pdo->prepare("
        UPDATE disparos_oficial
           SET status='running',
               started_webhook_at = COALESCE(started_webhook_at, NOW()),
               paused_webhook_at  = NULL,
               auto_paused = false
         WHERE id=:id AND user_id=:u
           AND status IN ('draft','paused')
      ");
      $u->execute([':id'=>$id, ':u'=>$userId]);

      // garante itens pending
      $leadsPayload = $bundle['leads'];
      if ($leadsPayload) {
        $pdo->beginTransaction();

        $values=[]; $params=[];
        foreach ($leadsPayload as $i => $row) {
          $leadId  = (int)($row['id'] ?? 0);
          $tel     = preg_replace('/\D+/', '', (string)($row['phone'] ?? ''));
          if ($tel === '') continue;
          $values[] = "( :d$i, :l$i, :t$i, :s$i )";
          $params[":d$i"] = $id;
          $params[":l$i"] = $leadId ?: null;
          $params[":t$i"] = $tel;
          $params[":s$i"] = 'pending';
        }

        if ($values) {
          $sqlIns = "INSERT INTO disparos_oficial_itens (disparo_id, lead_id, telefone, status)
                     VALUES ".implode(',', $values)."
                     ON CONFLICT (disparo_id, telefone) DO NOTHING";
          $pdo->prepare($sqlIns)->execute($params);

          $pdo->prepare("
            UPDATE disparos_oficial
               SET total=(SELECT COUNT(*) FROM disparos_oficial_itens WHERE disparo_id=:d)
             WHERE id=:d AND user_id=:u
          ")->execute([':d'=>$id, ':u'=>$userId]);
        }

        $pdo->commit();
      }

      // userRow
      $stU = $pdo->prepare("SELECT id, email, name, meta FROM users WHERE id=:u LIMIT 1");
      $stU->execute([':u'=>$userId]);
      $userRow = $stU->fetch(PDO::FETCH_ASSOC) ?: ['id'=>$userId,'email'=>$authEmail,'name'=>$authName];

      $bundle = loadCampaign($pdo, $id, $userId);
      $payload = buildWebhookPayload($pdo, $bundle, $userRow);
      $webhook = sendOfficialWebhook($payload);

      jexit(['ok'=>true,'webhook'=>$webhook]);
    }

    /* =====================================================
     * pause
     * =================================================== */
    case 'pause': {
      $id = (int)($_POST['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $pdo->beginTransaction();

      $u = $pdo->prepare("
        UPDATE disparos_oficial
           SET status='paused',
               paused_webhook_at = NOW(),
               auto_paused = false
         WHERE id=:id AND user_id=:u AND status='running'
      ");
      $u->execute([':id'=>$id, ':u'=>$userId]);
      if ($u->rowCount() === 0) { $pdo->rollBack(); jexit(['ok'=>false,'error'=>'Não foi possível pausar.'], 409); }

      $pdo->prepare("
        UPDATE disparos_oficial_itens
           SET status='paused', updated_at=NOW()
         WHERE disparo_id=:d AND status IN ('pending','queued','retry')
      ")->execute([':d'=>$id]);

      $pdo->commit();
      jexit(['ok'=>true]);
    }

    /* =====================================================
     * resume
     * =================================================== */
    case 'resume': {
      $id = (int)($_POST['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $bundle = loadCampaign($pdo, $id, $userId);
      
      if (empty($bundle['camp']['synced_evolua_chat'])) {
        jexit([
          'ok'=>false,
          'error'=>'Antes de retomar, sincronize os leads com o Evolua Chat.',
          'needs_sync'=>true
        ], 409);
      }

      if (is_array($bundle['schedule'])) {
        $nowLocal = sch_now_local($bundle['schedule']);
        $inside   = sch_is_within_window($bundle['schedule'], $nowLocal);
        $blocked  = sch_is_blocked($bundle['schedule'], $nowLocal);

        if (!$inside || $blocked) {
          $pdo->prepare("
            UPDATE disparos_oficial
               SET status='paused',
                   paused_webhook_at = NOW(),
                   auto_paused = true
             WHERE id=:id AND user_id=:u
          ")->execute([':id'=>$id, ':u'=>$userId]);

          jexit(['ok'=>true,'scheduled'=>true,'status'=>'paused','auto_paused'=>true]);
        }
      }

      $pdo->beginTransaction();

      $u = $pdo->prepare("
        UPDATE disparos_oficial
           SET status='running', paused_webhook_at=NULL, auto_paused=false
         WHERE id=:id AND user_id=:u AND status='paused'
      ");
      $u->execute([':id'=>$id, ':u'=>$userId]);
      if ($u->rowCount() === 0) { $pdo->rollBack(); jexit(['ok'=>false,'error'=>'Não foi possível retomar.'], 409); }

      $pdo->prepare("
        UPDATE disparos_oficial_itens
           SET status='pending', updated_at=NOW()
         WHERE disparo_id=:d AND status='paused'
      ")->execute([':d'=>$id]);

      $pdo->commit();

      // reenvia webhook
      $stU = $pdo->prepare("SELECT id, email, name, meta FROM users WHERE id=:u LIMIT 1");
      $stU->execute([':u'=>$userId]);
      $userRow = $stU->fetch(PDO::FETCH_ASSOC) ?: ['id'=>$userId,'email'=>$authEmail,'name'=>$authName];

      $bundle = loadCampaign($pdo, $id, $userId);
      $payload = buildWebhookPayload($pdo, $bundle, $userRow);
      $webhook = sendOfficialWebhook($payload);

      jexit(['ok'=>true,'webhook'=>$webhook]);
    }

    /* =====================================================
     * cancel
     * =================================================== */
    case 'cancel': {
      $id = (int)($_POST['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $pdo->beginTransaction();

      $pdo->prepare("
        UPDATE disparos_oficial_itens
           SET status='canceled', updated_at=NOW()
         WHERE disparo_id=:d AND status IN ('pending','queued','retry','paused')
      ")->execute([':d'=>$id]);

      $u = $pdo->prepare("
        UPDATE disparos_oficial
           SET status='canceled'
         WHERE id=:id AND user_id=:u AND status IN ('draft','running','paused')
      ");
      $u->execute([':id'=>$id, ':u'=>$userId]);
      if ($u->rowCount() === 0) { $pdo->rollBack(); jexit(['ok'=>false,'error'=>'Não foi possível cancelar.'], 409); }

      $pdo->commit();
      jexit(['ok'=>true]);
    }

    /* =====================================================
     * delete
     * =================================================== */
    case 'delete': {
      $id = (int)($_POST['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $pdo->beginTransaction();
      $pdo->prepare("DELETE FROM disparos_oficial_itens WHERE disparo_id=:d")->execute([':d'=>$id]);

      $d = $pdo->prepare("DELETE FROM disparos_oficial WHERE id=:id AND user_id=:u");
      $d->execute([':id'=>$id, ':u'=>$userId]);
      if ($d->rowCount() === 0) { $pdo->rollBack(); jexit(['ok'=>false,'error'=>'Não foi possível excluir.'], 409); }

      $pdo->commit();
      jexit(['ok'=>true]);
    }

    /* =====================================================
     * stats
     * =================================================== */
    case 'stats': {
      $id = (int)($_GET['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $st = $pdo->prepare("
        SELECT
          COUNT(*) FILTER (WHERE status='sent')  AS enviados,
          COUNT(*) FILTER (WHERE status='error') AS erros,
          COUNT(*) FILTER (WHERE status='sem_whatsapp') AS sem_whatsapp,
          COUNT(*) AS total_itens
        FROM disparos_oficial_itens
        WHERE disparo_id=:d
      ");
      $st->execute([':d'=>$id]);
      $row = $st->fetch(PDO::FETCH_ASSOC) ?: ['enviados'=>0,'erros'=>0,'sem_whatsapp'=>0,'total_itens'=>0];

      $pdo->prepare("
        UPDATE disparos_oficial
           SET total = :tot
         WHERE id=:d AND user_id=:u
      ")->execute([':tot'=>(int)$row['total_itens'], ':d'=>$id, ':u'=>$userId]);

      jexit(['ok'=>true,'data'=>$row]);
    }

    /* =====================================================
     * details
     * =================================================== */
    case 'details': {
      $id    = (int)($_GET['id'] ?? 0);
      $page  = max(1, (int)($_GET['page'] ?? 1));
      $limit = min(100, max(10, (int)($_GET['limit'] ?? 20)));
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      $bundle = loadCampaign($pdo, $id, $userId);
      $c = $bundle['camp'];

      $stS = $pdo->prepare("
        SELECT
          COUNT(*) AS total,
          COUNT(*) FILTER (WHERE status='pending')  AS pending,
          COUNT(*) FILTER (WHERE status='queued')   AS queued,
          COUNT(*) FILTER (WHERE status='retry')    AS retry,
          COUNT(*) FILTER (WHERE status='sent')     AS sent,
          COUNT(*) FILTER (WHERE status='error')    AS error,
          COUNT(*) FILTER (WHERE status='paused')   AS paused,
          COUNT(*) FILTER (WHERE status='canceled') AS canceled,
          COUNT(*) FILTER (WHERE status='sem_whatsapp') AS sem_whatsapp
        FROM disparos_oficial_itens
        WHERE disparo_id=:d
      ");
      $stS->execute([':d'=>$id]);
      $stats = $stS->fetch(PDO::FETCH_ASSOC) ?: [];

      $offset = ($page - 1) * $limit;

      $stCnt = $pdo->prepare("SELECT COUNT(*) FROM disparos_oficial_itens WHERE disparo_id=:d");
      $stCnt->execute([':d'=>$id]);
      $totalLeads = (int)$stCnt->fetchColumn();

      $stL = $pdo->prepare("
        SELECT
          di.id, di.lead_id, di.telefone, di.status,
          l.company_name, l.folder_id, l.created_at AS lead_created_at,
          f.name AS folder_name
        FROM disparos_oficial_itens di
        LEFT JOIN leads l ON l.id = di.lead_id AND l.user_id = :u
        LEFT JOIN lead_folders f ON f.id = l.folder_id AND f.user_id = :u
        WHERE di.disparo_id = :d
        ORDER BY di.id
        LIMIT :lim OFFSET :off
      ");
      $stL->bindValue(':u', $userId);
      $stL->bindValue(':d', $id, PDO::PARAM_INT);
      $stL->bindValue(':lim', $limit, PDO::PARAM_INT);
      $stL->bindValue(':off', $offset, PDO::PARAM_INT);
      $stL->execute();

      $leadRows = $stL->fetchAll(PDO::FETCH_ASSOC) ?: [];

      jexit([
        'ok'=>true,
        'campaign'=>[
          'id' => (int)$c['id'],
          'nome' => $c['nome'],
          'status'=> $c['status'],
          'created_at'=> $c['created_at'],
          'total' => (int)$c['total'],
          'enviados' => (int)$c['enviados'],
          'erros' => (int)$c['erros'],
          'min_delay' => (int)$c['min_delay'],
          'max_delay' => (int)$c['max_delay'],
          'schedule'  => $bundle['schedule'],
          'template_id' => $c['template_id'] ?? null,
          'template_snapshot' => $bundle['template_snapshot'],
          'template_vars' => $bundle['template_vars'],
        ],
        'stats'=>$stats,
        'leads'=>[
          'page'=>$page,
          'limit'=>$limit,
          'total'=>$totalLeads,
          'data'=>array_map(fn($r)=>[
            'id'=>(int)$r['id'],
            'lead_id'=>$r['lead_id']!==null?(int)$r['lead_id']:null,
            'telefone'=>$r['telefone'],
            'status'=>$r['status'],
            'company_name'=>$r['company_name'],
            'lead_created_at'=>$r['lead_created_at'],
            'folder_id'=>$r['folder_id']!==null?(int)$r['folder_id']:null,
            'folder_name'=>$r['folder_name'] ?? null,
          ], $leadRows)
        ]
      ]);
    }

    default:
      jexit(['ok'=>false,'error'=>'Ação inválida'], 400);
  }

} catch (Throwable $e) {
  jexit(['ok'=>false,'error'=>$e->getMessage()], 500);
}