import { Injectable, Logger } from "@nestjs/common"; import { PrismaService } from "../../database/prisma.service"; import { Sport } from "@prisma/client"; @Injectable() export class LeaguesService { private readonly logger = new Logger(LeaguesService.name); constructor(private readonly prisma: PrismaService) {} /** * Get all countries */ async findAllCountries() { return this.prisma.country.findMany({ orderBy: { name: "asc" }, }); } /** * Get country by ID */ async findCountryById(id: string) { return this.prisma.country.findUnique({ where: { id }, include: { leagues: true }, }); } /** * Get all leagues */ async findAllLeagues(sport?: Sport) { return this.prisma.league.findMany({ where: sport ? { sport } : undefined, include: { country: true }, orderBy: { name: "asc" }, }); } /** * Get league by ID */ async findLeagueById(id: string) { return this.prisma.league.findUnique({ where: { id }, include: { country: true }, }); } /** * Get leagues by country */ async findLeaguesByCountry(countryId: string, sport?: Sport) { return this.prisma.league.findMany({ where: { countryId, ...(sport ? { sport } : {}), }, include: { country: true }, orderBy: { name: "asc" }, }); } /** * Get all teams */ async findAllTeams(sport?: Sport, search?: string) { return this.prisma.team.findMany({ where: { ...(sport ? { sport } : {}), ...(search ? { name: { contains: search, mode: "insensitive" } } : {}), }, orderBy: { name: "asc" }, take: 100, }); } /** * Get team by ID */ async findTeamById(id: string) { return this.prisma.team.findUnique({ where: { id }, }); } /** * Search teams by name */ async searchTeams(name: string, sport?: Sport) { return this.prisma.team.findMany({ where: { name: { contains: name, mode: "insensitive" }, ...(sport ? { sport } : {}), }, take: 20, }); } /** * Get team's matches (past + upcoming) with pagination */ async getTeamRecentMatches( teamId: string, page: number = 1, limit: number = 20, season?: string ) { const skip = (page - 1) * limit; const where: any = { OR: [{ homeTeamId: teamId }, { awayTeamId: teamId }], }; if (season) { // season format expected: "2024-2025" const parts = season.split("-"); if (parts.length === 2) { const startYear = parseInt(parts[0], 10); const endYear = parseInt(parts[1], 10); if (!isNaN(startYear) && !isNaN(endYear)) { // Season starts August 1st of startYear const startDate = new Date(Date.UTC(startYear, 7, 1)).getTime(); // Season ends July 31st of endYear const endDate = new Date(Date.UTC(endYear, 6, 31, 23, 59, 59, 999)).getTime(); where.mstUtc = { gte: startDate, lte: endDate, }; } } } const [data, total] = await this.prisma.$transaction([ this.prisma.match.findMany({ where, include: { homeTeam: true, awayTeam: true, league: { include: { country: true } }, }, orderBy: { mstUtc: "desc" }, skip, take: limit, }), this.prisma.match.count({ where }), ]); return { data: data.map((m) => ({ id: m.id, matchName: m.matchName, matchSlug: m.matchSlug, mstUtc: Number(m.mstUtc), scoreHome: m.scoreHome, scoreAway: m.scoreAway, status: m.status, state: m.state, homeTeamName: m.homeTeam?.name, homeTeamLogo: m.homeTeamId ? `https://file.mackolikfeeds.com/teams/${m.homeTeamId}` : null, awayTeamName: m.awayTeam?.name, awayTeamLogo: m.awayTeamId ? `https://file.mackolikfeeds.com/teams/${m.awayTeamId}` : null, leagueName: m.league?.name, countryName: m.league?.country?.name, })), total, page, limit, totalPages: Math.ceil(total / limit), }; } /** * Get head-to-head matches between two teams */ async getHeadToHead(teamId1: string, teamId2: string, limit: number = 10) { const matches = await this.prisma.match.findMany({ where: { OR: [ { homeTeamId: teamId1, awayTeamId: teamId2 }, { homeTeamId: teamId2, awayTeamId: teamId1 }, ], state: "postGame", // Finished matches are stored as "postGame" }, include: { homeTeam: true, awayTeam: true, league: true, }, orderBy: { mstUtc: "desc" }, take: limit, }); // Calculate statistics let team1Wins = 0; let team2Wins = 0; let draws = 0; matches.forEach((match) => { const homeScore = Number(match.scoreHome ?? -1); const awayScore = Number(match.scoreAway ?? -1); // Skip matches without scores if (homeScore === -1 || awayScore === -1) return; const isTeam1Home = match.homeTeamId === teamId1; if (homeScore === awayScore) { draws++; } else if ( (isTeam1Home && homeScore > awayScore) || (!isTeam1Home && awayScore > homeScore) ) { team1Wins++; } else { team2Wins++; } }); return { matches, team1Wins, team2Wins, draws, }; } }