import { describe, expect, it, vi, type Mock } from 'vitest';
import { ReferenceType, TransactionType } from '../../domain/entities/Wallet';
import type { TransactionRepository, WalletRepository } from '../../domain/repositories/WalletRepository';
import { ProcessWalletTransactionUseCase, type ProcessWalletTransactionInput } from './ProcessWalletTransactionUseCase';

describe('ProcessWalletTransactionUseCase', () => {
  let walletRepository: {
    findByLeagueId: Mock;
    create: Mock;
    update: Mock;
  };
  let transactionRepository: {
    create: Mock;
  };
  let useCase: ProcessWalletTransactionUseCase;

  beforeEach(() => {
    walletRepository = {
      findByLeagueId: vi.fn(),
      create: vi.fn(),
      update: vi.fn(),
    };

    transactionRepository = {
      create: vi.fn(),
    };

    useCase = new ProcessWalletTransactionUseCase(
      walletRepository as unknown as WalletRepository,
      transactionRepository as unknown as TransactionRepository,
    );
  });

  it('processes a deposit transaction and returns the result', async () => {
    const input: ProcessWalletTransactionInput = {
      leagueId: 'league-1',
      type: TransactionType.DEPOSIT,
      amount: 100,
      description: 'Test deposit',
      referenceId: 'ref-1',
      referenceType: ReferenceType.SPONSORSHIP,
    };

    const wallet = {
      id: 'wallet-1',
      leagueId: 'league-1',
      balance: 50,
      totalRevenue: 50,
      totalPlatformFees: 0,
      totalWithdrawn: 0,
      currency: 'USD',
      createdAt: new Date(),
    };

    const transaction = {
      id: 'txn-1',
      walletId: 'wallet-1',
      type: TransactionType.DEPOSIT,
      amount: 100,
      description: 'Test deposit',
      referenceId: 'ref-1',
      referenceType: ReferenceType.SPONSORSHIP,
      createdAt: new Date(),
    };

    walletRepository.findByLeagueId.mockResolvedValue(wallet);
    transactionRepository.create.mockResolvedValue(transaction);
    walletRepository.update.mockResolvedValue({ ...wallet, balance: 150, totalRevenue: 150 });

    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    const value = result.value;
    expect(value.wallet).toEqual({ ...wallet, balance: 150, totalRevenue: 150 });
    expect(value.transaction).toEqual(transaction);
  });

  it('returns error for insufficient balance on withdrawal', async () => {
    const input: ProcessWalletTransactionInput = {
      leagueId: 'league-1',
      type: TransactionType.WITHDRAWAL,
      amount: 100,
      description: 'Test withdrawal',
    };

    const wallet = {
      id: 'wallet-1',
      leagueId: 'league-1',
      balance: 50,
      totalRevenue: 50,
      totalPlatformFees: 0,
      totalWithdrawn: 0,
      currency: 'USD',
      createdAt: new Date(),
    };

    walletRepository.findByLeagueId.mockResolvedValue(wallet);

    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr().code).toBe('INSUFFICIENT_BALANCE');
  });
});