/** * Application Use Case: GetSponsorDashboardUseCase * * Returns sponsor dashboard metrics including sponsorships, impressions, and investment data. */ import { Result } from '@core/shared/domain/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { LeagueMembershipRepository } from '../../domain/repositories/LeagueMembershipRepository'; import type { LeagueRepository } from '../../domain/repositories/LeagueRepository'; import type { RaceRepository } from '../../domain/repositories/RaceRepository'; import type { SeasonRepository } from '../../domain/repositories/SeasonRepository'; import type { SeasonSponsorshipRepository } from '../../domain/repositories/SeasonSponsorshipRepository'; import type { SponsorRepository } from '../../domain/repositories/SponsorRepository'; import { Money } from '../../domain/value-objects/Money'; export interface GetSponsorDashboardInput { sponsorId: string; } export interface SponsoredLeagueMetrics { drivers: number; races: number; impressions: number; } export type SponsoredLeagueStatus = 'active' | 'upcoming' | 'completed'; export interface SponsoredLeagueSummary { leagueId: string; leagueName: string; tier: 'main' | 'secondary'; metrics: SponsoredLeagueMetrics; status: SponsoredLeagueStatus; } export interface SponsorDashboardMetrics { impressions: number; impressionsChange: number; uniqueViewers: number; viewersChange: number; races: number; drivers: number; exposure: number; exposureChange: number; } export interface SponsorInvestmentSummary { activeSponsorships: number; totalInvestment: Money; costPerThousandViews: number; } export interface GetSponsorDashboardResult { sponsorId: string; sponsorName: string; metrics: SponsorDashboardMetrics; sponsoredLeagues: SponsoredLeagueSummary[]; investment: SponsorInvestmentSummary; } export type GetSponsorDashboardErrorCode = 'SPONSOR_NOT_FOUND' | 'REPOSITORY_ERROR'; export class GetSponsorDashboardUseCase { constructor( private readonly sponsorRepository: SponsorRepository, private readonly seasonSponsorshipRepository: SeasonSponsorshipRepository, private readonly seasonRepository: SeasonRepository, private readonly leagueRepository: LeagueRepository, private readonly leagueMembershipRepository: LeagueMembershipRepository, private readonly raceRepository: RaceRepository, ) {} async execute( params: GetSponsorDashboardInput, ): Promise>> { try { const { sponsorId } = params; const sponsor = await this.sponsorRepository.findById(sponsorId); if (!sponsor) { return Result.err({ code: 'SPONSOR_NOT_FOUND', details: { message: 'Sponsor not found', }, }); } // Get all sponsorships for this sponsor const sponsorships = await this.seasonSponsorshipRepository.findBySponsorId(sponsorId); // Aggregate data across all sponsorships let totalImpressions = 0; let totalDrivers = 0; let totalRaces = 0; let totalInvestmentMoney = Money.create(0, 'USD'); const sponsoredLeagues: SponsoredLeagueSummary[] = []; const seenLeagues = new Set(); for (const sponsorship of sponsorships) { // Get season to find league const season = await this.seasonRepository.findById(sponsorship.seasonId); if (!season) continue; // Only process each league once if (seenLeagues.has(season.leagueId)) continue; seenLeagues.add(season.leagueId); const league = await this.leagueRepository.findById(season.leagueId); if (!league) continue; // Get membership count for this league const memberships = await this.leagueMembershipRepository.getLeagueMembers(season.leagueId); const driverCount = memberships.length; totalDrivers += driverCount; // Get races for this league const races = await this.raceRepository.findByLeagueId(season.leagueId); const raceCount = races.length; totalRaces += raceCount; // Calculate impressions based on completed races and drivers const completedRaces = races.filter(r => r.status.isCompleted()).length; const leagueImpressions = completedRaces * driverCount * 100; // Simplified: 100 views per driver per race totalImpressions += leagueImpressions; // Determine status based on season dates const now = new Date(); let status: SponsoredLeagueStatus = 'active'; if (season.endDate && season.endDate < now) { status = 'completed'; } else if (season.startDate && season.startDate > now) { status = 'upcoming'; } // Add investment totalInvestmentMoney = totalInvestmentMoney.add( Money.create(sponsorship.pricing.amount, sponsorship.pricing.currency), ); sponsoredLeagues.push({ leagueId: league.id.toString(), leagueName: league.name.toString(), tier: sponsorship.tier, metrics: { drivers: driverCount, races: raceCount, impressions: leagueImpressions, }, status, }); } const activeSponsorships = sponsorships.filter((s) => s.status.toString() === 'active').length; const costPerThousandViews = totalImpressions > 0 ? totalInvestmentMoney.amount / (totalImpressions / 1000) : 0; // Calculate unique viewers (simplified: assume 70% of impressions are unique) const uniqueViewers = Math.round(totalImpressions * 0.7); // Calculate exposure score (0-100 based on tier distribution) const mainSponsorships = sponsorships.filter(s => s.tier === 'main').length; const exposure = sponsorships.length > 0 ? Math.min(100, (mainSponsorships * 30) + (sponsorships.length * 10)) : 0; const result: GetSponsorDashboardResult = { sponsorId, sponsorName: sponsor.name.toString(), metrics: { impressions: totalImpressions, impressionsChange: 0, uniqueViewers, viewersChange: 0, races: totalRaces, drivers: totalDrivers, exposure, exposureChange: 0, }, sponsoredLeagues, investment: { activeSponsorships, totalInvestment: totalInvestmentMoney, costPerThousandViews: Math.round(costPerThousandViews * 100) / 100, }, }; return Result.ok(result); } catch (err) { const error = err as { message?: string } | undefined; return Result.err({ code: 'REPOSITORY_ERROR', details: { message: error?.message ?? 'Failed to fetch sponsor dashboard', }, }); } } }