false, 'error' => 'Unauthorized']); exit; } $pdo = og_session_get_pdo(); if (!$pdo) { ob_clean(); echo json_encode(['success' => false, 'error' => 'DB unavailable']); exit; } // ── Auto-create match_results if missing ───────────────────────────────────── try { $pdo->exec("CREATE TABLE IF NOT EXISTS match_results ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, match_key VARCHAR(100) NOT NULL DEFAULT '', match_id BIGINT UNSIGNED NULL, discipline VARCHAR(50) NOT NULL DEFAULT '', mode VARCHAR(50) NOT NULL DEFAULT '1v1', winner_user_id BIGINT UNSIGNED NOT NULL DEFAULT 0, loser_user_id BIGINT UNSIGNED NOT NULL DEFAULT 0, winner_username VARCHAR(100) NOT NULL DEFAULT '', loser_username VARCHAR(100) NOT NULL DEFAULT '', score VARCHAR(200) NOT NULL DEFAULT '', sets_winner TINYINT NOT NULL DEFAULT 0, sets_loser TINYINT NOT NULL DEFAULT 0, reason VARCHAR(50) NOT NULL DEFAULT '', ended_at DATETIME NULL, payload_json LONGTEXT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uniq_match_key (discipline, mode, match_key), INDEX idx_winner (winner_user_id), INDEX idx_loser (loser_user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch (Exception $e) { // table may already exist with different schema -- ignore } // ── Check which optional columns exist in matches ──────────────────────────── function matchesHasColumn(PDO $pdo, string $col): bool { static $cache = []; if (!isset($cache[$col])) { $cache[$col] = (int)$pdo->query( "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'matches' AND column_name = " . $pdo->quote($col) )->fetchColumn() > 0; } return $cache[$col]; } // ── Helper: fetch matches by status with usernames ──────────────────────────── function fetchMatchesByStatus(PDO $pdo, string $status): array { $disciplineExpr = matchesHasColumn($pdo, 'Discipline') ? "COALESCE(m.Discipline, 'ping-pong')" : "'ping-pong'"; $sql = "SELECT m.id, {$disciplineExpr} AS discipline, m.Status AS status, COALESCE(m.Score, '0:0') AS score, m.StartTime AS started_at, m.EndTime AS ended_at, m.Team1_ID AS user1_id, m.Team2_ID AS user2_id, COALESCE(u1.username, '') AS user1_username, COALESCE(u2.username, '') AS user2_username FROM matches m LEFT JOIN users u1 ON u1.id = m.Team1_ID LEFT JOIN users u2 ON u2.id = m.Team2_ID WHERE m.Status = :status ORDER BY m.StartTime DESC LIMIT 200"; $stmt = $pdo->prepare($sql); $stmt->execute([':status' => $status]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } // ── Fetch live / planned / ended sessions ──────────────────────────────────── try { $live = fetchMatchesByStatus($pdo, 'live'); $planned = fetchMatchesByStatus($pdo, 'planned'); $ended = fetchMatchesByStatus($pdo, 'end'); } catch (Exception $e) { ob_clean(); echo json_encode(['success' => false, 'error' => 'matches_query: ' . $e->getMessage()]); exit; } // ── Paginated / filtered match_results ─────────────────────────────────────── $page = max(1, (int)($_GET['page'] ?? 1)); $limit = min(100, max(1, (int)($_GET['limit'] ?? 25))); $offset = ($page - 1) * $limit; $allowedSort = ['id','discipline','mode','winner_username','loser_username','score','reason','ended_at','created_at']; $sortBy = in_array($_GET['sortBy'] ?? '', $allowedSort) ? $_GET['sortBy'] : 'ended_at'; $sortOrder = strtoupper($_GET['sortOrder'] ?? 'DESC') === 'ASC' ? 'ASC' : 'DESC'; // Filters $filters = []; $params = []; if (!empty($_GET['user'])) { $like = '%' . $_GET['user'] . '%'; $filters[] = '(r.winner_username LIKE :user1 OR r.loser_username LIKE :user2)'; $params[':user1'] = $like; $params[':user2'] = $like; } if (!empty($_GET['discipline'])) { $filters[] = 'r.discipline = :discipline'; $params[':discipline'] = $_GET['discipline']; } if (!empty($_GET['mode'])) { $filters[] = 'r.mode = :mode'; $params[':mode'] = $_GET['mode']; } if (!empty($_GET['reason'])) { $filters[] = 'r.reason = :reason'; $params[':reason'] = $_GET['reason']; } if (!empty($_GET['date_from'])) { $filters[] = 'r.ended_at >= :date_from'; $params[':date_from'] = $_GET['date_from'] . ' 00:00:00'; } if (!empty($_GET['date_to'])) { $filters[] = 'r.ended_at <= :date_to'; $params[':date_to'] = $_GET['date_to'] . ' 23:59:59'; } $where = $filters ? 'WHERE ' . implode(' AND ', $filters) : ''; $totalRecords = 0; $totalPages = 1; $results = []; try { // Count $countSql = "SELECT COUNT(*) FROM match_results r $where"; $countStmt = $pdo->prepare($countSql); $countStmt->execute($params); $totalRecords = (int)$countStmt->fetchColumn(); $totalPages = $totalRecords > 0 ? (int)ceil($totalRecords / $limit) : 1; // Rows $rowsSql = "SELECT r.id, r.match_id, r.discipline, r.mode, r.winner_user_id, r.winner_username, r.loser_user_id, r.loser_username, r.score, r.sets_winner, r.sets_loser, r.reason, r.ended_at, r.created_at FROM match_results r $where ORDER BY r.`$sortBy` $sortOrder LIMIT :limit OFFSET :offset"; $rowsStmt = $pdo->prepare($rowsSql); foreach ($params as $k => $v) { $rowsStmt->bindValue($k, $v); } $rowsStmt->bindValue(':limit', $limit, PDO::PARAM_INT); $rowsStmt->bindValue(':offset', $offset, PDO::PARAM_INT); $rowsStmt->execute(); $results = $rowsStmt->fetchAll(PDO::FETCH_ASSOC); } catch (Exception $e) { ob_clean(); echo json_encode(['success' => false, 'error' => 'results_query: ' . $e->getMessage()]); exit; } ob_clean(); echo json_encode([ 'success' => true, 'live' => $live, 'planned' => $planned, 'ended_sessions' => $ended, 'results' => $results, 'pagination' => [ 'currentPage' => $page, 'totalPages' => $totalPages, 'totalRecords' => $totalRecords, 'recordsPerPage' => $limit, 'hasNextPage' => $page < $totalPages, 'hasPreviousPage' => $page > 1, ], ], JSON_UNESCAPED_UNICODE);