Files
gridpilot.gg/core/racing/application/use-cases/GetLeagueOwnerSummaryUseCase.ts
2026-01-16 19:46:49 +01:00

120 lines
4.6 KiB
TypeScript

import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Driver } from '../../domain/entities/Driver';
import type { League } from '../../domain/entities/League';
import type { DriverRepository } from '../../domain/repositories/DriverRepository';
import type { LeagueMembershipRepository } from '../../domain/repositories/LeagueMembershipRepository';
import type { LeagueRepository } from '../../domain/repositories/LeagueRepository';
import type { StandingRepository } from '../../domain/repositories/StandingRepository';
export interface GetLeagueOwnerSummaryInput {
leagueId: string;
}
export type GetLeagueOwnerSummaryErrorCode = 'LEAGUE_NOT_FOUND' | 'OWNER_NOT_FOUND' | 'REPOSITORY_ERROR';
export interface GetLeagueOwnerSummaryResult {
league: League;
owner: Driver;
totalMembers: number;
activeMembers: number;
rating: number | null;
rank: number | null;
}
export class GetLeagueOwnerSummaryUseCase {
constructor(
private readonly leagueRepository: LeagueRepository,
private readonly driverRepository: DriverRepository,
private readonly leagueMembershipRepository: LeagueMembershipRepository,
private readonly standingRepository: StandingRepository,
) {}
async execute(
input: GetLeagueOwnerSummaryInput,
): Promise<Result<GetLeagueOwnerSummaryResult, ApplicationErrorCode<GetLeagueOwnerSummaryErrorCode, { message: string }>>> {
try {
const league = await this.leagueRepository.findById(input.leagueId);
if (!league) {
return Result.err({
code: 'LEAGUE_NOT_FOUND',
details: { message: 'League not found' },
});
}
const owner = await this.driverRepository.findById(league.ownerId.toString());
if (!owner) {
return Result.err({
code: 'OWNER_NOT_FOUND',
details: { message: 'League owner not found' },
});
}
const members = await this.leagueMembershipRepository.getLeagueMembers(input.leagueId);
const totalMembers = members.length;
const activeMembers = members.filter(m => m.status.toString() === 'active').length;
// Calculate rating and rank for the owner
let rating: number | null = null;
let rank: number | null = null;
try {
// Get standing for the owner in this league
const ownerStanding = await this.standingRepository.findByDriverIdAndLeagueId(owner.id.toString(), league.id.toString());
if (ownerStanding) {
// Calculate rating from standing
const baseRating = 1000;
const pointsBonus = ownerStanding.points.toNumber() * 2;
const positionBonus = Math.max(0, 50 - (ownerStanding.position.toNumber() * 2));
const winBonus = ownerStanding.wins * 100;
rating = Math.round(baseRating + pointsBonus + positionBonus + winBonus);
// Calculate rank among all drivers in this league
const leagueStandings = await this.standingRepository.findByLeagueId(league.id.toString());
const driverStats = new Map<string, { rating: number }>();
for (const standing of leagueStandings) {
const driverId = standing.driverId.toString();
const standingBaseRating = 1000;
const standingPointsBonus = standing.points.toNumber() * 2;
const standingPositionBonus = Math.max(0, 50 - (standing.position.toNumber() * 2));
const standingWinBonus = standing.wins * 100;
const standingRating = Math.round(standingBaseRating + standingPointsBonus + standingPositionBonus + standingWinBonus);
driverStats.set(driverId, { rating: standingRating });
}
const rankings = Array.from(driverStats.entries())
.sort(([, a], [, b]) => b.rating - a.rating)
.map(([driverId], index) => ({ driverId, rank: index + 1 }));
const ownerRanking = rankings.find(r => r.driverId === owner.id.toString());
rank = ownerRanking ? ownerRanking.rank : null;
}
} catch (error) {
// If rating calculation fails, continue with null values
console.error('Failed to calculate rating/rank:', error);
}
return Result.ok({
league,
owner,
totalMembers,
activeMembers,
rating,
rank,
});
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Failed to get league owner summary';
return Result.err({
code: 'REPOSITORY_ERROR',
details: { message },
});
}
}
}