0) { ob_end_clean(); } ob_start(); session_start(); require_once __DIR__ . '/db.php'; if (empty($_SESSION['admin_id'])) { http_response_code(401); echo json_encode(['ok'=>false, 'error'=>'auth']); exit; } // Helper seguro para prepares function must_prepare(mysqli $conn, string $sql): mysqli_stmt { $st = $conn->prepare($sql); if (!$st) { throw new RuntimeException('prepare_failed: '. $conn->error .' | SQL='. preg_replace('/\s+/', ' ', $sql)); } return $st; } function qcount(mysqli $conn, string $sql): int { $rs = $conn->query($sql); if (!$rs) throw new RuntimeException('query_failed: '. $conn->error .' | SQL='. preg_replace('/\s+/', ' ', $sql)); $row = $rs->fetch_assoc(); return (int)($row['c'] ?? 0); } try { $from = trim($_GET['from'] ?? ''); $to = trim($_GET['to'] ?? ''); $landing_id = (int)($_GET['landing_id'] ?? 0); $want_meta = (int)($_GET['meta'] ?? 0); if ($from === '' || $to === '') { $to = date('Y-m-d'); $from = date('Y-m-d', strtotime($to.' -30 day')); } $from_dt = $from.' 00:00:00'; $to_dt = $to.' 23:59:59'; // --- KPIs $kpis = [ 'landings' => qcount($conn, "SELECT COUNT(*) c FROM landing_pages"), 'variants' => qcount($conn, "SELECT COUNT(*) c FROM landing_variants"), 'blocks' => qcount($conn, "SELECT COUNT(*) c FROM landing_blocks"), 'leads_window' => 0, 'range_label' => date('d M', strtotime($from)).' - '.date('d M', strtotime($to)), 'filtered' => $landing_id > 0 ]; if ($landing_id > 0) { $st = must_prepare($conn, "SELECT COUNT(*) c FROM landing_forms WHERE landing_id=? AND created_at BETWEEN ? AND ?"); $st->bind_param('iss', $landing_id, $from_dt, $to_dt); } else { $st = must_prepare($conn, "SELECT COUNT(*) c FROM landing_forms WHERE created_at BETWEEN ? AND ?"); $st->bind_param('ss', $from_dt, $to_dt); } $st->execute(); $r = $st->get_result()->fetch_assoc(); $kpis['leads_window'] = (int)($r['c'] ?? 0); // --- Top + series $top = []; if ($landing_id > 0) { $st = must_prepare($conn, " SELECT lp.id AS landing_id, lp.titulo, SUM(lvs.event_type='impression') AS imps, SUM(lvs.event_type='conversion') AS conv, ROUND(SUM(lvs.event_type='conversion')/NULLIF(SUM(lvs.event_type='impression'),0)*100,2) AS cr FROM landing_pages lp LEFT JOIN landing_variant_stats lvs ON lvs.landing_id=lp.id AND lvs.created_at BETWEEN ? AND ? WHERE lp.id=? GROUP BY lp.id, lp.titulo "); $st->bind_param('ssi', $from_dt, $to_dt, $landing_id); } else { // --- Top global (landing_id = 0): usar subquery para poder ordenar por 'cr' $st = must_prepare($conn, " SELECT landing_id, titulo, imps, conv, cr FROM ( SELECT lp.id AS landing_id, lp.titulo, SUM(lvs.event_type='impression') AS imps, SUM(lvs.event_type='conversion') AS conv, ROUND( SUM(lvs.event_type='conversion') / NULLIF(SUM(lvs.event_type='impression'), 0) * 100, 2 ) AS cr FROM landing_pages lp LEFT JOIN landing_variant_stats lvs ON lvs.landing_id = lp.id AND lvs.created_at BETWEEN ? AND ? GROUP BY lp.id, lp.titulo ) t ORDER BY (cr IS NULL), cr DESC, imps DESC LIMIT 10 "); $st->bind_param('ss', $from_dt, $to_dt); } $st->execute(); $rs = $st->get_result(); while($row = $rs->fetch_assoc()){ $row['imps'] = (int)($row['imps'] ?? 0); $row['conv'] = (int)($row['conv'] ?? 0); $row['cr'] = $row['imps'] ? (float)$row['cr'] : null; // Serie diaria $st2 = must_prepare($conn, " SELECT DATE(created_at) d, SUM(event_type='impression') imp, SUM(event_type='conversion') conv FROM landing_variant_stats WHERE landing_id=? AND created_at BETWEEN ? AND ? GROUP BY DATE(created_at) ORDER BY d ASC "); $lid = (int)$row['landing_id']; $st2->bind_param('iss', $lid, $from_dt, $to_dt); $st2->execute(); $ser = $st2->get_result()->fetch_all(MYSQLI_ASSOC); $row['series'] = array_map(function($p){ return ['d'=>$p['d'], 'imp'=>(int)$p['imp'], 'conv'=>(int)$p['conv']]; }, $ser); $top[] = $row; } // Lista para el select (si meta=1) $landings_list = []; if ($want_meta === 1) { $q = $conn->query("SELECT id, titulo FROM landing_pages ORDER BY titulo ASC"); if (!$q) throw new RuntimeException('query_failed: '. $conn->error .' | SQL=SELECT id,titulo FROM landing_pages ORDER BY titulo ASC'); while($L = $q->fetch_assoc()){ $landings_list[] = ['id'=>(int)$L['id'], 'titulo'=>$L['titulo']]; } } $warnings = $php_warnings; ob_end_clean(); echo json_encode([ 'ok'=>true, 'kpis'=>$kpis, 'top'=>$top, 'landings_list'=>$landings_list, 'warnings'=>$warnings ], JSON_UNESCAPED_UNICODE); } catch (Throwable $e) { ob_end_clean(); http_response_code(500); echo json_encode(['ok'=>false, 'error'=>$e->getMessage()], JSON_UNESCAPED_UNICODE); }