false, 'error' => 'Invalid parameters']); exit; } $ticketModel = new TicketModel($conn); $ticket = $ticketModel->getTicketById($ticketId); if (!$ticket || !$ticketModel->canUserAccessTicket($ticket, $currentUser)) { http_response_code(404); echo json_encode(['success' => false, 'error' => 'Ticket not found']); exit; } if ($action === 'watch') { $stmt = $conn->prepare( "INSERT IGNORE INTO ticket_watchers (ticket_id, user_id) VALUES (?, ?)" ); $stmt->bind_param("ii", $ticketId, $userId); $stmt->execute(); $stmt->close(); } else { $stmt = $conn->prepare( "DELETE FROM ticket_watchers WHERE ticket_id = ? AND user_id = ?" ); $stmt->bind_param("ii", $ticketId, $userId); $stmt->execute(); $stmt->close(); } // Return updated state $countStmt = $conn->prepare( "SELECT COUNT(*) as cnt FROM ticket_watchers WHERE ticket_id = ?" ); $countStmt->bind_param("i", $ticketId); $countStmt->execute(); $count = (int)$countStmt->get_result()->fetch_assoc()['cnt']; $countStmt->close(); apiRespond([ 'success' => true, 'watching' => $action === 'watch', 'watcher_count' => $count, ]); } // GET — return current watch state for this user if ($_SERVER['REQUEST_METHOD'] !== 'GET') { http_response_code(405); echo json_encode(['success' => false, 'error' => 'Method not allowed']); exit; } if ($ticketId <= 0) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'ticket_id required']); exit; } $watchingStmt = $conn->prepare( "SELECT COUNT(*) as cnt FROM ticket_watchers WHERE ticket_id = ? AND user_id = ?" ); $watchingStmt->bind_param("ii", $ticketId, $userId); $watchingStmt->execute(); $watching = (bool)$watchingStmt->get_result()->fetch_assoc()['cnt']; $watchingStmt->close(); $countStmt = $conn->prepare( "SELECT COUNT(*) as cnt FROM ticket_watchers WHERE ticket_id = ?" ); $countStmt->bind_param("i", $ticketId); $countStmt->execute(); $count = (int)$countStmt->get_result()->fetch_assoc()['cnt']; $countStmt->close(); echo json_encode([ 'success' => true, 'watching' => $watching, 'watcher_count' => $count, ]);