/**
 * Application Use Case: GetSponsorSponsorshipsUseCase
 *
 * Returns detailed sponsorship information for a sponsor's campaigns/sponsorships page.
 */

import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
import type { ISponsorRepository } from '../../domain/repositories/ISponsorRepository';
import type { SeasonSponsorship } from '../../domain/entities/season/SeasonSponsorship';
import type { League } from '../../domain/entities/League';
import type { Season } from '../../domain/entities/season/Season';
import type { Sponsor } from '../../domain/entities/sponsor/Sponsor';
import { Money } from '../../domain/value-objects/Money';

export type GetSponsorSponsorshipsInput = {
  sponsorId: string;
};

export type SponsorshipMetrics = {
  drivers: number;
  races: number;
  completedRaces: number;
  impressions: number;
};

export type SponsorshipFinancials = {
  pricing: Money;
  platformFee: Money;
  netAmount: Money;
};

export type SponsorSponsorshipSummary = {
  sponsorship: SeasonSponsorship;
  league: League;
  season: Season;
  metrics: SponsorshipMetrics;
  financials: SponsorshipFinancials;
};

export type GetSponsorSponsorshipsResultSummary = {
  totalSponsorships: number;
  activeSponsorships: number;
  totalInvestment: Money;
  totalPlatformFees: Money;
};

export type GetSponsorSponsorshipsResult = {
  sponsor: Sponsor;
  sponsorships: SponsorSponsorshipSummary[];
  summary: GetSponsorSponsorshipsResultSummary;
};

export type GetSponsorSponsorshipsErrorCode = 'SPONSOR_NOT_FOUND' | 'REPOSITORY_ERROR';

export class GetSponsorSponsorshipsUseCase {
  constructor(
    private readonly sponsorRepository: ISponsorRepository,
    private readonly seasonSponsorshipRepository: ISeasonSponsorshipRepository,
    private readonly seasonRepository: ISeasonRepository,
    private readonly leagueRepository: ILeagueRepository,
    private readonly leagueMembershipRepository: ILeagueMembershipRepository,
    private readonly raceRepository: IRaceRepository,
    private readonly output: UseCaseOutputPort<GetSponsorSponsorshipsResult>,
  ) {}

  async execute(
    params: GetSponsorSponsorshipsInput,
  ): Promise<Result<void, ApplicationErrorCode<GetSponsorSponsorshipsErrorCode, { message: string }>>> {
    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',
          },
        });
      }

      const sponsorships = await this.seasonSponsorshipRepository.findBySponsorId(sponsorId);

      const sponsorshipSummaries: SponsorSponsorshipSummary[] = [];
      let totalInvestment = Money.create(0, 'USD');
      let totalPlatformFees = Money.create(0, 'USD');

      for (const sponsorship of sponsorships) {
        const season = await this.seasonRepository.findById(sponsorship.seasonId);
        if (!season) continue;

        const league = await this.leagueRepository.findById(season.leagueId);
        if (!league) continue;

        const memberships = await this.leagueMembershipRepository.getLeagueMembers(season.leagueId);
        const driverCount = memberships.length;

        const races = await this.raceRepository.findByLeagueId(season.leagueId);
        const completedRaces = races.filter(r => r.status.isCompleted()).length;

        const impressions = completedRaces * driverCount * 100;

        const platformFeeMoney = sponsorship.getPlatformFee();
        const netAmountMoney = sponsorship.getNetAmount();
        const pricingMoney = Money.create(sponsorship.pricing.amount, sponsorship.pricing.currency);

        totalInvestment = totalInvestment.add(pricingMoney);
        totalPlatformFees = totalPlatformFees.add(platformFeeMoney);

        sponsorshipSummaries.push({
          sponsorship,
          league,
          season,
          metrics: {
            drivers: driverCount,
            races: races.length,
            completedRaces,
            impressions,
          },
          financials: {
            pricing: pricingMoney,
            platformFee: platformFeeMoney,
            netAmount: netAmountMoney,
          },
        });
      }

      const activeSponsorships = sponsorships.filter(s => s.status === 'active').length;

      const result: GetSponsorSponsorshipsResult = {
        sponsor,
        sponsorships: sponsorshipSummaries,
        summary: {
          totalSponsorships: sponsorships.length,
          activeSponsorships,
          totalInvestment,
          totalPlatformFees,
        },
      };

      this.output.present(result);

      return Result.ok(undefined);
    } catch (err) {
      const error = err as { message?: string } | undefined;

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: {
          message: error?.message ?? 'Failed to load sponsor sponsorships',
        },
      });
    }
  }
}
