import { Injectable, Inject } from '@nestjs/common'; import { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO'; import { CreateSponsorOutputDTO } from './dtos/CreateSponsorOutputDTO'; import { GetSponsorDashboardQueryParamsDTO } from './dtos/GetSponsorDashboardQueryParamsDTO'; import { SponsorDashboardDTO } from './dtos/SponsorDashboardDTO'; import { GetSponsorSponsorshipsQueryParamsDTO } from './dtos/GetSponsorSponsorshipsQueryParamsDTO'; import { SponsorSponsorshipsDTO } from './dtos/SponsorSponsorshipsDTO'; import { GetSponsorOutputDTO } from './dtos/GetSponsorOutputDTO'; import { GetPendingSponsorshipRequestsOutputDTO } from './dtos/GetPendingSponsorshipRequestsOutputDTO'; import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshipPricingResultDTO'; import { GetSponsorsOutputDTO } from './dtos/GetSponsorsOutputDTO'; import { AvailableLeagueDTO } from './dtos/AvailableLeagueDTO'; import { LeagueDetailDTO } from './dtos/LeagueDetailDTO'; import { DriverDTO } from './dtos/DriverDTO'; import { RaceDTO } from './dtos/RaceDTO'; import { SponsorProfileDTO } from './dtos/SponsorProfileDTO'; import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO'; import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO'; import { PaymentMethodDTO } from './dtos/PaymentMethodDTO'; import { InvoiceDTO } from './dtos/InvoiceDTO'; import { BillingStatsDTO } from './dtos/BillingStatsDTO'; // Use cases import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase'; import { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase'; import { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateSponsorUseCase'; import { GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase'; import { GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase'; import { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase'; import { GetPendingSponsorshipRequestsUseCase, GetPendingSponsorshipRequestsInput, } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase'; import { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase'; import { RejectSponsorshipRequestUseCase } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase'; import { GetSponsorBillingUseCase } from '@core/payments/application/use-cases/GetSponsorBillingUseCase'; import { GET_SPONSOR_BILLING_USE_CASE_TOKEN } from './SponsorProviders'; import type { SponsorableEntityType } from '@core/racing/domain/entities/SponsorshipRequest'; import type { Logger } from '@core/shared/application'; // Presenters import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter'; import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter'; import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter'; import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter'; import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter'; import { GetSponsorPresenter } from './presenters/GetSponsorPresenter'; import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter'; import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter'; import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter'; import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter'; import { AvailableLeaguesPresenter } from './presenters/AvailableLeaguesPresenter'; import { LeagueDetailPresenter } from './presenters/LeagueDetailPresenter'; import { SponsorSettingsPresenter } from './presenters/SponsorSettingsPresenter'; import { SponsorSettingsUpdatePresenter } from './presenters/SponsorSettingsUpdatePresenter'; import { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter'; import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase'; // Tokens import { GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN, GET_SPONSORS_USE_CASE_TOKEN, CREATE_SPONSOR_USE_CASE_TOKEN, GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN, GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN, GET_SPONSOR_USE_CASE_TOKEN, GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN, ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN, REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN, LOGGER_TOKEN, GET_ENTITY_SPONSORSHIP_PRICING_PRESENTER_TOKEN, GET_SPONSORS_PRESENTER_TOKEN, CREATE_SPONSOR_PRESENTER_TOKEN, GET_SPONSOR_DASHBOARD_PRESENTER_TOKEN, GET_SPONSOR_SPONSORSHIPS_PRESENTER_TOKEN, GET_SPONSOR_PRESENTER_TOKEN, GET_PENDING_SPONSORSHIP_REQUESTS_PRESENTER_TOKEN, ACCEPT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN, REJECT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN, GET_SPONSOR_BILLING_PRESENTER_TOKEN, } from './SponsorProviders'; @Injectable() export class SponsorService { constructor( @Inject(GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN) private readonly getSponsorshipPricingUseCase: GetSponsorshipPricingUseCase, @Inject(GET_SPONSORS_USE_CASE_TOKEN) private readonly getSponsorsUseCase: GetSponsorsUseCase, @Inject(CREATE_SPONSOR_USE_CASE_TOKEN) private readonly createSponsorUseCase: CreateSponsorUseCase, @Inject(GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN) private readonly getSponsorDashboardUseCase: GetSponsorDashboardUseCase, @Inject(GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN) private readonly getSponsorSponsorshipsUseCase: GetSponsorSponsorshipsUseCase, @Inject(GET_SPONSOR_USE_CASE_TOKEN) private readonly getSponsorUseCase: GetSponsorUseCase, @Inject(GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN) private readonly getPendingSponsorshipRequestsUseCase: GetPendingSponsorshipRequestsUseCase, @Inject(ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN) private readonly acceptSponsorshipRequestUseCase: AcceptSponsorshipRequestUseCase, @Inject(REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN) private readonly rejectSponsorshipRequestUseCase: RejectSponsorshipRequestUseCase, @Inject(GET_SPONSOR_BILLING_USE_CASE_TOKEN) private readonly getSponsorBillingUseCase: GetSponsorBillingUseCase, @Inject(LOGGER_TOKEN) private readonly logger: Logger, // Injected presenters @Inject(GET_ENTITY_SPONSORSHIP_PRICING_PRESENTER_TOKEN) private readonly getEntitySponsorshipPricingPresenter: GetEntitySponsorshipPricingPresenter, @Inject(GET_SPONSORS_PRESENTER_TOKEN) private readonly getSponsorsPresenter: GetSponsorsPresenter, @Inject(CREATE_SPONSOR_PRESENTER_TOKEN) private readonly createSponsorPresenter: CreateSponsorPresenter, @Inject(GET_SPONSOR_DASHBOARD_PRESENTER_TOKEN) private readonly getSponsorDashboardPresenter: GetSponsorDashboardPresenter, @Inject(GET_SPONSOR_SPONSORSHIPS_PRESENTER_TOKEN) private readonly getSponsorSponsorshipsPresenter: GetSponsorSponsorshipsPresenter, @Inject(GET_SPONSOR_PRESENTER_TOKEN) private readonly getSponsorPresenter: GetSponsorPresenter, @Inject(GET_PENDING_SPONSORSHIP_REQUESTS_PRESENTER_TOKEN) private readonly getPendingSponsorshipRequestsPresenter: GetPendingSponsorshipRequestsPresenter, @Inject(ACCEPT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN) private readonly acceptSponsorshipRequestPresenter: AcceptSponsorshipRequestPresenter, @Inject(REJECT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN) private readonly rejectSponsorshipRequestPresenter: RejectSponsorshipRequestPresenter, @Inject(GET_SPONSOR_BILLING_PRESENTER_TOKEN) private readonly sponsorBillingPresenter: SponsorBillingPresenter, ) {} async getEntitySponsorshipPricing(): Promise { this.logger.debug('[SponsorService] Fetching sponsorship pricing.'); await this.getSponsorshipPricingUseCase.execute({}); return this.getEntitySponsorshipPricingPresenter.viewModel; } async getSponsors(): Promise { this.logger.debug('[SponsorService] Fetching sponsors.'); await this.getSponsorsUseCase.execute(); return this.getSponsorsPresenter.responseModel; } async createSponsor(input: CreateSponsorInputDTO): Promise { this.logger.debug('[SponsorService] Creating sponsor.', { input }); await this.createSponsorUseCase.execute(input); return this.createSponsorPresenter.viewModel; } async getSponsorDashboard( params: GetSponsorDashboardQueryParamsDTO, ): Promise { this.logger.debug('[SponsorService] Fetching sponsor dashboard.', { params }); await this.getSponsorDashboardUseCase.execute(params); const result = this.getSponsorDashboardPresenter.viewModel; if (!result) { throw new Error('Sponsor dashboard not found'); } return result; } async getSponsorSponsorships( params: GetSponsorSponsorshipsQueryParamsDTO, ): Promise { this.logger.debug('[SponsorService] Fetching sponsor sponsorships.', { params }); await this.getSponsorSponsorshipsUseCase.execute(params); const result = this.getSponsorSponsorshipsPresenter.viewModel; if (!result) { throw new Error('Sponsor sponsorships not found'); } return result; } async getSponsor(sponsorId: string): Promise { this.logger.debug('[SponsorService] Fetching sponsor.', { sponsorId }); await this.getSponsorUseCase.execute({ sponsorId }); const result = this.getSponsorPresenter.viewModel; if (!result) { throw new Error('Sponsor not found'); } return result; } async getPendingSponsorshipRequests(params: { entityType: SponsorableEntityType; entityId: string; }): Promise { this.logger.debug('[SponsorService] Fetching pending sponsorship requests.', { params }); await this.getPendingSponsorshipRequestsUseCase.execute( params as GetPendingSponsorshipRequestsInput, ); const result = this.getPendingSponsorshipRequestsPresenter.viewModel; if (!result) { throw new Error('Pending sponsorship requests not found'); } return result; } async acceptSponsorshipRequest( requestId: string, respondedBy: string, ): Promise { this.logger.debug('[SponsorService] Accepting sponsorship request.', { requestId, respondedBy, }); await this.acceptSponsorshipRequestUseCase.execute({ requestId, respondedBy, }); const result = this.acceptSponsorshipRequestPresenter.viewModel; if (!result) { throw new Error('Accept sponsorship request failed'); } return result; } async rejectSponsorshipRequest( requestId: string, respondedBy: string, reason?: string, ): Promise { this.logger.debug('[SponsorService] Rejecting sponsorship request.', { requestId, respondedBy, reason, }); const input: { requestId: string; respondedBy: string; reason?: string } = { requestId, respondedBy, }; if (reason !== undefined) { input.reason = reason; } await this.rejectSponsorshipRequestUseCase.execute(input); const result = this.rejectSponsorshipRequestPresenter.viewModel; if (!result) { throw new Error('Reject sponsorship request failed'); } return result; } async getSponsorBilling(sponsorId: string): Promise<{ paymentMethods: PaymentMethodDTO[]; invoices: InvoiceDTO[]; stats: BillingStatsDTO; }> { this.logger.debug('[SponsorService] Fetching sponsor billing.', { sponsorId }); await this.getSponsorBillingUseCase.execute({ sponsorId }); const result = this.sponsorBillingPresenter.viewModel; if (!result) { throw new Error('Sponsor billing not found'); } return result; } async getAvailableLeagues(): Promise { this.logger.debug('[SponsorService] Fetching available leagues.'); const presenter = new AvailableLeaguesPresenter(); const leagues: AvailableLeagueDTO[] = [ { id: 'league-1', name: 'GT3 Masters Championship', game: 'iRacing', drivers: 48, avgViewsPerRace: 8200, mainSponsorSlot: { available: true, price: 1200 }, secondarySlots: { available: 1, total: 2, price: 400 }, rating: 4.8, tier: 'premium', nextRace: '2025-12-20', seasonStatus: 'active', description: 'Premier GT3 racing with top-tier drivers. Weekly broadcasts and active community.', }, { id: 'league-2', name: 'Endurance Pro Series', game: 'ACC', drivers: 72, avgViewsPerRace: 12500, mainSponsorSlot: { available: false, price: 1500 }, secondarySlots: { available: 2, total: 2, price: 500 }, rating: 4.9, tier: 'premium', nextRace: '2026-01-05', seasonStatus: 'active', description: 'Multi-class endurance racing. High engagement from dedicated endurance fans.', }, ]; presenter.present(leagues); return presenter; } async getLeagueDetail(leagueId: string): Promise { this.logger.debug('[SponsorService] Fetching league detail.', { leagueId }); const presenter = new LeagueDetailPresenter(); // Mock data const league: LeagueDetailDTO = { id: leagueId, name: 'GT3 Masters Championship', game: 'iRacing', tier: 'premium', season: 'Season 3', description: "Premier GT3 racing with top-tier drivers competing across the world's most iconic circuits.", drivers: 48, races: 12, completedRaces: 8, totalImpressions: 45200, avgViewsPerRace: 5650, engagement: 4.2, rating: 4.8, seasonStatus: 'active', seasonDates: { start: '2025-10-01', end: '2026-02-28' }, nextRace: { name: 'Spa-Francorchamps', date: '2025-12-20' }, sponsorSlots: { main: { available: true, price: 1200, benefits: [ 'Primary logo placement on all liveries', 'League page header banner', 'Race results page branding', 'Social media feature posts', 'Newsletter sponsor spot', ], }, secondary: { available: 1, total: 2, price: 400, benefits: [ 'Secondary logo on liveries', 'League page sidebar placement', 'Race results mention', 'Social media mentions', ], }, }, }; const drivers: DriverDTO[] = [ { id: 'd1', name: 'Max Verstappen', country: 'NL', position: 1, races: 8, impressions: 4200, team: 'Red Bull Racing', }, { id: 'd2', name: 'Lewis Hamilton', country: 'GB', position: 2, races: 8, impressions: 3980, team: 'Mercedes AMG', }, ]; const races: RaceDTO[] = [ { id: 'r1', name: 'Spa-Francorchamps', date: '2025-12-20', views: 0, status: 'upcoming', }, { id: 'r2', name: 'Monza', date: '2025-12-08', views: 5800, status: 'completed', }, ]; presenter.present({ league, drivers, races }); return presenter; } async getSponsorSettings(sponsorId: string): Promise { this.logger.debug('[SponsorService] Fetching sponsor settings.', { sponsorId }); const presenter = new SponsorSettingsPresenter(); // Mock data const profile: SponsorProfileDTO = { companyName: 'Acme Racing Co.', contactName: 'John Smith', contactEmail: 'sponsor@acme-racing.com', contactPhone: '+1 (555) 123-4567', website: 'https://acme-racing.com', description: 'Premium sim racing equipment and accessories for competitive drivers.', logoUrl: '', industry: 'Racing Equipment', address: { street: '123 Racing Boulevard', city: 'Indianapolis', country: 'United States', postalCode: '46222', }, taxId: 'US12-3456789', socialLinks: { twitter: '@acmeracing', linkedin: 'acme-racing-co', instagram: '@acmeracing', }, }; const notifications: NotificationSettingsDTO = { emailNewSponsorships: true, emailWeeklyReport: true, emailRaceAlerts: false, emailPaymentAlerts: true, emailNewOpportunities: true, emailContractExpiry: true, }; const privacy: PrivacySettingsDTO = { publicProfile: true, showStats: false, showActiveSponsorships: true, allowDirectContact: true, }; presenter.present({ profile, notifications, privacy }); return presenter; } async updateSponsorSettings( sponsorId: string, input: { profile?: Partial; notifications?: Partial; privacy?: Partial; }, ): Promise { this.logger.debug('[SponsorService] Updating sponsor settings.', { sponsorId, input }); // Mock implementation - in real app, this would persist to database this.logger.info('[SponsorService] Settings updated successfully.', { sponsorId }); const presenter = new SponsorSettingsUpdatePresenter(); presenter.present({ success: true }); return presenter; } }