import { faker } from '@faker-js/faker'; import type { League } from '@core/racing/domain/entities/League'; import { SponsorshipRequest } from '@core/racing/domain/entities/SponsorshipRequest'; import { Season } from '@core/racing/domain/entities/season/Season'; import { SeasonSponsorship } from '@core/racing/domain/entities/season/SeasonSponsorship'; import type { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor'; import { Money } from '@core/racing/domain/value-objects/Money'; export class RacingSeasonSponsorshipFactory { constructor(private readonly baseDate: Date) {} createSeasons(leagues: League[]): Season[] { const seasons: Season[] = []; for (const league of leagues) { const leagueId = league.id.toString(); if (leagueId === 'league-5') { seasons.push( Season.create({ id: 'season-1', leagueId, gameId: 'iracing', name: 'Season 1 (GT Sprint)', year: 2025, order: 1, status: 'active', startDate: this.daysFromBase(-30), }), Season.create({ id: 'season-2', leagueId, gameId: 'iracing', name: 'Season 2 (Endurance Cup)', year: 2024, order: 0, status: 'completed', startDate: this.daysFromBase(-120), endDate: this.daysFromBase(-60), }), Season.create({ id: 'season-3', leagueId, gameId: 'iracing', name: 'Season 3 (Planned)', year: 2025, order: 2, status: 'planned', startDate: this.daysFromBase(14), }), ); continue; } if (leagueId === 'league-3') { seasons.push( Season.create({ id: 'league-3-season-a', leagueId, gameId: 'iracing', name: 'Split Season A', year: 2025, order: 1, status: 'active', startDate: this.daysFromBase(-10), }), Season.create({ id: 'league-3-season-b', leagueId, gameId: 'iracing', name: 'Split Season B', year: 2025, order: 2, status: 'active', startDate: this.daysFromBase(-3), }), ); continue; } const baseYear = this.baseDate.getUTCFullYear(); const seasonCount = leagueId === 'league-2' ? 1 : faker.number.int({ min: 1, max: 3 }); for (let i = 0; i < seasonCount; i++) { const id = `${leagueId}-season-${i + 1}`; const isFirst = i === 0; const status: Season['status'] = leagueId === 'league-1' && isFirst ? 'active' : leagueId === 'league-2' ? 'planned' : isFirst ? faker.helpers.arrayElement(['active', 'planned'] as const) : faker.helpers.arrayElement(['completed', 'archived', 'cancelled'] as const); const startOffset = status === 'active' ? faker.number.int({ min: -60, max: -1 }) : status === 'planned' ? faker.number.int({ min: 7, max: 60 }) : faker.number.int({ min: -200, max: -90 }); const endOffset = status === 'completed' || status === 'archived' || status === 'cancelled' ? faker.number.int({ min: -89, max: -7 }) : undefined; seasons.push( Season.create({ id, leagueId, gameId: 'iracing', name: `${faker.word.adjective()} ${faker.word.noun()} Season`, year: baseYear + faker.number.int({ min: -1, max: 1 }), order: i + 1, status, startDate: this.daysFromBase(startOffset), ...(endOffset !== undefined ? { endDate: this.daysFromBase(endOffset) } : {}), }), ); } } return seasons; } createSeasonSponsorships(seasons: Season[], sponsors: Sponsor[]): SeasonSponsorship[] { const sponsorships: SeasonSponsorship[] = []; const sponsorIds = sponsors.map((s) => s.id.toString()); for (const season of seasons) { const sponsorshipCount = season.id === 'season-1' ? 2 : season.status === 'active' ? faker.number.int({ min: 0, max: 2 }) : faker.number.int({ min: 0, max: 1 }); const usedSponsorIds = new Set(); for (let i = 0; i < sponsorshipCount; i++) { const tier: SeasonSponsorship['tier'] = i === 0 ? 'main' : faker.helpers.arrayElement(['secondary', 'secondary', 'main'] as const); const sponsorIdCandidate = faker.helpers.arrayElement(sponsorIds); const sponsorId = usedSponsorIds.has(sponsorIdCandidate) ? faker.helpers.arrayElement(sponsorIds) : sponsorIdCandidate; usedSponsorIds.add(sponsorId); const base = SeasonSponsorship.create({ id: `season-sponsorship-${season.id}-${i + 1}`, seasonId: season.id, leagueId: season.leagueId, sponsorId, tier, pricing: Money.create( tier === 'main' ? faker.number.int({ min: 900, max: 2500 }) : faker.number.int({ min: 250, max: 900 }), 'USD', ), createdAt: faker.date.recent({ days: 120, refDate: this.baseDate }), description: tier === 'main' ? 'Main sponsor slot' : 'Secondary sponsor slot', ...(season.status === 'active' ? { status: faker.helpers.arrayElement(['active', 'pending'] as const), activatedAt: faker.date.recent({ days: 30, refDate: this.baseDate }), } : season.status === 'completed' || season.status === 'archived' ? { status: faker.helpers.arrayElement(['ended', 'cancelled'] as const), endedAt: faker.date.recent({ days: 200, refDate: this.baseDate }), } : { status: faker.helpers.arrayElement(['pending', 'cancelled'] as const), }), }); sponsorships.push(base); } } return sponsorships; } createSponsorshipRequests(seasons: Season[], sponsors: Sponsor[]): SponsorshipRequest[] { const requests: SponsorshipRequest[] = []; const sponsorIds = sponsors.map((s) => s.id.toString()); for (const season of seasons) { const isHighTrafficDemo = season.id === 'season-1'; const maxRequests = isHighTrafficDemo ? 8 : season.status === 'active' ? faker.number.int({ min: 0, max: 4 }) : faker.number.int({ min: 0, max: 1 }); for (let i = 0; i < maxRequests; i++) { const tier: SponsorshipRequest['tier'] = i === 0 ? 'main' : faker.helpers.arrayElement(['secondary', 'secondary', 'main'] as const); const sponsorId = isHighTrafficDemo && i === 0 ? 'demo-sponsor-1' : faker.helpers.arrayElement(sponsorIds); const offeredAmount = Money.create( tier === 'main' ? faker.number.int({ min: 1000, max: 3500 }) : faker.number.int({ min: 200, max: 1200 }), 'USD', ); const includeMessage = i % 3 !== 0; const message = includeMessage ? faker.helpers.arrayElement([ 'We would love to sponsor this season — high-quality sim racing content fits our brand.', 'We can provide prize pool support + gear giveaways for podium finishers.', 'Interested in the main slot: branding on liveries + broadcast overlays.', 'We want a secondary slot to test engagement before a bigger commitment.', ]) : undefined; // A mix of statuses for edge cases (pending is what the UI lists) const status = season.status === 'active' ? faker.helpers.arrayElement(['pending', 'pending', 'pending', 'rejected', 'withdrawn'] as const) : faker.helpers.arrayElement(['pending', 'rejected'] as const); requests.push( SponsorshipRequest.create({ id: `sponsorship-request-${season.id}-${i + 1}`, sponsorId, entityType: 'season', entityId: season.id, tier, offeredAmount, ...(message !== undefined ? { message } : {}), status, createdAt: faker.date.recent({ days: 60, refDate: this.baseDate }), }), ); } } return requests; } private daysFromBase(days: number): Date { return new Date(this.baseDate.getTime() + days * 24 * 60 * 60 * 1000); } }