/**
 * Integration Test: Sponsor Leagues Use Case Orchestration
 *
 * Tests the orchestration logic of sponsor leagues-related Use Cases:
 * - GetSponsorSponsorshipsUseCase: Retrieves sponsor's sponsorships/campaigns
 * - Validates that Use Cases correctly interact with their Ports (Repositories)
 * - Uses In-Memory adapters for fast, deterministic testing
 *
 * Focus: Business logic orchestration, NOT UI rendering
 */

import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
import { InMemorySponsorRepository } from '../../../adapters/racing/persistence/inmemory/InMemorySponsorRepository';
import { InMemorySeasonSponsorshipRepository } from '../../../adapters/racing/persistence/inmemory/InMemorySeasonSponsorshipRepository';
import { InMemorySeasonRepository } from '../../../adapters/racing/persistence/inmemory/InMemorySeasonRepository';
import { InMemoryLeagueRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryLeagueRepository';
import { InMemoryLeagueMembershipRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository';
import { InMemoryRaceRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryRaceRepository';
import { GetSponsorSponsorshipsUseCase } from '../../../core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
import { Sponsor } from '../../../core/racing/domain/entities/sponsor/Sponsor';
import { SeasonSponsorship } from '../../../core/racing/domain/entities/season/SeasonSponsorship';
import { Season } from '../../../core/racing/domain/entities/season/Season';
import { League } from '../../../core/racing/domain/entities/League';
import { LeagueMembership } from '../../../core/racing/domain/entities/LeagueMembership';
import { Race } from '../../../core/racing/domain/entities/Race';
import { Money } from '../../../core/racing/domain/value-objects/Money';
import { Logger } from '../../../core/shared/domain/Logger';

describe('Sponsor Leagues Use Case Orchestration', () => {
  let sponsorRepository: InMemorySponsorRepository;
  let seasonSponsorshipRepository: InMemorySeasonSponsorshipRepository;
  let seasonRepository: InMemorySeasonRepository;
  let leagueRepository: InMemoryLeagueRepository;
  let leagueMembershipRepository: InMemoryLeagueMembershipRepository;
  let raceRepository: InMemoryRaceRepository;
  let getSponsorSponsorshipsUseCase: GetSponsorSponsorshipsUseCase;
  let mockLogger: Logger;

  beforeAll(() => {
    mockLogger = {
      info: () => {},
      debug: () => {},
      warn: () => {},
      error: () => {},
    } as unknown as Logger;
    
    sponsorRepository = new InMemorySponsorRepository(mockLogger);
    seasonSponsorshipRepository = new InMemorySeasonSponsorshipRepository(mockLogger);
    seasonRepository = new InMemorySeasonRepository(mockLogger);
    leagueRepository = new InMemoryLeagueRepository(mockLogger);
    leagueMembershipRepository = new InMemoryLeagueMembershipRepository(mockLogger);
    raceRepository = new InMemoryRaceRepository(mockLogger);
    
    getSponsorSponsorshipsUseCase = new GetSponsorSponsorshipsUseCase(
      sponsorRepository,
      seasonSponsorshipRepository,
      seasonRepository,
      leagueRepository,
      leagueMembershipRepository,
      raceRepository,
    );
  });

  beforeEach(() => {
    sponsorRepository.clear();
    seasonSponsorshipRepository.clear();
    seasonRepository.clear();
    leagueRepository.clear();
    leagueMembershipRepository.clear();
    raceRepository.clear();
  });

  describe('GetSponsorSponsorshipsUseCase - Success Path', () => {
    it('should retrieve all sponsorships for a sponsor', async () => {
      // Given: A sponsor exists with ID "sponsor-123"
      const sponsor = Sponsor.create({
        id: 'sponsor-123',
        name: 'Test Company',
        contactEmail: 'test@example.com',
      });
      await sponsorRepository.create(sponsor);

      // And: The sponsor has 3 sponsorships with different statuses
      const league1 = League.create({
        id: 'league-1',
        name: 'League 1',
        description: 'Description 1',
        ownerId: 'owner-1',
      });
      await leagueRepository.create(league1);

      const league2 = League.create({
        id: 'league-2',
        name: 'League 2',
        description: 'Description 2',
        ownerId: 'owner-2',
      });
      await leagueRepository.create(league2);

      const league3 = League.create({
        id: 'league-3',
        name: 'League 3',
        description: 'Description 3',
        ownerId: 'owner-3',
      });
      await leagueRepository.create(league3);

      const season1 = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        name: 'Season 1',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season1);

      const season2 = Season.create({
        id: 'season-2',
        leagueId: 'league-2',
        name: 'Season 2',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season2);

      const season3 = Season.create({
        id: 'season-3',
        leagueId: 'league-3',
        name: 'Season 3',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season3);

      const sponsorship1 = SeasonSponsorship.create({
        id: 'sponsorship-1',
        sponsorId: 'sponsor-123',
        seasonId: 'season-1',
        tier: 'main',
        pricing: Money.create(1000, 'USD'),
        status: 'active',
      });
      await seasonSponsorshipRepository.create(sponsorship1);

      const sponsorship2 = SeasonSponsorship.create({
        id: 'sponsorship-2',
        sponsorId: 'sponsor-123',
        seasonId: 'season-2',
        tier: 'secondary',
        pricing: Money.create(500, 'USD'),
        status: 'pending',
      });
      await seasonSponsorshipRepository.create(sponsorship2);

      const sponsorship3 = SeasonSponsorship.create({
        id: 'sponsorship-3',
        sponsorId: 'sponsor-123',
        seasonId: 'season-3',
        tier: 'secondary',
        pricing: Money.create(300, 'USD'),
        status: 'completed',
      });
      await seasonSponsorshipRepository.create(sponsorship3);

      // And: The sponsor has different numbers of drivers and races in each league
      for (let i = 1; i <= 10; i++) {
        const membership = LeagueMembership.create({
          id: `membership-1-${i}`,
          leagueId: 'league-1',
          driverId: `driver-1-${i}`,
          role: 'member',
          status: 'active',
        });
        await leagueMembershipRepository.saveMembership(membership);
      }

      for (let i = 1; i <= 5; i++) {
        const membership = LeagueMembership.create({
          id: `membership-2-${i}`,
          leagueId: 'league-2',
          driverId: `driver-2-${i}`,
          role: 'member',
          status: 'active',
        });
        await leagueMembershipRepository.saveMembership(membership);
      }

      for (let i = 1; i <= 8; i++) {
        const membership = LeagueMembership.create({
          id: `membership-3-${i}`,
          leagueId: 'league-3',
          driverId: `driver-3-${i}`,
          role: 'member',
          status: 'active',
        });
        await leagueMembershipRepository.saveMembership(membership);
      }

      for (let i = 1; i <= 5; i++) {
        const race = Race.create({
          id: `race-1-${i}`,
          leagueId: 'league-1',
          track: 'Track 1',
          scheduledAt: new Date(`2025-0${i}-01`),
          status: 'completed',
        });
        await raceRepository.create(race);
      }

      for (let i = 1; i <= 3; i++) {
        const race = Race.create({
          id: `race-2-${i}`,
          leagueId: 'league-2',
          track: 'Track 2',
          scheduledAt: new Date(`2025-0${i}-01`),
          status: 'completed',
        });
        await raceRepository.create(race);
      }

      for (let i = 1; i <= 4; i++) {
        const race = Race.create({
          id: `race-3-${i}`,
          leagueId: 'league-3',
          track: 'Track 3',
          scheduledAt: new Date(`2025-0${i}-01`),
          status: 'completed',
        });
        await raceRepository.create(race);
      }

      // When: GetSponsorSponsorshipsUseCase.execute() is called with sponsor ID
      const result = await getSponsorSponsorshipsUseCase.execute({ sponsorId: 'sponsor-123' });

      // Then: The result should contain sponsor sponsorships
      expect(result.isOk()).toBe(true);
      const sponsorships = result.unwrap();

      // And: The sponsor name should be correct
      expect(sponsorships.sponsor.name.toString()).toBe('Test Company');

      // And: The sponsorships should contain all 3 sponsorships
      expect(sponsorships.sponsorships).toHaveLength(3);

      // And: The summary should show correct values
      expect(sponsorships.summary.totalSponsorships).toBe(3);
      expect(sponsorships.summary.activeSponsorships).toBe(1);
      expect(sponsorships.summary.totalInvestment.amount).toBe(1800); // 1000 + 500 + 300
      expect(sponsorships.summary.totalPlatformFees.amount).toBe(180); // 100 + 50 + 30

      // And: Each sponsorship should have correct metrics
      const sponsorship1Summary = sponsorships.sponsorships.find(s => s.sponsorship.id === 'sponsorship-1');
      expect(sponsorship1Summary).toBeDefined();
      expect(sponsorship1Summary?.metrics.drivers).toBe(10);
      expect(sponsorship1Summary?.metrics.races).toBe(5);
      expect(sponsorship1Summary?.metrics.completedRaces).toBe(5);
      expect(sponsorship1Summary?.metrics.impressions).toBe(5000); // 5 * 10 * 100
    });

    it('should retrieve sponsorships with minimal data', async () => {
      // Given: A sponsor exists with ID "sponsor-123"
      const sponsor = Sponsor.create({
        id: 'sponsor-123',
        name: 'Test Company',
        contactEmail: 'test@example.com',
      });
      await sponsorRepository.create(sponsor);

      // And: The sponsor has 1 sponsorship
      const league = League.create({
        id: 'league-1',
        name: 'League 1',
        description: 'Description 1',
        ownerId: 'owner-1',
      });
      await leagueRepository.create(league);

      const season = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        name: 'Season 1',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season);

      const sponsorship = SeasonSponsorship.create({
        id: 'sponsorship-1',
        sponsorId: 'sponsor-123',
        seasonId: 'season-1',
        tier: 'main',
        pricing: Money.create(1000, 'USD'),
        status: 'active',
      });
      await seasonSponsorshipRepository.create(sponsorship);

      // When: GetSponsorSponsorshipsUseCase.execute() is called with sponsor ID
      const result = await getSponsorSponsorshipsUseCase.execute({ sponsorId: 'sponsor-123' });

      // Then: The result should contain sponsor sponsorships
      expect(result.isOk()).toBe(true);
      const sponsorships = result.unwrap();

      // And: The sponsorships should contain 1 sponsorship
      expect(sponsorships.sponsorships).toHaveLength(1);

      // And: The summary should show correct values
      expect(sponsorships.summary.totalSponsorships).toBe(1);
      expect(sponsorships.summary.activeSponsorships).toBe(1);
      expect(sponsorships.summary.totalInvestment.amount).toBe(1000);
      expect(sponsorships.summary.totalPlatformFees.amount).toBe(100);
    });

    it('should retrieve sponsorships with empty result when no sponsorships exist', async () => {
      // Given: A sponsor exists with ID "sponsor-123"
      const sponsor = Sponsor.create({
        id: 'sponsor-123',
        name: 'Test Company',
        contactEmail: 'test@example.com',
      });
      await sponsorRepository.create(sponsor);

      // And: The sponsor has no sponsorships
      // When: GetSponsorSponsorshipsUseCase.execute() is called with sponsor ID
      const result = await getSponsorSponsorshipsUseCase.execute({ sponsorId: 'sponsor-123' });

      // Then: The result should contain sponsor sponsorships
      expect(result.isOk()).toBe(true);
      const sponsorships = result.unwrap();

      // And: The sponsorships should be empty
      expect(sponsorships.sponsorships).toHaveLength(0);

      // And: The summary should show zero values
      expect(sponsorships.summary.totalSponsorships).toBe(0);
      expect(sponsorships.summary.activeSponsorships).toBe(0);
      expect(sponsorships.summary.totalInvestment.amount).toBe(0);
      expect(sponsorships.summary.totalPlatformFees.amount).toBe(0);
    });
  });

  describe('GetSponsorSponsorshipsUseCase - Error Handling', () => {
    it('should return error when sponsor does not exist', async () => {
      // Given: No sponsor exists with the given ID
      // When: GetSponsorSponsorshipsUseCase.execute() is called with non-existent sponsor ID
      const result = await getSponsorSponsorshipsUseCase.execute({ sponsorId: 'non-existent-sponsor' });

      // Then: Should return an error
      expect(result.isErr()).toBe(true);
      const error = result.unwrapErr();
      expect(error.code).toBe('SPONSOR_NOT_FOUND');
    });
  });

  describe('Sponsor Leagues Data Orchestration', () => {
    it('should correctly aggregate sponsorship metrics across multiple sponsorships', async () => {
      // Given: A sponsor exists with ID "sponsor-123"
      const sponsor = Sponsor.create({
        id: 'sponsor-123',
        name: 'Test Company',
        contactEmail: 'test@example.com',
      });
      await sponsorRepository.create(sponsor);

      // And: The sponsor has 3 sponsorships with different investments
      const league1 = League.create({
        id: 'league-1',
        name: 'League 1',
        description: 'Description 1',
        ownerId: 'owner-1',
      });
      await leagueRepository.create(league1);

      const league2 = League.create({
        id: 'league-2',
        name: 'League 2',
        description: 'Description 2',
        ownerId: 'owner-2',
      });
      await leagueRepository.create(league2);

      const league3 = League.create({
        id: 'league-3',
        name: 'League 3',
        description: 'Description 3',
        ownerId: 'owner-3',
      });
      await leagueRepository.create(league3);

      const season1 = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        name: 'Season 1',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season1);

      const season2 = Season.create({
        id: 'season-2',
        leagueId: 'league-2',
        name: 'Season 2',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season2);

      const season3 = Season.create({
        id: 'season-3',
        leagueId: 'league-3',
        name: 'Season 3',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season3);

      const sponsorship1 = SeasonSponsorship.create({
        id: 'sponsorship-1',
        sponsorId: 'sponsor-123',
        seasonId: 'season-1',
        tier: 'main',
        pricing: Money.create(1000, 'USD'),
        status: 'active',
      });
      await seasonSponsorshipRepository.create(sponsorship1);

      const sponsorship2 = SeasonSponsorship.create({
        id: 'sponsorship-2',
        sponsorId: 'sponsor-123',
        seasonId: 'season-2',
        tier: 'secondary',
        pricing: Money.create(2000, 'USD'),
        status: 'active',
      });
      await seasonSponsorshipRepository.create(sponsorship2);

      const sponsorship3 = SeasonSponsorship.create({
        id: 'sponsorship-3',
        sponsorId: 'sponsor-123',
        seasonId: 'season-3',
        tier: 'secondary',
        pricing: Money.create(3000, 'USD'),
        status: 'active',
      });
      await seasonSponsorshipRepository.create(sponsorship3);

      // And: The sponsor has different numbers of drivers and races in each league
      for (let i = 1; i <= 10; i++) {
        const membership = LeagueMembership.create({
          id: `membership-1-${i}`,
          leagueId: 'league-1',
          driverId: `driver-1-${i}`,
          role: 'member',
          status: 'active',
        });
        await leagueMembershipRepository.saveMembership(membership);
      }

      for (let i = 1; i <= 5; i++) {
        const membership = LeagueMembership.create({
          id: `membership-2-${i}`,
          leagueId: 'league-2',
          driverId: `driver-2-${i}`,
          role: 'member',
          status: 'active',
        });
        await leagueMembershipRepository.saveMembership(membership);
      }

      for (let i = 1; i <= 8; i++) {
        const membership = LeagueMembership.create({
          id: `membership-3-${i}`,
          leagueId: 'league-3',
          driverId: `driver-3-${i}`,
          role: 'member',
          status: 'active',
        });
        await leagueMembershipRepository.saveMembership(membership);
      }

      for (let i = 1; i <= 5; i++) {
        const race = Race.create({
          id: `race-1-${i}`,
          leagueId: 'league-1',
          track: 'Track 1',
          scheduledAt: new Date(`2025-0${i}-01`),
          status: 'completed',
        });
        await raceRepository.create(race);
      }

      for (let i = 1; i <= 3; i++) {
        const race = Race.create({
          id: `race-2-${i}`,
          leagueId: 'league-2',
          track: 'Track 2',
          scheduledAt: new Date(`2025-0${i}-01`),
          status: 'completed',
        });
        await raceRepository.create(race);
      }

      for (let i = 1; i <= 4; i++) {
        const race = Race.create({
          id: `race-3-${i}`,
          leagueId: 'league-3',
          track: 'Track 3',
          scheduledAt: new Date(`2025-0${i}-01`),
          status: 'completed',
        });
        await raceRepository.create(race);
      }

      // When: GetSponsorSponsorshipsUseCase.execute() is called
      const result = await getSponsorSponsorshipsUseCase.execute({ sponsorId: 'sponsor-123' });

      // Then: The metrics should be correctly aggregated
      expect(result.isOk()).toBe(true);
      const sponsorships = result.unwrap();

      // Total drivers: 10 + 5 + 8 = 23
      expect(sponsorships.sponsorships[0].metrics.drivers).toBe(10);
      expect(sponsorships.sponsorships[1].metrics.drivers).toBe(5);
      expect(sponsorships.sponsorships[2].metrics.drivers).toBe(8);

      // Total races: 5 + 3 + 4 = 12
      expect(sponsorships.sponsorships[0].metrics.races).toBe(5);
      expect(sponsorships.sponsorships[1].metrics.races).toBe(3);
      expect(sponsorships.sponsorships[2].metrics.races).toBe(4);

      // Total investment: 1000 + 2000 + 3000 = 6000
      expect(sponsorships.summary.totalInvestment.amount).toBe(6000);

      // Total platform fees: 100 + 200 + 300 = 600
      expect(sponsorships.summary.totalPlatformFees.amount).toBe(600);
    });

    it('should correctly calculate impressions based on completed races and drivers', async () => {
      // Given: A sponsor exists with ID "sponsor-123"
      const sponsor = Sponsor.create({
        id: 'sponsor-123',
        name: 'Test Company',
        contactEmail: 'test@example.com',
      });
      await sponsorRepository.create(sponsor);

      // And: The sponsor has 1 league with 10 drivers and 5 completed races
      const league = League.create({
        id: 'league-1',
        name: 'League 1',
        description: 'Description 1',
        ownerId: 'owner-1',
      });
      await leagueRepository.create(league);

      const season = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        name: 'Season 1',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season);

      const sponsorship = SeasonSponsorship.create({
        id: 'sponsorship-1',
        sponsorId: 'sponsor-123',
        seasonId: 'season-1',
        tier: 'main',
        pricing: Money.create(1000, 'USD'),
        status: 'active',
      });
      await seasonSponsorshipRepository.create(sponsorship);

      for (let i = 1; i <= 10; i++) {
        const membership = LeagueMembership.create({
          id: `membership-${i}`,
          leagueId: 'league-1',
          driverId: `driver-${i}`,
          role: 'member',
          status: 'active',
        });
        await leagueMembershipRepository.saveMembership(membership);
      }

      for (let i = 1; i <= 5; i++) {
        const race = Race.create({
          id: `race-${i}`,
          leagueId: 'league-1',
          track: 'Track 1',
          scheduledAt: new Date(`2025-0${i}-01`),
          status: 'completed',
        });
        await raceRepository.create(race);
      }

      // When: GetSponsorSponsorshipsUseCase.execute() is called
      const result = await getSponsorSponsorshipsUseCase.execute({ sponsorId: 'sponsor-123' });

      // Then: Impressions should be calculated correctly
      // Impressions = completed races * drivers * 100 = 5 * 10 * 100 = 5000
      expect(result.isOk()).toBe(true);
      const sponsorships = result.unwrap();
      expect(sponsorships.sponsorships[0].metrics.impressions).toBe(5000);
    });

    it('should correctly calculate platform fees and net amounts', async () => {
      // Given: A sponsor exists with ID "sponsor-123"
      const sponsor = Sponsor.create({
        id: 'sponsor-123',
        name: 'Test Company',
        contactEmail: 'test@example.com',
      });
      await sponsorRepository.create(sponsor);

      // And: The sponsor has 1 sponsorship
      const league = League.create({
        id: 'league-1',
        name: 'League 1',
        description: 'Description 1',
        ownerId: 'owner-1',
      });
      await leagueRepository.create(league);

      const season = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        name: 'Season 1',
        startDate: new Date('2025-01-01'),
        endDate: new Date('2025-12-31'),
      });
      await seasonRepository.create(season);

      const sponsorship = SeasonSponsorship.create({
        id: 'sponsorship-1',
        sponsorId: 'sponsor-123',
        seasonId: 'season-1',
        tier: 'main',
        pricing: Money.create(1000, 'USD'),
        status: 'active',
      });
      await seasonSponsorshipRepository.create(sponsorship);

      // When: GetSponsorSponsorshipsUseCase.execute() is called
      const result = await getSponsorSponsorshipsUseCase.execute({ sponsorId: 'sponsor-123' });

      // Then: Platform fees and net amounts should be calculated correctly
      expect(result.isOk()).toBe(true);
      const sponsorships = result.unwrap();

      // Platform fee = 10% of pricing = 100
      expect(sponsorships.sponsorships[0].financials.platformFee.amount).toBe(100);

      // Net amount = pricing - platform fee = 1000 - 100 = 900
      expect(sponsorships.sponsorships[0].financials.netAmount.amount).toBe(900);
    });
  });
});
