/** * Value Object: SponsorshipPricing * * Represents the sponsorship slot configuration and pricing for any sponsorable entity. * Used by drivers, teams, races, and leagues to define their sponsorship offerings. */ import { Money } from './Money'; import type { IValueObject } from '@core/shared/domain'; export interface SponsorshipSlotConfig { tier: 'main' | 'secondary'; price: Money; benefits: string[]; available: boolean; maxSlots: number; // How many sponsors of this tier can exist (1 for main, 2 for secondary typically) } export interface SponsorshipPricingProps { mainSlot?: SponsorshipSlotConfig | undefined; secondarySlots?: SponsorshipSlotConfig | undefined; acceptingApplications: boolean; customRequirements?: string | undefined; } export class SponsorshipPricing implements IValueObject { readonly mainSlot: SponsorshipSlotConfig | undefined; readonly secondarySlots: SponsorshipSlotConfig | undefined; readonly acceptingApplications: boolean; readonly customRequirements: string | undefined; private constructor(props: SponsorshipPricingProps) { this.mainSlot = props.mainSlot; this.secondarySlots = props.secondarySlots; this.acceptingApplications = props.acceptingApplications; this.customRequirements = props.customRequirements; } get props(): SponsorshipPricingProps { return { mainSlot: this.mainSlot, secondarySlots: this.secondarySlots, acceptingApplications: this.acceptingApplications, customRequirements: this.customRequirements, }; } equals(other: IValueObject): boolean { const a = this.props; const b = other.props; const mainEqual = (a.mainSlot === undefined && b.mainSlot === undefined) || (a.mainSlot !== undefined && b.mainSlot !== undefined && a.mainSlot.tier === b.mainSlot.tier && a.mainSlot.price.amount === b.mainSlot.price.amount && a.mainSlot.price.currency === b.mainSlot.price.currency && a.mainSlot.available === b.mainSlot.available && a.mainSlot.maxSlots === b.mainSlot.maxSlots && a.mainSlot.benefits.length === b.mainSlot.benefits.length && a.mainSlot.benefits.every((val, idx) => val === b.mainSlot!.benefits[idx])); const secondaryEqual = (a.secondarySlots === undefined && b.secondarySlots === undefined) || (a.secondarySlots !== undefined && b.secondarySlots !== undefined && a.secondarySlots.tier === b.secondarySlots.tier && a.secondarySlots.price.amount === b.secondarySlots.price.amount && a.secondarySlots.price.currency === b.secondarySlots.price.currency && a.secondarySlots.available === b.secondarySlots.available && a.secondarySlots.maxSlots === b.secondarySlots.maxSlots && a.secondarySlots.benefits.length === b.secondarySlots.benefits.length && a.secondarySlots.benefits.every( (val, idx) => val === b.secondarySlots!.benefits[idx], )); return ( mainEqual && secondaryEqual && a.acceptingApplications === b.acceptingApplications && a.customRequirements === b.customRequirements ); } static create(props: Partial = {}): SponsorshipPricing { return new SponsorshipPricing({ ...(props.mainSlot !== undefined ? { mainSlot: props.mainSlot } : {}), ...(props.secondarySlots !== undefined ? { secondarySlots: props.secondarySlots } : {}), acceptingApplications: props.acceptingApplications ?? true, ...(props.customRequirements !== undefined ? { customRequirements: props.customRequirements } : {}), }); } /** * Check if a specific tier is available */ isSlotAvailable(tier: 'main' | 'secondary'): boolean { if (tier === 'main') { return !!this.mainSlot?.available; } return !!this.secondarySlots?.available; } /** * Get price for a specific tier */ getPrice(tier: 'main' | 'secondary'): Money | null { if (tier === 'main') { return this.mainSlot?.price ?? null; } return this.secondarySlots?.price ?? null; } /** * Get benefits for a specific tier */ getBenefits(tier: 'main' | 'secondary'): string[] { if (tier === 'main') { return this.mainSlot?.benefits ?? []; } return this.secondarySlots?.benefits ?? []; } /** * Update main slot pricing */ updateMainSlot(config: Partial): SponsorshipPricing { const currentMain = this.mainSlot ?? { tier: 'main' as const, price: Money.create(0, 'USD'), benefits: [], available: true, maxSlots: 1, }; const base = this.props; return new SponsorshipPricing({ ...base, mainSlot: { ...currentMain, ...config, tier: 'main', }, }); } /** * Update secondary slot pricing */ updateSecondarySlot(config: Partial): SponsorshipPricing { const currentSecondary = this.secondarySlots ?? { tier: 'secondary' as const, price: Money.create(0, 'USD'), benefits: [], available: true, maxSlots: 2, }; const base = this.props; return new SponsorshipPricing({ ...base, secondarySlots: { ...currentSecondary, ...config, tier: 'secondary', }, }); } /** * Enable/disable accepting applications */ setAcceptingApplications(accepting: boolean): SponsorshipPricing { const base = this.props; return new SponsorshipPricing({ ...base, acceptingApplications: accepting, }); } }