false,'error'=>'Server error']); exit; } ob_end_clean(); header('Content-Type: application/json'); if (!isLoggedIn()) { echo json_encode(['success'=>false,'error'=>'Not authenticated']); exit; } $action = $_GET['action'] ?? 'list'; $userId = (int)$_SESSION['user_id']; $isAdmin = !empty($_SESSION['is_admin']); switch ($action) { // ── List broadcasts for this user ───────────────────── case 'list': // Get broadcasts targeting this user $stmt = db()->prepare(" SELECT b.*, u.username AS sender_name, u.alias AS sender_alias, (SELECT COUNT(*) FROM broadcast_replies WHERE broadcast_id=b.id) AS reply_count, (SELECT COUNT(*) FROM broadcast_reads WHERE broadcast_id=b.id AND user_id=?) AS is_read, (SELECT COUNT(*) FROM broadcast_reads WHERE broadcast_id=b.id) AS read_count FROM broadcasts b JOIN users u ON b.admin_id = u.id WHERE b.target = 'all' OR (b.target = 'verified' AND EXISTS(SELECT 1 FROM users WHERE id=? AND email_verified=1 AND is_admin=0)) OR (b.target = 'unverified' AND EXISTS(SELECT 1 FROM users WHERE id=? AND email_verified=0)) OR (b.target = 'admins' AND ?) ORDER BY b.sent_at DESC "); $stmt->execute([$userId, $userId, $userId, $isAdmin ? 1 : 0]); echo json_encode(['success'=>true, 'broadcasts'=>$stmt->fetchAll()]); break; // ── Mark as read ────────────────────────────────────── case 'mark_read': if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; } $d = json_decode(file_get_contents('php://input'), true); $bid= (int)($d['broadcast_id'] ?? 0); if (!$bid) { echo json_encode(['success'=>false]); exit; } db()->prepare("INSERT IGNORE INTO broadcast_reads (broadcast_id,user_id) VALUES (?,?)")->execute([$bid,$userId]); echo json_encode(['success'=>true]); break; // ── Get replies for a broadcast ─────────────────────── case 'replies': $bid = (int)($_GET['broadcast_id'] ?? 0); if (!$bid) { echo json_encode(['success'=>false]); exit; } $stmt = db()->prepare(" SELECT br.*, u.username, u.alias, u.is_admin FROM broadcast_replies br JOIN users u ON br.user_id = u.id WHERE br.broadcast_id = ? ORDER BY br.created_at ASC "); $stmt->execute([$bid]); echo json_encode(['success'=>true,'replies'=>$stmt->fetchAll()]); break; // ── Post a reply ────────────────────────────────────── case 'reply': if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; } $d = json_decode(file_get_contents('php://input'), true); $bid = (int)($d['broadcast_id'] ?? 0); $msg = substr(trim($d['message'] ?? ''), 0, 1000); if (!$bid || !$msg) { echo json_encode(['success'=>false,'error'=>'broadcast_id and message required']); exit; } db()->prepare("INSERT INTO broadcast_replies (broadcast_id,user_id,message) VALUES (?,?,?)")->execute([$bid,$userId,$msg]); db()->prepare("INSERT IGNORE INTO broadcast_reads (broadcast_id,user_id) VALUES (?,?)")->execute([$bid,$userId]); echo json_encode(['success'=>true,'id'=>db()->lastInsertId()]); break; // ── Unread count ────────────────────────────────────── case 'unread_count': $stmt = db()->prepare(" SELECT COUNT(*) FROM broadcasts b WHERE (b.target='all' OR (b.target='verified' AND EXISTS(SELECT 1 FROM users WHERE id=? AND email_verified=1 AND is_admin=0)) OR (b.target='unverified' AND EXISTS(SELECT 1 FROM users WHERE id=? AND email_verified=0)) OR (b.target='admins' AND ?)) AND NOT EXISTS (SELECT 1 FROM broadcast_reads WHERE broadcast_id=b.id AND user_id=?) "); $stmt->execute([$userId,$userId,$isAdmin?1:0,$userId]); echo json_encode(['success'=>true,'count'=>(int)$stmt->fetchColumn()]); break; default: echo json_encode(['success'=>false,'error'=>'Unknown action']); }