<?php
// public/api/disparos.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 is_uuid(string $s): bool {
  return (bool)preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', trim($s));
}

/**
 * Cria (se não existir) e retorna o id de `users` p/ o e-mail atual.
 */
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;
}

/** Carrega uma campanha do usuário + snapshot de funil + userRow + userMeta. */
function loadCampaignWithUser(PDO $pdo, int $disparoId, string $userId): array {
  // campanha
  $stC = $pdo->prepare("
    SELECT id, user_id, nome, min_delay, max_delay, total, enviados, erros, created_at, leads,
           COALESCE(ignore_default_message,false) AS ignore_default_message,
           COALESCE(ignore_timeout_seconds,0)     AS ignore_timeout_seconds,
           status, started_webhook_at, paused_webhook_at,
           funil_id, funil_snapshot,
           crm_stage_id
      FROM disparos
     WHERE id=:id AND user_id=:u
     LIMIT 1
  ");
  $stC->execute([':id'=>$disparoId, ':u'=>$userId]);
  $camp = $stC->fetch(PDO::FETCH_ASSOC);
  if (!$camp) throw new RuntimeException('Campanha não encontrada.');

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

  // user
  $stU = $pdo->prepare("
    SELECT id, email, name, meta, prompt_broadcast_agent, default_broadcast_message
    FROM users
    WHERE id=:u
    LIMIT 1
  ");
  $stU->execute([':u'=>$userId]);
  $userRow  = $stU->fetch(PDO::FETCH_ASSOC) ?: [];
  $userMeta = $userRow['meta'] ?? null;
  if (is_string($userMeta)) $userMeta = json_decode($userMeta, true);
  if (!is_array($userMeta)) $userMeta = [];

  // webhook
  $webhookList = $userMeta['webhook'] ?? [];
  $webhookUrl  = N8N_WEBHOOK_URL ?: ($webhookList[0] ?? '');

  // funil snapshot (já congelado em create/start)
  $funil = null;
  if (!empty($camp['funil_snapshot'])) {
    $funil = is_string($camp['funil_snapshot'])
            ? (json_decode($camp['funil_snapshot'], true) ?: null)
            : (is_array($camp['funil_snapshot']) ? $camp['funil_snapshot'] : null);
  }

  return [
    'camp'        => $camp,
    'leads'       => $leadsPayload,
    'userRow'     => $userRow,
    'userMeta'    => $userMeta,
    'webhookUrl'  => $webhookUrl,
    'funil'       => $funil,
  ];
}

/** Monta o payload padrão do webhook (idéntico ao do start). */
function buildCampaignPayload(array $bundle): array {
  $camp     = $bundle['camp'];
  $userRow  = $bundle['userRow'];
  $userMeta = $bundle['userMeta'];
  $funil    = $bundle['funil'];
  $leads    = $bundle['leads'];

  return [
    'event'    => 'campaign.started',
    'campaign' => [
      'id'        => (int)$camp['id'],
      'name'      => $camp['nome'],
      'min_delay' => (int)$camp['min_delay'],
      'max_delay' => (int)$camp['max_delay'],
      'total'     => (int)$camp['total'],
      'status'    => 'running',
      'created_at'=> $camp['created_at'],
      'ignore_default_message' => (bool)$camp['ignore_default_message'],
      'ignore_timeout_seconds' => (int)$camp['ignore_timeout_seconds'],
      'crm_stage_id' => isset($camp['crm_stage_id']) ? (int)$camp['crm_stage_id'] : null,
    ],
    'user' => [
      'id'    => $userRow['id'] ?? null,
      'email' => $userRow['email'] ?? null,
      'name'  => $userRow['name'] ?? null,
    ],
    'meta'                     => $userMeta,
    'instance'                 => $userMeta['instance'] ?? null,
    'prompt_broadcast_agent'   => trim((string)($userRow['prompt_broadcast_agent'] ?? '')),
    'default_broadcast_message'=> trim((string)($userRow['default_broadcast_message'] ?? '')),
    'funnel'                   => $funil,
    'leads'                    => $leads,
  ];
}

/** Envia webhook se houver URL. */
function sendCampaignWebhook(?string $webhookUrl, array $payload): ?array {
  if (!$webhookUrl) return null;
  return http_post_json($webhookUrl, $payload);
}

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

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


// --- Helpers de agenda (iguais aos do scheduler) ---
function sch_is_within_window(array $schedule, DateTimeImmutable $nowLocal): bool {
  $start = $schedule['start'] ?? null;
  $end   = $schedule['end']   ?? null;
  if (!$start || !$end) return true; // sem janela = 24h

  [$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; // 24h

  if ($startAt < $endAt) {
    return ($nowLocal >= $startAt && $nowLocal <= $endAt);
  } else {
    // atravessa meia-noite (ex: 22:00→08:00)
    return ($nowLocal >= $startAt) || ($nowLocal <= $endAt);
  }
}

function sch_is_blocked(array $schedule, DateTimeImmutable $nowLocal): bool {
  $w = (int)$nowLocal->format('w'); // 0=dom ... 6=sáb
  $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;
}

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);
}






try {
  switch ($action) {

    // ========== 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,
               COALESCE(d.ignore_default_message,false) AS ignore_default_message,
               COALESCE(d.ignore_timeout_seconds,0)     AS ignore_timeout_seconds,
               COALESCE(d.funil_snapshot->>'nome','Disparo por IA/Padrão') AS funil_nome
        FROM disparos 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_itens di
  WHERE di.disparo_id = d.id
) x ON TRUE
        WHERE d.user_id = :u
        ORDER BY d.id DESC
      ");
      $st->execute([':u' => $userId]);
      jexit(['ok' => true, 'data' => $st->fetchAll(PDO::FETCH_ASSOC)]);
    }

    // ========== UPDATE ==========
    case 'update': {
      // payload JSON
      $in = json_decode(file_get_contents('php://input'), true) ?? [];
      $id = (int)($in['id'] ?? 0);
      if ($id <= 0) jexit(['ok'=>false,'error'=>'ID inválido'], 422);

      // Existe? É do usuário?
      $st = $pdo->prepare("
        SELECT id, user_id, status
          FROM disparos
         WHERE id=:id AND user_id=:u
         LIMIT 1
      ");
      $st->execute([':id'=>$id, ':u'=>$userId]);
      $row = $st->fetch(PDO::FETCH_ASSOC);
      if (!$row) jexit(['ok'=>false,'error'=>'Campanha não encontrada'], 404);

      $status = $row['status'];
      if (!in_array($status, ['draft','running','paused'], true)) {
        jexit(['ok'=>false,'error'=>'Status não permite edição.'], 409);
      }

      // Campos editáveis
      $updates = [];
      $params  = [':id'=>$id, ':u'=>$userId];

      // nome
      if (array_key_exists('nome', $in)) {
        $nome = trim((string)$in['nome']);
        if ($nome === '') jexit(['ok'=>false,'error'=>'Nome não pode ser vazio.'], 422);
        $updates[] = 'nome = :nome';
        $params[':nome'] = $nome;
      }

      // delays
      if (array_key_exists('min_delay', $in)) {
        $a = max(1, (int)$in['min_delay']);
        $updates[] = 'min_delay = :a';
        $params[':a'] = $a;
      }
      if (array_key_exists('max_delay', $in)) {
        $b = max(1, (int)$in['max_delay']);
        $updates[] = 'max_delay = :b';
        $params[':b'] = $b;
      }

      // ignore default message + timeout
      $ignFlag = null; $ignSecs = null;
      if (array_key_exists('ignore_default_message', $in)) {
        $ignFlag = !empty($in['ignore_default_message']);
        $updates[] = 'ignore_default_message = :ign';
        $params[':ign'] = $ignFlag ? 'true' : 'false';
      }
      if (array_key_exists('ignore_timeout_seconds', $in)) {
        $ignSecs = (int)$in['ignore_timeout_seconds'];
        if ($ignSecs < 0) $ignSecs = 0;
      }
      // se user desligar o ignore, zera o seconds
      if ($ignFlag === false) $ignSecs = 0;
      if ($ignSecs !== null) {
        $updates[] = 'ignore_timeout_seconds = :igns';
        $params[':igns'] = $ignSecs;
      }

      // schedule
      if (array_key_exists('schedule', $in)) {
        $sch = $in['schedule'];
        if ($sch === null) {
          $updates[] = 'schedule = NULL';
        } else {
          // validações leves
          $tz    = trim((string)($sch['tz'] ?? 'America/Sao_Paulo'));
          $start = trim((string)($sch['start'] ?? ''));
          $end   = trim((string)($sch['end']   ?? ''));
          $wds   = array_values(array_filter(array_map('intval',(array)($sch['blocked_weekdays']??[])), fn($n)=>$n>=0 && $n<=6));
          $dates = array_values(array_filter((array)($sch['blocked_dates']??[]), fn($d)=>preg_match('/^\d{4}-\d{2}-\d{2}$/',(string)$d)));

          $payload = null;
          if ($start !== '' && $end !== '') {
            $payload = [
              'tz' => $tz ?: 'America/Sao_Paulo',
              'start' => $start,
              'end' => $end,
              'blocked_weekdays' => $wds,
              'blocked_dates' => $dates,
            ];
          }
          if ($payload === null) {
            $updates[] = 'schedule = NULL';
          } else {
            $updates[] = 'schedule = :schedule::jsonb';
            $params[':schedule'] = json_encode($payload, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
          }
        }
      }

      if (!$updates) jexit(['ok'=>false,'error'=>'Nada para atualizar.'], 422);

      $sql = "UPDATE disparos SET ".implode(', ', $updates)." WHERE id=:id AND user_id=:u";
      $u = $pdo->prepare($sql);
      $u->execute($params);

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



// ========== CHECK CONNECTION FAILURE ==========
    // Retorna se o usuário tem alguma campanha com falha_connection = true
    case 'check_connection_failure': {
      $st = $pdo->prepare("
        SELECT id, nome
          FROM disparos
         WHERE user_id = :u
           AND falha_connection = true
         ORDER BY id DESC
         LIMIT 1
      ");
      $st->execute([':u' => $userId]);
      $row = $st->fetch(PDO::FETCH_ASSOC);

      if ($row) {
        jexit([
          'ok'             => true,
          'has_failure'    => true,
          'campaign_id'    => (int)$row['id'],
          'campaign_nome'  => $row['nome'],
        ]);
      }
      jexit(['ok' => true, 'has_failure' => false]);
    }

    // ========== CLEAR CONNECTION FAILURE ==========
    // Limpa o flag falha_connection de TODAS as campanhas do usuário
    case 'clear_connection_failure': {
      $u = $pdo->prepare("
        UPDATE disparos
           SET falha_connection = false
         WHERE user_id = :u
           AND falha_connection = true
      ");
      $u->execute([':u' => $userId]);

      jexit([
        'ok'      => true,
        'cleared' => $u->rowCount(),
      ]);
    }













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

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

      // booleans
      $ignoreDefault = !empty($in['ignore_default_message']) ? 'true' : 'false';
      $ignoreSecs    = (int)($in['ignore_timeout_seconds'] ?? 0);
      if ($ignoreSecs < 0) $ignoreSecs = 0;
      if ($ignoreDefault !== 'true') $ignoreSecs = 0;

      // Funil opcional – aceita tanto UUID quanto número (compara por texto)
      $funilInput = isset($in['funil_id']) && $in['funil_id'] !== '' ? (string)$in['funil_id'] : null;
      $funilIdForColumn = null; // só preenche se for UUID válido (coluna funil_id = uuid)
      $funilSnapshot = null;

      if ($funilInput !== null) {
        $f = $pdo->prepare("
          SELECT id::text AS id_text, nome, versao, sequencia, status
          FROM funis
          WHERE id::text = :id AND user_id = :u
          LIMIT 1
        ");
        $f->execute([':id' => $funilInput, ':u' => $userId]);
        $row = $f->fetch(PDO::FETCH_ASSOC);

        if (!$row || $row['status'] !== 'published') {
          jexit(['ok'=>false,'error'=>'Funil inválido ou não publicado.'], 422);
        }

        if (is_uuid($funilInput)) {
          $funilIdForColumn = $funilInput; // grava em funil_id (uuid) somente se for uuid válido
        }

        $funilSnapshot = [
          'id_text'  => $row['id_text'],
          'nome'     => $row['nome'],
          'versao'   => (int)$row['versao'],
          'sequencia'=> is_string($row['sequencia'])
                        ? (json_decode($row['sequencia'], true) ?: [])
                        : ($row['sequencia'] ?: []),
        ];
      }

      if ($nome === '' || !is_array($leadIds) || empty($leadIds)) {
        jexit(['ok'=>false,'error'=>'Informe nome e selecione pelo menos 1 lead.'], 422);
      }

      // Buscar leads válidos
      $leadIds = array_values(array_unique(array_map('intval', $leadIds)));
      $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);
      if (!$rows) jexit(['ok'=>false,'error'=>'Nenhum lead válido encontrado.'], 422);

      $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 nos leads selecionados.'], 422);
      $total = count($leadsPayload);

      // --- NOVO: coletar agenda (opcional) ---
      $tz = trim((string)($in['schedule']['tz'] ?? 'America/Sao_Paulo'));
      if ($tz === '') $tz = 'America/Sao_Paulo';

      $start = trim((string)($in['schedule']['start'] ?? '')); // "HH:MM"
      $end   = trim((string)($in['schedule']['end']   ?? ''));

      $blockedWeekdays = $in['schedule']['blocked_weekdays'] ?? [];
      $blockedDates    = $in['schedule']['blocked_dates']    ?? [];

      // normalizações leves
      $blockedWeekdays = array_values(array_unique(array_map('intval', (array)$blockedWeekdays)));
      $blockedWeekdays = array_values(array_filter($blockedWeekdays, fn($n) => $n >= 0 && $n <= 6));
      $blockedDates    = array_values(array_filter((array)$blockedDates, function($d){
        return (bool)preg_match('/^\d{4}-\d{2}-\d{2}$/', (string)$d);
      }));

      $schedule = null;
      if ($start !== '' && $end !== '') {
        $schedule = [
          'tz'               => $tz,
          'start'            => $start,
          'end'              => $end,
          'blocked_weekdays' => $blockedWeekdays,
          'blocked_dates'    => $blockedDates,
        ];
      }

      // CRM Stage ID
      $crmStageId = isset($in['crm_stage_id']) && $in['crm_stage_id'] !== '' 
        ? (int)$in['crm_stage_id'] 
        : null;

      $sql = "
        INSERT INTO disparos
          (user_id, instance_id, nome, mensagem, min_delay, max_delay, status, total, leads,
           ignore_default_message, ignore_timeout_seconds,
           funil_id, funil_snapshot,
           schedule,
           crm_stage_id)
        VALUES
          (:u, NULL, :n, NULL, :a, :b, 'draft', :tot, :leads::jsonb,
           (:ign)::boolean, :igns,
           :fid, :fsnap::jsonb,
           :schedule::jsonb,
           :crm_stage_id)
        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(':ign', $ignoreDefault);
      $st->bindValue(':igns', $ignoreSecs, PDO::PARAM_INT);

      if ($funilIdForColumn === null) {
        $st->bindValue(':fid', null, PDO::PARAM_NULL);
      } else {
        $st->bindValue(':fid', $funilIdForColumn, PDO::PARAM_STR);
      }
      $st->bindValue(':fsnap',
        $funilSnapshot ? json_encode($funilSnapshot, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) : null,
        $funilSnapshot ? PDO::PARAM_STR : PDO::PARAM_NULL
      );

      // bind do schedule
      $st->bindValue(':schedule',
        $schedule ? json_encode($schedule, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) : null,
        $schedule ? PDO::PARAM_STR : PDO::PARAM_NULL
      );

      // bind do crm_stage_id
      $st->bindValue(':crm_stage_id', 
        $crmStageId, 
        $crmStageId !== null ? PDO::PARAM_INT : PDO::PARAM_NULL
      );

      $st->execute();
      $disparoId = (int)$st->fetchColumn();

      jexit(['ok'=>true,'id'=>$disparoId,'total'=>$total]);
    }

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

      // Verificar conexão antes de iniciar
      $stUser = $pdo->prepare("SELECT instance_name, state, url_api FROM users WHERE email=:e LIMIT 1");
      $stUser->execute([':e'=>$_SESSION['user']['email']]);
      $userConn = $stUser->fetch(PDO::FETCH_ASSOC);
      
      if (!$userConn || empty($userConn['instance_name'])) {
        jexit([
          'ok'=>false,
          'error'=>'connection_missing',
          'message'=>'Você não possui uma conexão WhatsApp configurada. Acesse a aba Conexões para criar uma.'
        ], 409);
      }

      if (strtolower($userConn['state'] ?? '') !== 'open') {
        jexit([
          'ok'=>false,
          'error'=>'connection_not_open',
          'message'=>'Sua conexão WhatsApp não está ativa. Acesse a aba Conexões para reconectar escaneando o QR Code.',
          'current_state'=>$userConn['state']
        ], 409);
      }

      // Carrega campanha para consultar schedule
      $stCamp = $pdo->prepare("SELECT id, user_id, status, schedule::text AS schedule_text FROM disparos WHERE id=:id AND user_id=:u LIMIT 1");
      $stCamp->execute([':id'=>$id, ':u'=>$userId]);
      $rowCamp = $stCamp->fetch(PDO::FETCH_ASSOC);
      if (!$rowCamp) jexit(['ok'=>false,'error'=>'Campanha não encontrada'], 404);

      $schedule = json_decode($rowCamp['schedule_text'] ?? 'null', true) ?: null;

      // Se houver schedule e estivermos fora/bloqueado, não mandar webhook agora
      if (is_array($schedule)) {
        $nowLocal = sch_now_local($schedule);
        $inside   = sch_is_within_window($schedule, $nowLocal);
        $blocked  = sch_is_blocked($schedule, $nowLocal);

        if (!$inside || $blocked) {
          // Garantir itens já agora (para a UI mostrar Total e o n8n ter pending na retomada)
          $bundle = loadCampaignWithUser($pdo, $id, $userId);
          $camp   = $bundle['camp'];
          $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"] = $camp['id'];
              $params[":l$i"] = $leadId ?: null;
              $params[":t$i"] = $tel;
              $params[":s$i"] = 'pending';
            }
            if ($values) {
              $sqlIns = "INSERT INTO disparos_itens (disparo_id, lead_id, telefone, status)
                         VALUES ".implode(',', $values)."
                         ON CONFLICT (disparo_id, telefone) DO NOTHING";
              $stIns = $pdo->prepare($sqlIns);
              $stIns->execute($params);

              $stTot = $pdo->prepare("
                UPDATE disparos
                   SET total=(SELECT COUNT(*) FROM disparos_itens WHERE disparo_id=:d)
                 WHERE id=:d
              ");
              $stTot->execute([':d'=>$camp['id']]);
            }
            $pdo->commit();
          }

          // Em vez de iniciar, deixa pausada por auto-paused
          $u = $pdo->prepare("
            UPDATE disparos
               SET status='paused',
                   paused_webhook_at = NOW(),
                   auto_paused = true
             WHERE id=:id AND user_id=:u
               AND status IN ('draft','running','paused')
          ");
          $u->execute([':id'=>$id, ':u'=>$userId]);

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

      // Dentro da janela → inicia normal
      $u = $pdo->prepare("
        UPDATE disparos
           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='draft' AND started_webhook_at IS NULL
      ");
      $u->execute([':id'=>$id, ':u'=>$userId]);
      if ($u->rowCount() === 0) {
        jexit(['ok'=>false,'error'=>'Não foi possível iniciar (já iniciado ou status inválido).'], 409);
      }

      // Garantir itens e enviar webhook
      $bundle = loadCampaignWithUser($pdo, $id, $userId);
      $camp   = $bundle['camp'];
      $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"] = $camp['id'];
          $params[":l$i"] = $leadId ?: null;
          $params[":t$i"] = $tel;
          $params[":s$i"] = 'pending';
        }
        if ($values) {
          $sqlIns = "INSERT INTO disparos_itens (disparo_id, lead_id, telefone, status)
                     VALUES ".implode(',', $values)."
                     ON CONFLICT (disparo_id, telefone) DO NOTHING";
          $stIns = $pdo->prepare($sqlIns);
          $stIns->execute($params);

          $stTot = $pdo->prepare("
            UPDATE disparos 
               SET total=(SELECT COUNT(*) FROM disparos_itens WHERE disparo_id=:d) 
             WHERE id=:d
          ");
          $stTot->execute([':d'=>$camp['id']]);
        }
        $pdo->commit();
      }

      // Webhook de start
      $bundle = loadCampaignWithUser($pdo, $id, $userId);
      $payload = buildCampaignPayload($bundle);
      $webhookResult = sendCampaignWebhook($bundle['webhookUrl'], $payload);

      jexit([
        'ok'=>true,
        'webhook'=>[
          'configured'=>(bool)$bundle['webhookUrl'],
          'ok'        =>$webhookResult['ok'] ?? null,
          'status'    =>$webhookResult['status'] ?? null,
          'error'     =>$webhookResult['error'] ?? null,
        ]
      ]);
    }

    // ========== 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
           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);
      }

      $upItems = $pdo->prepare("
        UPDATE disparos_itens
           SET status='paused'
         WHERE disparo_id=:d
           AND status IN ('pending','queued','retry')
      ");
      try { $upItems->execute([':d'=>$id]); } catch (Throwable $e) { /* ok */ }

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

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

      // Verificar conexão antes de retomar
      $stUser = $pdo->prepare("SELECT instance_name, state, url_api FROM users WHERE email=:e LIMIT 1");
      $stUser->execute([':e'=>$_SESSION['user']['email']]);
      $userConn = $stUser->fetch(PDO::FETCH_ASSOC);
      
      if (!$userConn || empty($userConn['instance_name'])) {
        jexit([
          'ok'=>false,
          'error'=>'connection_missing',
          'message'=>'Você não possui uma conexão WhatsApp configurada. Acesse a aba Conexões para criar uma.'
        ], 409);
      }

      if (strtolower($userConn['state'] ?? '') !== 'open') {
        jexit([
          'ok'=>false,
          'error'=>'connection_not_open',
          'message'=>'Sua conexão WhatsApp não está ativa. Acesse a aba Conexões para reconectar escaneando o QR Code.',
          'current_state'=>$userConn['state']
        ], 409);
      }

      // Carrega campanha p/ consultar schedule
      $stCamp = $pdo->prepare("SELECT id, user_id, status, schedule::text AS schedule_text FROM disparos WHERE id=:id AND user_id=:u LIMIT 1");
      $stCamp->execute([':id'=>$id, ':u'=>$userId]);
      $rowCamp = $stCamp->fetch(PDO::FETCH_ASSOC);
      if (!$rowCamp) jexit(['ok'=>false,'error'=>'Campanha não encontrada'], 404);

      $schedule = json_decode($rowCamp['schedule_text'] ?? 'null', true) ?: null;

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

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

          jexit([
            'ok'=>true,
            'scheduled'=>true,
            'status'=>'paused',
            'auto_paused'=>true,
            'reason'=>'fora_da_janela_ou_bloqueado',
            'message'=>'Campanha continuará pausada até a próxima janela.'
          ]);
        }
      }

      // Dentro da janela → retoma normal
      $pdo->beginTransaction();

      $u = $pdo->prepare("
        UPDATE disparos
           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);
      }

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

      $pdo->commit();

      // Reenvia o webhook completo
      $bundle  = loadCampaignWithUser($pdo, $id, $userId);
      $payload = buildCampaignPayload($bundle);
      $webhookResult = sendCampaignWebhook($bundle['webhookUrl'], $payload);

      jexit([
        'ok'=>true,
        'webhook'=>[
          'configured'=>(bool)$bundle['webhookUrl'],
          'ok'        =>$webhookResult['ok'] ?? null,
          'status'    =>$webhookResult['status'] ?? null,
          'error'     =>$webhookResult['error'] ?? null,
        ]
      ]);
    }

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

      $pdo->beginTransaction();
      $upIt = $pdo->prepare("
        UPDATE disparos_itens
           SET status='canceled'
         WHERE disparo_id=:d AND status IN ('pending','queued','retry','paused')
      ");
      try { $upIt->execute([':d'=>$id]); } catch (Throwable $e) { /* ok */ }

      $u = $pdo->prepare("
        UPDATE disparos
           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();
      $di = $pdo->prepare("DELETE FROM disparos_itens WHERE disparo_id = :d");
      $di->execute([':d'=>$id]);

      $d = $pdo->prepare("DELETE FROM disparos 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 (ID inválido ou de outro usuário).'], 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(*)                                 AS total_itens
        FROM disparos_itens
        WHERE disparo_id=:d
      ");
      $st->execute([':d'=>$id]);
      $row = $st->fetch(PDO::FETCH_ASSOC) ?: ['enviados'=>0,'erros'=>0,'total_itens'=>0];

      $up = $pdo->prepare("
        UPDATE disparos
           SET total = :tot
         WHERE id=:d AND user_id=:u
      ");
      $up->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);

      $st = $pdo->prepare("
        SELECT
          d.id,
          d.user_id,
          d.nome,
          d.status,
          d.total,
          d.enviados,
          d.erros,
          d.created_at,
          d.min_delay,
          d.max_delay,
          COALESCE(d.ignore_default_message,false) AS ignore_default_message,
          COALESCE(d.ignore_timeout_seconds,0) AS ignore_timeout_seconds,
          d.funil_id,
          d.funil_snapshot::text AS funil_snapshot_text,
          d.schedule::text AS schedule_text
        FROM disparos d
        WHERE d.id=:id AND d.user_id=:u
        LIMIT 1
      ");
      $st->execute([':id'=>$id, ':u'=>$userId]);
      $camp = $st->fetch(PDO::FETCH_ASSOC);
      if (!$camp) jexit(['ok'=>false,'error'=>'Campanha não encontrada'], 404);

      $funilSnapshot = $camp['funil_snapshot_text'] ? (json_decode($camp['funil_snapshot_text'], true) ?: null) : null;
      $schedule      = $camp['schedule_text']       ? (json_decode($camp['schedule_text'], true)       ?: null) : null;

      $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
        FROM disparos_itens
        WHERE disparo_id=:d
      ");
      $stS->execute([':d'=>$id]);
      $stats = $stS->fetch(PDO::FETCH_ASSOC) ?: [
        'total'=>0,'pending'=>0,'queued'=>0,'retry'=>0,'sent'=>0,'error'=>0,'paused'=>0,'canceled'=>0
      ];

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

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

      $sqlLeads = "
        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_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 = $pdo->prepare($sqlLeads);
      $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) ?: [];

      $leadData = array_map(function($r){
        return [
          '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);

      jexit([
        'ok'=>true,
        'campaign'=>[
          'id' => (int)$camp['id'],
          'nome' => $camp['nome'],
          'status' => $camp['status'],
          'created_at'=> $camp['created_at'],
          'total' => (int)$camp['total'],
          'enviados' => (int)$camp['enviados'],
          'erros' => (int)$camp['erros'],
          'min_delay' => isset($camp['min_delay']) ? (int)$camp['min_delay'] : 1,
          'max_delay' => isset($camp['max_delay']) ? (int)$camp['max_delay'] : 1,
          'ignore_default_message' => (bool)$camp['ignore_default_message'],
          'ignore_timeout_seconds' => (int)$camp['ignore_timeout_seconds'],
          'funil_id' => $camp['funil_id'],
          'funil_snapshot'=> $funilSnapshot,
          'schedule' => $schedule,
        ],
        'stats'=>$stats,
        'leads'=>[
          'page'=>$page,
          'limit'=>$limit,
          'total'=>$totalLeads,
          'data'=>$leadData
        ]
      ]);
    }

    default:
      jexit(['ok'=>false,'error'=>'Ação inválida'], 400);
  }
} catch (Throwable $e) {
  jexit(['ok'=>false,'error'=>$e->getMessage()], 500);
}