import type { Logger } from '@core/shared/domain/Logger'; import { Result } from '@core/shared/domain/Result'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import { LeagueWalletId } from '../../domain/entities/league-wallet/LeagueWalletId'; import { Transaction } from '../../domain/entities/league-wallet/Transaction'; import { TransactionId } from '../../domain/entities/league-wallet/TransactionId'; import { LeagueRepository } from '../../domain/repositories/LeagueRepository'; import { LeagueWalletRepository } from '../../domain/repositories/LeagueWalletRepository'; import { TransactionRepository } from '../../domain/repositories/TransactionRepository'; import { Money } from '../../domain/value-objects/Money'; export type WithdrawFromLeagueWalletInput = { leagueId: string; requestedById: string; amount: number; currency: 'USD' | 'EUR' | 'GBP'; reason?: string; }; export type WithdrawFromLeagueWalletResult = { leagueId: string; amount: Money; transactionId: string; walletBalanceAfter: Money; }; export type WithdrawFromLeagueWalletErrorCode = | 'LEAGUE_NOT_FOUND' | 'WALLET_NOT_FOUND' | 'INSUFFICIENT_FUNDS' | 'UNAUTHORIZED_WITHDRAWAL' | 'REPOSITORY_ERROR'; /** * Use Case for withdrawing from league wallet. */ export class WithdrawFromLeagueWalletUseCase { constructor(private readonly leagueRepository: LeagueRepository, private readonly walletRepository: LeagueWalletRepository, private readonly transactionRepository: TransactionRepository, private readonly logger: Logger) {} async execute( input: WithdrawFromLeagueWalletInput, ): Promise< Result< WithdrawFromLeagueWalletResult, ApplicationErrorCode< WithdrawFromLeagueWalletErrorCode, { message: string; } > > > { try { const league = await this.leagueRepository.findById(input.leagueId); if (!league) { return Result.err({ code: 'LEAGUE_NOT_FOUND', details: { message: `League with id ${input.leagueId} not found` }, }); } const wallet = await this.walletRepository.findByLeagueId(input.leagueId); if (!wallet) { return Result.err({ code: 'WALLET_NOT_FOUND', details: { message: `Wallet for league ${input.leagueId} not found` }, }); } if (league.ownerId.toString() !== input.requestedById) { return Result.err({ code: 'UNAUTHORIZED_WITHDRAWAL', details: { message: 'Only the league owner can withdraw from the league wallet' }, }); } const withdrawalAmount = Money.create(input.amount, input.currency); if (!wallet.canWithdraw(withdrawalAmount)) { return Result.err({ code: 'INSUFFICIENT_FUNDS', details: { message: 'Insufficient balance for withdrawal' }, }); } const transactionId = TransactionId.create(`txn-${Date.now()}`); const transaction = Transaction.create({ id: transactionId, walletId: LeagueWalletId.create(wallet.id.toString()), type: 'withdrawal', amount: withdrawalAmount, description: input.reason ?? 'League wallet withdrawal', metadata: { reason: input.reason, requestedById: input.requestedById, }, completedAt: undefined, }); const updatedWallet = wallet.withdrawFunds(withdrawalAmount, transactionId.toString()); await this.transactionRepository.create(transaction); await this.walletRepository.update(updatedWallet); const result: WithdrawFromLeagueWalletResult = { leagueId: input.leagueId, amount: withdrawalAmount, transactionId: transactionId.toString(), walletBalanceAfter: updatedWallet.balance, }; return Result.ok(result); } catch (error) { this.logger.error( 'Failed to withdraw from league wallet', error instanceof Error ? error : undefined, { leagueId: input.leagueId, requestedById: input.requestedById, }, ); return Result.err({ code: 'REPOSITORY_ERROR', details: { message: error instanceof Error ? error.message : 'Failed to withdraw from league wallet', }, }); } } }