import { logger } from "@/lib/logger"; import type { Match, MatchInput } from "@/features/matches/types"; import type PocketBase from "pocketbase"; import { transformMatch } from "../util/transform-types"; export function createMatchesService(pb: PocketBase) { return { async getMatch(id: string): Promise { const result = await pb.collection("matches").getOne(id, { expand: "tournament, home, away, home.players, away.players", }); return transformMatch(result); }, // match Ids where the current lid is home_from_lid or away_from_lid async getChildMatches(matchId: string): Promise<{ winner: Match | undefined, loser: Match | undefined }> { const match = await this.getMatch(matchId); if (!match) throw new Error("Match not found") const result = await pb.collection("matches").getFullList({ filter: `tournament="${match.tournament.id}" && (home_from_lid = ${match.lid} || away_from_lid = ${match.lid}) && bye = false`, expand: "tournament, home, away, home.players, away.players", }); const winnerMatch = result.find(m => (m.home_from_lid === match.lid && !m.home_from_loser) || (m.away_from_lid === match.lid && !m.away_from_loser)); const loserMatch = result.find(m => (m.home_from_lid === match.lid && m.home_from_loser) || (m.away_from_lid === match.lid && m.away_from_loser)); return { winner: winnerMatch ? transformMatch(winnerMatch) : undefined, loser: loserMatch ? transformMatch(loserMatch) : undefined } }, async createMatch(data: MatchInput): Promise { // logger.info("PocketBase | Creating match", data); const result = await pb.collection("matches").create(data); return result; }, async createMatches(matches: MatchInput[]): Promise { logger.info("PocketBase | Creating multiple matches", { count: matches.length, }); const results = await Promise.all( matches.map((match) => pb.collection("matches").create(match)) ); return results; }, async updateMatch(id: string, data: Partial): Promise { logger.info("PocketBase | Updating match", { id, data }); const result = await pb.collection("matches").update(id, data, { expand: 'home, away, tournament, home.players, away.players' }); return transformMatch(result); }, async deleteMatch(id: string): Promise { logger.info("PocketBase | Deleting match", id); await pb.collection("matches").delete(id); }, async deleteMatchesByTournament(tournamentId: string): Promise { logger.info("PocketBase | Deleting matches for tournament", tournamentId); const matches = await pb.collection("matches").getFullList({ filter: `tournament = "${tournamentId}"`, fields: "id", }); await Promise.all( matches.map((match) => pb.collection("matches").delete(match.id)) ); }, async getMatchesBetweenPlayers(player1Id: string, player2Id: string): Promise { logger.info("PocketBase | Getting matches between players", { player1Id, player2Id }); const player1Teams = await pb.collection("teams").getFullList({ filter: `players ~ "${player1Id}"`, fields: "id", }); const player2Teams = await pb.collection("teams").getFullList({ filter: `players ~ "${player2Id}"`, fields: "id", }); const player1TeamIds = player1Teams.map(t => t.id); const player2TeamIds = player2Teams.map(t => t.id); if (player1TeamIds.length === 0 || player2TeamIds.length === 0) { return []; } const allTeamIds = [...new Set([...player1TeamIds, ...player2TeamIds])]; const batchSize = 10; const allMatches: any[] = []; for (let i = 0; i < allTeamIds.length; i += batchSize) { const batch = allTeamIds.slice(i, i + batchSize); const teamFilters = batch.map(id => `home="${id}" || away="${id}"`).join(' || '); const results = await pb.collection("matches").getFullList({ filter: teamFilters, expand: "tournament, home, away, home.players, away.players", sort: "-created", }); allMatches.push(...results); } const uniqueMatches = Array.from( new Map(allMatches.map(m => [m.id, m])).values() ); return uniqueMatches .filter(match => { const homeTeamId = typeof match.home === 'string' ? match.home : match.home?.id; const awayTeamId = typeof match.away === 'string' ? match.away : match.away?.id; const player1InHome = player1TeamIds.includes(homeTeamId); const player1InAway = player1TeamIds.includes(awayTeamId); const player2InHome = player2TeamIds.includes(homeTeamId); const player2InAway = player2TeamIds.includes(awayTeamId); return (player1InHome && player2InAway) || (player1InAway && player2InHome); }) .map(match => transformMatch(match)); }, async getMatchesBetweenTeams(team1Id: string, team2Id: string): Promise { logger.info("PocketBase | Getting matches between teams", { team1Id, team2Id }); const filter = `(home="${team1Id}" && away="${team2Id}") || (home="${team2Id}" && away="${team1Id}")`; const results = await pb.collection("matches").getFullList({ filter, expand: "tournament, home, away, home.players, away.players", sort: "-created", }); return results.map(match => transformMatch(match)); }, async getMatchesByGroup(groupId: string): Promise { logger.info("PocketBase | Getting matches for group", { groupId }); const results = await pb.collection("matches").getFullList({ filter: `group = "${groupId}"`, expand: "tournament, home, away, home.players, away.players", sort: "created", }); return results.map(match => transformMatch(match)); }, }; }