import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { GetSponsorSponsorshipsUseCase } from './GetSponsorSponsorshipsUseCase';
import { ISponsorRepository } from '../../domain/repositories/ISponsorRepository';
import { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
import { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
import { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import { Sponsor } from '../../domain/entities/Sponsor';
import { SeasonSponsorship } from '../../domain/entities/SeasonSponsorship';
import { Season } from '../../domain/entities/Season';
import { League } from '../../domain/entities/League';
import { Money } from '../../domain/value-objects/Money';

describe('GetSponsorSponsorshipsUseCase', () => {
  let useCase: GetSponsorSponsorshipsUseCase;
  let sponsorRepository: {
    findById: Mock;
  };
  let seasonSponsorshipRepository: {
    findBySponsorId: Mock;
  };
  let seasonRepository: {
    findById: Mock;
  };
  let leagueRepository: {
    findById: Mock;
  };
  let leagueMembershipRepository: {
    getLeagueMembers: Mock;
  };
  let raceRepository: {
    findByLeagueId: Mock;
  };

  beforeEach(() => {
    sponsorRepository = {
      findById: vi.fn(),
    };
    seasonSponsorshipRepository = {
      findBySponsorId: vi.fn(),
    };
    seasonRepository = {
      findById: vi.fn(),
    };
    leagueRepository = {
      findById: vi.fn(),
    };
    leagueMembershipRepository = {
      getLeagueMembers: vi.fn(),
    };
    raceRepository = {
      findByLeagueId: vi.fn(),
    };
    useCase = new GetSponsorSponsorshipsUseCase(
      sponsorRepository as unknown as ISponsorRepository,
      seasonSponsorshipRepository as unknown as ISeasonSponsorshipRepository,
      seasonRepository as unknown as ISeasonRepository,
      leagueRepository as unknown as ILeagueRepository,
      leagueMembershipRepository as unknown as ILeagueMembershipRepository,
      raceRepository as unknown as IRaceRepository,
    );
  });

  it('should return sponsor sponsorships for existing sponsor', async () => {
    const sponsorId = 'sponsor-1';
    const sponsor = Sponsor.create({
      id: sponsorId,
      name: 'Test Sponsor',
      contactEmail: 'test@example.com',
    });
    const sponsorship = SeasonSponsorship.create({
      id: 'sponsorship-1',
      sponsorId,
      seasonId: 'season-1',
      tier: 'main',
      pricing: Money.create(10000, 'USD'),
    });
    const season = Season.create({
      id: 'season-1',
      leagueId: 'league-1',
      gameId: 'game-1',
      name: 'Season 1',
      status: 'active',
    });
    const league = League.create({
      id: 'league-1',
      name: 'Test League',
      description: 'Test',
      ownerId: 'owner-1',
    });
    const memberships = [{ driverId: 'driver-1' }];
    const races = [{ id: 'race-1', status: 'completed' }];

    sponsorRepository.findById.mockResolvedValue(sponsor);
    seasonSponsorshipRepository.findBySponsorId.mockResolvedValue([sponsorship]);
    seasonRepository.findById.mockResolvedValue(season);
    leagueRepository.findById.mockResolvedValue(league);
    leagueMembershipRepository.getLeagueMembers.mockResolvedValue(memberships);
    raceRepository.findByLeagueId.mockResolvedValue(races);

    const result = await useCase.execute({ sponsorId });

    expect(result.isOk()).toBe(true);
    const data = result.unwrap();
    expect(data?.sponsorId).toBe(sponsorId);
    expect(data?.sponsorships).toHaveLength(1);
  });

  it('should return null for non-existing sponsor', async () => {
    const sponsorId = 'sponsor-1';
    sponsorRepository.findById.mockResolvedValue(null);

    const result = await useCase.execute({ sponsorId });

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toBe(null);
  });

  it('should return error on repository failure', async () => {
    const sponsorId = 'sponsor-1';
    sponsorRepository.findById.mockRejectedValue(new Error('DB error'));

    const result = await useCase.execute({ sponsorId });

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr()).toEqual({
      code: 'REPOSITORY_ERROR',
      message: 'Failed to fetch sponsor sponsorships',
    });
  });
});