Files
iddaai-be/src/modules/leagues/leagues.service.ts
T

234 lines
5.5 KiB
TypeScript
Executable File

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,
};
}
}