import { NotFoundError } from '../../../domain/errors/not-found-error';
import { WalletBalanceService } from '../../../domain/services/wallet-balance.service';
import { IWalletRepository } from '../../../domain/repositories/wallet-repository';
import { INetworkRepository } from '../../../domain/repositories/network-repository';
import { IAddressRepository } from '../../../domain/repositories/address-repository';
import { ITokenRepository } from '../../../domain/repositories/token-repository';
import { ITransactionRepository } from '../../../domain/repositories/transaction-repository';
import { TokenBalanceOutput } from '../../dto/balance.dto';

export class GetWalletBalancesForNetworkUseCase {
  constructor(
    private readonly walletRepository: IWalletRepository,
    private readonly networkRepository: INetworkRepository,
    private readonly addressRepository: IAddressRepository,
    private readonly tokenRepository: ITokenRepository,
    private readonly transactionRepository: ITransactionRepository,
    private readonly balanceService: WalletBalanceService,
  ) {}

  async execute(walletId: string, networkId: string): Promise<TokenBalanceOutput[]> {
    const wallet = await this.walletRepository.findById(walletId);
    if (!wallet) {
      throw new NotFoundError('Wallet', walletId);
    }

    const network = await this.networkRepository.findById(networkId);
    if (!network) {
      throw new NotFoundError('Network', networkId);
    }

    const addresses = await this.addressRepository.findByWalletId(walletId);
    const networkAddresses = addresses.filter((address) => address.type === network.addressType);
    const addressIds = networkAddresses.map((address) => address.id);

    if (addressIds.length === 0) {
      return [];
    }

    const transactions = await this.transactionRepository.findByAddressIds(addressIds);
    const networkTransactions = transactions.filter(
      (transaction) => transaction.networkId === networkId,
    );
    const tokens = await this.tokenRepository.findByNetworkId(networkId);

    const balances = this.balanceService.calculate(networkAddresses, networkTransactions, tokens);
    return balances;
  }
}
