import { Injectable, Inject, NotFoundException, BadRequestException } from '@nestjs/common';
import { WALLET_REPOSITORY, IWalletRepository } from '../../domain/repositories/wallet.repository.interface';
import { TRANSACTION_REPOSITORY, ITransactionRepository } from '../../domain/repositories/transaction.repository.interface';
import { TransactionType } from '../../domain/entities/transaction.entity';

@Injectable()
export class WalletService {
  constructor(
    @Inject(WALLET_REPOSITORY) private readonly walletRepo: IWalletRepository,
    @Inject(TRANSACTION_REPOSITORY) private readonly txRepo: ITransactionRepository,
  ) {}

  async getWallet(userId: string) {
    let wallet = await this.walletRepo.findByUserId(userId);
    if (!wallet) {
      wallet = await this.walletRepo.create(userId);
    }
    return {
      id: wallet.id,
      balance: wallet.balance,
      frozenBalance: wallet.frozenBalance,
      currency: wallet.currency,
      status: wallet.status,
    };
  }

  async deposit(userId: string, amount: string, description?: string) {
    const wallet = await this.walletRepo.findByUserIdWithLock(userId);
    if (!wallet) throw new NotFoundException('Wallet not found');

    const oldBalance = parseFloat(wallet.balance);
    const depositAmount = parseFloat(amount);
    if (depositAmount <= 0) throw new BadRequestException('Amount must be positive');

    const newBalance = (oldBalance + depositAmount).toFixed(8);
    wallet.balance = newBalance;
    await this.walletRepo.save(wallet);

    const tx = await this.txRepo.create({
      walletId: wallet.id,
      type: TransactionType.DEPOSIT,
      amount,
      balanceAfter: newBalance,
      currency: wallet.currency,
      description: description || 'Deposit',
      status: 'completed',
    });

    return { balance: newBalance, transactionId: tx.id };
  }

  async withdraw(userId: string, amount: string, description?: string) {
    const wallet = await this.walletRepo.findByUserIdWithLock(userId);
    if (!wallet) throw new NotFoundException('Wallet not found');

    const oldBalance = parseFloat(wallet.balance);
    const withdrawAmount = parseFloat(amount);
    if (withdrawAmount <= 0) throw new BadRequestException('Amount must be positive');
    if (withdrawAmount > oldBalance) throw new BadRequestException('Insufficient balance');

    const newBalance = (oldBalance - withdrawAmount).toFixed(8);
    wallet.balance = newBalance;
    await this.walletRepo.save(wallet);

    const tx = await this.txRepo.create({
      walletId: wallet.id,
      type: TransactionType.WITHDRAWAL,
      amount: `-${amount}`,
      balanceAfter: newBalance,
      currency: wallet.currency,
      description: description || 'Withdrawal',
      status: 'completed',
    });

    return { balance: newBalance, transactionId: tx.id };
  }

  async getTransactions(userId: string, page: number, limit: number) {
    const wallet = await this.walletRepo.findByUserId(userId);
    if (!wallet) return { items: [], total: 0, page, limit };

    const [items, total] = await this.txRepo.findByWalletId(wallet.id, page, limit);
    return { items, total, page, limit };
  }
}
