import { Driver } from '@core/racing/domain/entities/Driver'; import { League } from '@core/racing/domain/entities/League'; import { Team } from '@core/racing/domain/entities/Team'; import type { TeamJoinRequest, TeamMembership } from '@core/racing/domain/types/TeamMembership'; import { faker } from '@faker-js/faker'; import { seedId } from './SeedIdHelper'; export class RacingTeamFactory { constructor( private readonly baseDate: Date, private readonly persistence: 'postgres' | 'inmemory' = 'inmemory', ) {} createTeams(drivers: Driver[], leagues: League[]): Team[] { const teamCount = 15; return Array.from({ length: teamCount }, (_, idx) => { const i = idx + 1; const owner = faker.helpers.arrayElement(drivers); const teamLeagues = faker.helpers.arrayElements( leagues.map((l) => l.id.toString()), { min: 0, max: 3 }, ); return Team.create({ id: seedId(`team-${i}`, this.persistence), name: faker.company.name() + ' Racing', tag: faker.string.alpha({ length: 4, casing: 'upper' }), description: faker.lorem.sentences(2), ownerId: owner.id, leagues: teamLeagues, createdAt: faker.date.past({ years: 2, refDate: this.baseDate }), }); }); } createTeamMemberships(drivers: Driver[], teams: Team[]): TeamMembership[] { const memberships: TeamMembership[] = []; const usedDrivers = new Set(); teams.forEach((team, teamIndex) => { const availableDrivers = drivers.filter(d => !usedDrivers.has(d.id.toString()) && d.id.toString() !== team.ownerId.toString()); // Create varied team compositions let memberCount: number; let hasManager: boolean; if (teamIndex % 5 === 0) { // Solo teams (just owner) memberCount = 0; hasManager = false; } else if (teamIndex % 5 === 1) { // Small teams (2-3 members) memberCount = faker.number.int({ min: 1, max: 2 }); hasManager = faker.datatype.boolean(); } else if (teamIndex % 5 === 2) { // Medium teams (3-5 members) memberCount = faker.number.int({ min: 2, max: 4 }); hasManager = true; } else if (teamIndex % 5 === 3) { // Large teams (5-7 members) memberCount = faker.number.int({ min: 4, max: 6 }); hasManager = true; } else { // Mixed - sometimes with manager, sometimes without memberCount = faker.number.int({ min: 1, max: 5 }); hasManager = faker.datatype.boolean(); } const members = faker.helpers.arrayElements(availableDrivers, memberCount); // Add owner memberships.push({ teamId: team.id.toString(), driverId: team.ownerId.toString(), role: 'owner', status: 'active', joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }), }); usedDrivers.add(team.ownerId.toString()); // Add manager if needed if (hasManager && members.length > 0) { const managerIndex = faker.number.int({ min: 0, max: members.length - 1 }); const manager = members[managerIndex]!; memberships.push({ teamId: team.id.toString(), driverId: manager.id.toString(), role: 'manager', status: 'active', joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }), }); usedDrivers.add(manager.id.toString()); } // Add remaining members as drivers members.forEach((driver) => { if (!usedDrivers.has(driver.id.toString())) { memberships.push({ teamId: team.id.toString(), driverId: driver.id.toString(), role: 'driver', status: 'active', joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }), }); usedDrivers.add(driver.id.toString()); } }); }); return memberships; } createTeamJoinRequests( drivers: Driver[], teams: Team[], teamMemberships: TeamMembership[], ): TeamJoinRequest[] { const membershipIds = new Set(teamMemberships.map(m => `${m.teamId}:${m.driverId}`)); const requests: TeamJoinRequest[] = []; const addRequest = (request: TeamJoinRequest): void => { requests.push(request); }; const team1 = teams[0]; if (team1) { const candidateDriverIds = drivers .map(d => d.id.toString()) .filter(driverId => !membershipIds.has(`${team1.id.toString()}:${driverId}`)) .slice(0, 8); candidateDriverIds.forEach((driverId, idx) => { addRequest({ id: seedId(`team-join-${team1.id.toString()}-${driverId}`, this.persistence), teamId: team1.id.toString(), driverId, requestedAt: this.addDays(this.baseDate, -(5 + idx)), ...(idx % 3 === 0 ? { message: 'Can I join as a substitute driver for endurance events?' } : idx % 3 === 2 ? { message: '' } : {}), }); }); // Conflict edge case: owner submits a join request to own team. addRequest({ id: seedId(`team-join-${team1.id.toString()}-${team1.ownerId.toString()}-conflict`, this.persistence), teamId: team1.id.toString(), driverId: team1.ownerId.toString(), requestedAt: this.addDays(this.baseDate, -1), message: 'Testing edge case: owner submitted join request.', }); } const team3 = teams[2]; if (team3 && drivers[0]) { const driverId = drivers[0].id.toString(); addRequest({ id: seedId('dup-team-join-req-1', this.persistence), teamId: team3.id.toString(), driverId, requestedAt: this.addDays(this.baseDate, -10), message: 'First request message (will be overwritten).', }); addRequest({ id: seedId('dup-team-join-req-1', this.persistence), teamId: team3.id.toString(), driverId, requestedAt: this.addDays(this.baseDate, -9), message: 'Updated request message (duplicate id).', }); } return requests; } private addDays(date: Date, days: number): Date { return new Date(date.getTime() + days * 24 * 60 * 60 * 1000); } }