/**
 * Application Use Case: ProcessWalletTransactionUseCase
 *
 * Processes a wallet transaction (deposit or withdrawal).
 */

import type { IWalletRepository, ITransactionRepository } from '../../domain/repositories/IWalletRepository';
import type { Wallet, Transaction } from '../../domain/entities/Wallet';
import { TransactionType, ReferenceType } from '../../domain/entities/Wallet';
import type { UseCase } from '@core/shared/application/UseCase';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';

export interface ProcessWalletTransactionInput {
  leagueId: string;
  type: TransactionType;
  amount: number;
  description: string;
  referenceId?: string;
  referenceType?: ReferenceType;
}

export interface ProcessWalletTransactionResult {
  wallet: Wallet;
  transaction: Transaction;
}

export type ProcessWalletTransactionErrorCode = 'MISSING_REQUIRED_FIELDS' | 'INVALID_TYPE' | 'INSUFFICIENT_BALANCE';

export class ProcessWalletTransactionUseCase
  implements UseCase<ProcessWalletTransactionInput, void, ProcessWalletTransactionErrorCode>
{
  constructor(
    private readonly walletRepository: IWalletRepository,
    private readonly transactionRepository: ITransactionRepository,
    private readonly output: UseCaseOutputPort<ProcessWalletTransactionResult>,
  ) {}

  async execute(input: ProcessWalletTransactionInput): Promise<Result<void, ApplicationErrorCode<ProcessWalletTransactionErrorCode>>> {
    const { leagueId, type, amount, description, referenceId, referenceType } = input;

    if (!leagueId || !type || amount === undefined || !description) {
      return Result.err({ code: 'MISSING_REQUIRED_FIELDS' as const });
    }

    if (type !== TransactionType.DEPOSIT && type !== TransactionType.WITHDRAWAL) {
      return Result.err({ code: 'INVALID_TYPE' as const });
    }

    let wallet = await this.walletRepository.findByLeagueId(leagueId);

    if (!wallet) {
      const id = `wallet-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
      const newWallet: Wallet = {
        id,
        leagueId,
        balance: 0,
        totalRevenue: 0,
        totalPlatformFees: 0,
        totalWithdrawn: 0,
        currency: 'USD',
        createdAt: new Date(),
      };
      wallet = await this.walletRepository.create(newWallet);
    }

    if (type === TransactionType.WITHDRAWAL) {
      if (amount > wallet.balance) {
        return Result.err({ code: 'INSUFFICIENT_BALANCE' as const });
      }
    }

    const transactionId = `txn-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    const transaction: Transaction = {
      id: transactionId,
      walletId: wallet.id,
      type,
      amount,
      description,
      createdAt: new Date(),
      ...(referenceId !== undefined ? { referenceId } : {}),
      ...(referenceType !== undefined ? { referenceType } : {}),
    };

    const createdTransaction = await this.transactionRepository.create(transaction);

    if (type === TransactionType.DEPOSIT) {
      wallet.balance += amount;
      wallet.totalRevenue += amount;
    } else {
      wallet.balance -= amount;
      wallet.totalWithdrawn += amount;
    }

    const updatedWallet = await this.walletRepository.update(wallet);

    this.output.present({ wallet: updatedWallet, transaction: createdTransaction });

    return Result.ok(undefined);
  }
}