Files
gridpilot.gg/adapters/bootstrap/racing/RacingRaceFactory.ts
2025-12-30 00:15:35 +01:00

126 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { League } from '@core/racing/domain/entities/League';
import { Race } from '@core/racing/domain/entities/Race';
import { Track } from '@core/racing/domain/entities/Track';
import { seedId } from './SeedIdHelper';
export class RacingRaceFactory {
constructor(
private readonly baseDate: Date,
private readonly persistence: 'postgres' | 'inmemory' = 'inmemory',
) {}
create(leagues: League[], tracks: Track[]): Race[] {
const cars = ['GT3 Porsche 911', 'GT3 BMW M4', 'LMP3 Prototype', 'GT4 Alpine', 'Touring Civic'];
const leagueIds = leagues.map((l) => l.id.toString());
const trackIds = tracks.map((t) => t.id);
const demoLeagueId = 'league-5';
const races: Race[] = [];
// Create races with systematic coverage of different statuses and scenarios
const statuses: Array<'scheduled' | 'running' | 'completed' | 'cancelled'> = ['scheduled', 'running', 'completed', 'cancelled'];
for (let i = 1; i <= 100; i++) {
const leagueId = leagueIds[(i - 1) % leagueIds.length] ?? demoLeagueId;
const trackId = trackIds[(i - 1) % trackIds.length]!;
const track = tracks.find(t => t.id === trackId)!;
// Determine status systematically to ensure coverage
let status: 'scheduled' | 'running' | 'completed' | 'cancelled';
let scheduledAt: Date;
if (i <= 4) {
// First 4 races: one of each status
status = statuses[i - 1]!;
scheduledAt = this.addDays(this.baseDate, i <= 2 ? -35 + i : 1 + (i - 2) * 2);
} else if (i <= 10) {
// Next 6: completed races
status = 'completed';
scheduledAt = this.addDays(this.baseDate, -35 + i);
} else if (i <= 15) {
// Next 5: scheduled future races
status = 'scheduled';
scheduledAt = this.addDays(this.baseDate, 1 + (i - 10) * 3);
} else if (i <= 20) {
// Next 5: cancelled races
status = 'cancelled';
scheduledAt = this.addDays(this.baseDate, -20 + (i - 15));
} else {
// Rest: mix of scheduled and completed
status = i % 3 === 0 ? 'completed' : 'scheduled';
scheduledAt = status === 'completed'
? this.addDays(this.baseDate, -10 + (i - 20))
: this.addDays(this.baseDate, 5 + (i - 20) * 2);
}
const base = {
id: seedId(`race-${i}`, this.persistence),
leagueId,
scheduledAt,
track: track.name.toString(),
trackId: track.id,
car: cars[(i - 1) % cars.length]!,
};
// Special case for running race
if (status === 'running') {
races.push(
Race.create({
...base,
status: 'running',
strengthOfField: 45 + (i % 50), // Valid SOF: 0-100
registeredCount: 12 + (i % 5), // Varying registration counts
maxParticipants: 24, // Ensure max is set
}),
);
continue;
}
// Add varying SOF and registration counts for completed races
if (status === 'completed') {
races.push(
Race.create({
...base,
status: 'completed',
strengthOfField: 35 + (i % 60), // Valid SOF: 0-100
registeredCount: 8 + (i % 8),
maxParticipants: 20, // Ensure max is set
}),
);
continue;
}
// Scheduled races with some having registration data
if (status === 'scheduled') {
const hasRegistrations = i % 4 !== 0; // 75% have registrations
races.push(
Race.create({
...base,
status: 'scheduled',
...(hasRegistrations && {
strengthOfField: 40 + (i % 55), // Valid SOF: 0-100
registeredCount: 5 + (i % 10),
maxParticipants: 16 + (i % 10), // Ensure max is set and reasonable
}),
}),
);
continue;
}
// Cancelled races
races.push(
Race.create({
...base,
status: 'cancelled',
}),
);
}
return races;
}
private addDays(date: Date, days: number): Date {
return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
}
}