/**
 * Real-time SC Wallet Integration
 * Handles real-time balance loading, debiting, and crediting for games
 */

import { EventEmitter } from 'events';

export interface WalletTransaction {
  id: string;
  userId: string;
  gameId: string;
  type: 'debit' | 'credit';
  amount: number;
  previousBalance: number;
  newBalance: number;
  timestamp: Date;
  status: 'pending' | 'completed' | 'failed';
  description: string;
}

export interface WalletBalance {
  userId: string;
  sweepsCoins: number;
  gameCoins: number;
  totalSpent: number;
  totalWon: number;
  lastUpdated: Date;
}

export class RealtimeWalletIntegration extends EventEmitter {
  private walletBalances: Map<string, WalletBalance> = new Map();
  private transactions: WalletTransaction[] = [];
  private transactionQueue: WalletTransaction[] = [];
  private processingQueue = false;

  constructor() {
    super();
    this.startQueueProcessor();
  }

  /**
   * Load real-time wallet balance for user
   */
  async loadWalletBalance(userId: string): Promise<WalletBalance> {
    // Check cache first
    if (this.walletBalances.has(userId)) {
      const cached = this.walletBalances.get(userId)!;
      // Refresh if older than 5 seconds
      if (Date.now() - cached.lastUpdated.getTime() < 5000) {
        return cached;
      }
    }

    // Fetch from database (simulated)
    const balance: WalletBalance = {
      userId,
      sweepsCoins: Math.random() * 1000,
      gameCoins: Math.random() * 500,
      totalSpent: Math.random() * 5000,
      totalWon: Math.random() * 3000,
      lastUpdated: new Date(),
    };

    this.walletBalances.set(userId, balance);
    this.emit('balance_loaded', { userId, balance });

    return balance;
  }

  /**
   * Real-time debit bet amount from wallet
   */
  async debitBet(userId: string, gameId: string, amount: number): Promise<WalletBalance> {
    const balance = await this.loadWalletBalance(userId);

    if (balance.sweepsCoins < amount) {
      this.emit('insufficient_balance', { userId, required: amount, available: balance.sweepsCoins });
      throw new Error('Insufficient balance');
    }

    const transaction: WalletTransaction = {
      id: `txn-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      userId,
      gameId,
      type: 'debit',
      amount,
      previousBalance: balance.sweepsCoins,
      newBalance: balance.sweepsCoins - amount,
      timestamp: new Date(),
      status: 'pending',
      description: `Bet placed on ${gameId}`,
    };

    // Queue transaction for processing
    this.transactionQueue.push(transaction);

    // Update balance immediately (optimistic)
    balance.sweepsCoins -= amount;
    balance.totalSpent += amount;
    balance.lastUpdated = new Date();
    this.walletBalances.set(userId, balance);

    this.emit('bet_debited', { userId, gameId, amount, newBalance: balance.sweepsCoins });

    return balance;
  }

  /**
   * Real-time credit win amount to wallet
   */
  async creditWin(userId: string, gameId: string, amount: number): Promise<WalletBalance> {
    const balance = await this.loadWalletBalance(userId);

    const transaction: WalletTransaction = {
      id: `txn-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      userId,
      gameId,
      type: 'credit',
      amount,
      previousBalance: balance.sweepsCoins,
      newBalance: balance.sweepsCoins + amount,
      timestamp: new Date(),
      status: 'pending',
      description: `Win from ${gameId}`,
    };

    // Queue transaction for processing
    this.transactionQueue.push(transaction);

    // Update balance immediately (optimistic)
    balance.sweepsCoins += amount;
    balance.totalWon += amount;
    balance.lastUpdated = new Date();
    this.walletBalances.set(userId, balance);

    this.emit('win_credited', { userId, gameId, amount, newBalance: balance.sweepsCoins });

    return balance;
  }

  /**
   * Process transaction queue
   */
  private startQueueProcessor(): void {
    setInterval(() => {
      if (this.transactionQueue.length > 0 && !this.processingQueue) {
        this.processingQueue = true;
        this.processQueue();
      }
    }, 1000);
  }

  /**
   * Process queued transactions
   */
  private async processQueue(): Promise<void> {
    const batch = this.transactionQueue.splice(0, 10); // Process 10 at a time

    for (const transaction of batch) {
      try {
        // Simulate database save
        transaction.status = 'completed';
        this.transactions.push(transaction);

        this.emit('transaction_completed', transaction);
      } catch (error) {
        transaction.status = 'failed';
        this.emit('transaction_failed', { transaction, error });
      }
    }

    this.processingQueue = false;
  }

  /**
   * Get transaction history
   */
  getTransactionHistory(userId: string, limit: number = 50): WalletTransaction[] {
    return this.transactions
      .filter((t) => t.userId === userId)
      .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
      .slice(0, limit);
  }

  /**
   * Get wallet statistics
   */
  getWalletStats(userId: string): {
    totalTransactions: number;
    totalDebits: number;
    totalCredits: number;
    netBalance: number;
  } {
    const userTransactions = this.transactions.filter((t) => t.userId === userId);
    const totalDebits = userTransactions
      .filter((t) => t.type === 'debit')
      .reduce((sum, t) => sum + t.amount, 0);
    const totalCredits = userTransactions
      .filter((t) => t.type === 'credit')
      .reduce((sum, t) => sum + t.amount, 0);

    return {
      totalTransactions: userTransactions.length,
      totalDebits,
      totalCredits,
      netBalance: totalCredits - totalDebits,
    };
  }

  /**
   * Verify transaction
   */
  verifyTransaction(transactionId: string): WalletTransaction | undefined {
    return this.transactions.find((t) => t.id === transactionId);
  }

  /**
   * Rollback transaction (for failed spins)
   */
  async rollbackTransaction(transactionId: string): Promise<WalletBalance | null> {
    const transaction = this.transactions.find((t) => t.id === transactionId);
    if (!transaction) {
      return null;
    }

    const balance = await this.loadWalletBalance(transaction.userId);

    if (transaction.type === 'debit') {
      // Refund the debit
      balance.sweepsCoins = transaction.previousBalance;
      balance.totalSpent -= transaction.amount;
    } else if (transaction.type === 'credit') {
      // Remove the credit
      balance.sweepsCoins = transaction.previousBalance;
      balance.totalWon -= transaction.amount;
    }

    balance.lastUpdated = new Date();
    this.walletBalances.set(transaction.userId, balance);

    this.emit('transaction_rolled_back', { transactionId, newBalance: balance });

    return balance;
  }

  /**
   * Get real-time balance updates (for WebSocket)
   */
  subscribeToBalanceUpdates(userId: string, callback: (balance: WalletBalance) => void): () => void {
    const handler = (data: { userId: string; balance: WalletBalance }) => {
      if (data.userId === userId) {
        callback(data.balance);
      }
    };

    this.on('balance_loaded', handler);
    this.on('bet_debited', handler);
    this.on('win_credited', handler);

    // Return unsubscribe function
    return () => {
      this.off('balance_loaded', handler);
      this.off('bet_debited', handler);
      this.off('win_credited', handler);
    };
  }
}

export const realtimeWalletIntegration = new RealtimeWalletIntegration();
