import { SeasonSponsorship } from '@core/racing/domain/entities/season/SeasonSponsorship';
import type { SeasonSponsorshipRepository } from '@core/racing/domain/repositories/SeasonSponsorshipRepository';
import { Money } from '@core/racing/domain/value-objects/Money';
import { describe, expect, it, vi, type Mock } from 'vitest';
import type { Payment } from '../../domain/entities/Payment';
import { PayerType, PaymentStatus, PaymentType } from '../../domain/entities/Payment';
import type { PaymentRepository } from '../../domain/repositories/PaymentRepository';
import { GetSponsorBillingUseCase, type GetSponsorBillingInput } from './GetSponsorBillingUseCase';

describe('GetSponsorBillingUseCase', () => {
  let paymentRepository: { findByFilters: Mock };
  let seasonSponsorshipRepository: { findBySponsorId: Mock };
  let useCase: GetSponsorBillingUseCase;

  beforeEach(() => {
    paymentRepository = {
      findByFilters: vi.fn(),
    };

    seasonSponsorshipRepository = {
      findBySponsorId: vi.fn(),
    };

    useCase = new GetSponsorBillingUseCase(
      paymentRepository as unknown as PaymentRepository,
      seasonSponsorshipRepository as unknown as SeasonSponsorshipRepository,
    );
  });

  it('derives invoices and stats from payments and sponsorships', async () => {
    const sponsorId = 'sponsor-1';

    const payments: Payment[] = [
      {
        id: 'pay-1',
        type: PaymentType.SPONSORSHIP,
        amount: 100,
        platformFee: 10,
        netAmount: 90,
        payerId: sponsorId,
        payerType: PayerType.SPONSOR,
        leagueId: 'league-1',
        seasonId: 'season-1',
        status: PaymentStatus.COMPLETED,
        createdAt: new Date('2024-01-01T00:00:00.000Z'),
        completedAt: new Date('2024-01-01T00:00:00.000Z'),
      },
      {
        id: 'pay-2',
        type: PaymentType.SPONSORSHIP,
        amount: 50,
        platformFee: 5,
        netAmount: 45,
        payerId: sponsorId,
        payerType: PayerType.SPONSOR,
        leagueId: 'league-1',
        seasonId: 'season-1',
        status: PaymentStatus.PENDING,
        createdAt: new Date('2024-02-01T00:00:00.000Z'),
      },
    ];

    paymentRepository.findByFilters.mockResolvedValue(payments);

    const sponsorships = [
      SeasonSponsorship.create({
        id: 'ss-1',
        seasonId: 'season-1',
        leagueId: 'league-1',
        sponsorId,
        tier: 'main',
        pricing: Money.create(100, 'USD'),
        status: 'active',
      }),
      SeasonSponsorship.create({
        id: 'ss-2',
        seasonId: 'season-2',
        leagueId: 'league-1',
        sponsorId,
        tier: 'secondary',
        pricing: Money.create(50, 'USD'),
        status: 'pending',
      }),
    ];

    seasonSponsorshipRepository.findBySponsorId.mockResolvedValue(sponsorships);

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

    expect(result.isOk()).toBe(true);
    const value = result.unwrap();

    expect(paymentRepository.findByFilters).toHaveBeenCalledWith({
      payerId: sponsorId,
      type: PaymentType.SPONSORSHIP,
    });

    expect(seasonSponsorshipRepository.findBySponsorId).toHaveBeenCalledWith(sponsorId);

    expect(value.paymentMethods).toEqual([]);
    expect(value.invoices).toHaveLength(2);

    // totals: each invoice adds 19% VAT
    // pay-1 total: 100 + 19 = 119 (paid)
    // pay-2 total: 50 + 9.5 = 59.5 (pending)
    expect(value.stats.totalSpent).toBeCloseTo(119, 5);
    expect(value.stats.pendingAmount).toBeCloseTo(59.5, 5);

    expect(value.stats.activeSponsorships).toBe(1);
    expect(value.stats.nextPaymentDate).not.toBeNull();
    expect(value.stats.nextPaymentAmount).not.toBeNull();
  });
});