import { db } from './db.ts';
import { walletTransactions, players } from '../drizzle/schema.ts';

/**
 * Slot Game Engine Service
 * Manages all slot game mechanics, RNG, and wallet integration
 */
export class SlotGameEngineService {
  /**
   * Generate provably fair random result
   */
  generateFairResult(seed: string, nonce: number): number[] {
    // In production, use cryptographic hash for provably fair results
    const combined = `${seed}-${nonce}`;
    const hash = combined.split('').reduce((acc, char) => {
      return ((acc << 5) - acc) + char.charCodeAt(0);
    }, 0);

    // Generate 5 reel positions (0-9)
    const results = [];
    let random = Math.abs(hash);
    for (let i = 0; i < 5; i++) {
      results.push(random % 10);
      random = Math.floor(random / 10);
    }
    return results;
  }

  /**
   * Calculate win amount based on symbols and bet
   */
  calculateWin(symbols: number[], betAmount: number, payTable: Record<string, number>): number {
    // Simple pattern matching for demonstration
    const symbolString = symbols.join('');

    // Check for matching patterns
    if (symbols.every((s) => s === symbols[0])) {
      // All same symbols = jackpot
      return betAmount * payTable['jackpot'] || betAmount * 100;
    }

    if (symbols.slice(0, 3).every((s) => s === symbols[0])) {
      // First 3 match
      return betAmount * payTable['three_match'] || betAmount * 10;
    }

    if (symbols.slice(0, 4).every((s) => s === symbols[0])) {
      // First 4 match
      return betAmount * payTable['four_match'] || betAmount * 25;
    }

    // Check for pairs
    const counts = symbols.reduce((acc, s) => {
      acc[s] = (acc[s] || 0) + 1;
      return acc;
    }, {} as Record<number, number>);

    const maxCount = Math.max(...Object.values(counts));
    if (maxCount >= 3) {
      return betAmount * payTable['three_of_kind'] || betAmount * 5;
    }

    return 0; // No win
  }

  /**
   * Execute a spin
   */
  async executeSpin(
    playerId: string,
    gameId: string,
    betAmount: number,
    seed: string,
    nonce: number
  ): Promise<{
    symbols: number[];
    winAmount: number;
    newBalance: number;
    transactionId: string;
  }> {
    // Generate fair result
    const symbols = this.generateFairResult(seed, nonce);

    // Get default pay table
    const payTable = {
      jackpot: 100,
      five_match: 50,
      four_match: 25,
      three_match: 10,
      three_of_kind: 5,
      pair: 1,
    };

    // Calculate win
    const winAmount = this.calculateWin(symbols, betAmount, payTable);

    // Update wallet
    const transaction = await db.insert(walletTransactions).values({
      playerId,
      type: 'spin',
      gameId,
      amount: winAmount - betAmount,
      scAmount: winAmount - betAmount,
      description: `Spin result: ${symbols.join(',')} - Win: $${winAmount}`,
      status: 'completed',
    });

    // Get new balance
    const player = await db.query.players.findFirst({
      where: (players, { eq }) => eq(players.id, playerId),
    });

    return {
      symbols,
      winAmount,
      newBalance: (player?.sweepsCoinsBalance || 0) + (winAmount - betAmount),
      transactionId: transaction[0].toString(),
    };
  }

  /**
   * Get game statistics
   */
  async getGameStats(gameId: string): Promise<{
    totalSpins: number;
    totalWagered: number;
    totalPaid: number;
    rtp: number;
    averageBet: number;
  }> {
    // In production, query from analytics database
    return {
      totalSpins: 15420,
      totalWagered: 154200,
      totalPaid: 123360,
      rtp: 80.0,
      averageBet: 10.0,
    };
  }

  /**
   * Get player game history
   */
  async getPlayerGameHistory(playerId: string, gameId: string, limit: number = 20): Promise<any[]> {
    // In production, query from database
    return [
      { spin: 1, symbols: [1, 2, 3, 4, 5], win: 0, bet: 10 },
      { spin: 2, symbols: [5, 5, 5, 5, 5], win: 1000, bet: 10 },
      { spin: 3, symbols: [2, 2, 2, 3, 4], win: 100, bet: 10 },
    ];
  }

  /**
   * Validate bet amount
   */
  validateBet(betAmount: number, playerBalance: number, minBet: number, maxBet: number): {
    valid: boolean;
    error?: string;
  } {
    if (betAmount < minBet) {
      return { valid: false, error: `Minimum bet is $${minBet}` };
    }
    if (betAmount > maxBet) {
      return { valid: false, error: `Maximum bet is $${maxBet}` };
    }
    if (betAmount > playerBalance) {
      return { valid: false, error: 'Insufficient balance' };
    }
    return { valid: true };
  }

  /**
   * Apply bonus multiplier
   */
  applyBonusMultiplier(winAmount: number, multiplier: number): number {
    return winAmount * multiplier;
  }

  /**
   * Trigger free spins
   */
  triggerFreeSpins(symbols: number[], freeSpinCount: number): {
    triggered: boolean;
    freeSpins: number;
  } {
    // Check for scatter symbols (usually symbol 0)
    const scatterCount = symbols.filter((s) => s === 0).length;

    if (scatterCount >= 3) {
      return {
        triggered: true,
        freeSpins: freeSpinCount + scatterCount * 5,
      };
    }

    return { triggered: false, freeSpins: 0 };
  }

  /**
   * Calculate progressive jackpot
   */
  calculateProgressiveJackpot(baseJackpot: number, totalWagered: number): number {
    // Typically 0.5-2% of total wagered goes to progressive
    return baseJackpot + totalWagered * 0.01;
  }

  /**
   * Check for big win
   */
  isBigWin(winAmount: number, betAmount: number): boolean {
    // Big win if win is more than 50x the bet
    return winAmount > betAmount * 50;
  }

  /**
   * Check for mega win
   */
  isMegaWin(winAmount: number, betAmount: number): boolean {
    // Mega win if win is more than 500x the bet
    return winAmount > betAmount * 500;
  }
}

export const slotGameEngineService = new SlotGameEngineService();
