import crypto from 'crypto';

export type BonusType = 'pick_em' | 'wheel_spin' | 'free_spins' | 'multiplier';
export type BonusStatus = 'active' | 'completed' | 'expired';

export interface BonusRound {
  id: number;
  userId: number;
  gameId: number;
  bonusType: BonusType;
  triggerSpinId: string;
  betAmount: number;
  multiplier: number;
  freeSpinsCount: number;
  bonusWinAmount: number;
  status: BonusStatus;
  createdAt: Date;
  completedAt?: Date;
  expiresAt?: Date;
}

export interface BonusChoice {
  id: number;
  bonusRoundId: number;
  choiceIndex: number;
  symbol: string;
  value: number;
  isSelected: boolean;
  selectedAt?: Date;
}

/**
 * Bonus Round Engine
 * Handles different types of bonus games triggered by scatter symbols
 */
export class BonusRoundEngine {
  /**
   * Generate a pick-em bonus game
   * Player picks from hidden items to reveal prizes
   */
  static generatePickEm(
    betAmount: number,
    difficulty: 'easy' | 'medium' | 'hard' = 'medium'
  ): BonusChoice[] {
    const itemCount = difficulty === 'easy' ? 3 : difficulty === 'medium' ? 5 : 7;
    const choices: BonusChoice[] = [];

    // Generate random values with some high-value items
    const values = this.generatePickEmValues(itemCount);

    for (let i = 0; i < itemCount; i++) {
      choices.push({
        id: i,
        bonusRoundId: 0, // Will be set when saved
        choiceIndex: i,
        symbol: this.getSymbolForValue(values[i]),
        value: values[i],
        isSelected: false,
      });
    }

    return choices;
  }

  /**
   * Generate values for pick-em bonus
   * Ensures some high-value items are included
   */
  private static generatePickEmValues(count: number): number[] {
    const values: number[] = [];
    const multipliers = [1, 2, 3, 5, 10, 25, 50];

    for (let i = 0; i < count; i++) {
      // 30% chance of high value (10x+), 50% medium (3-10x), 20% low (1-3x)
      const rand = Math.random();
      let multiplier: number;

      if (rand < 0.3) {
        multiplier = multipliers[Math.floor(Math.random() * 3) + 4]; // 10, 25, 50
      } else if (rand < 0.8) {
        multiplier = multipliers[Math.floor(Math.random() * 3) + 2]; // 3, 5, 10
      } else {
        multiplier = multipliers[Math.floor(Math.random() * 2) + 1]; // 1, 2, 3
      }

      values.push(multiplier);
    }

    return values;
  }

  /**
   * Generate a wheel spin bonus game
   * Player spins a wheel to determine prize
   */
  static generateWheelSpin(betAmount: number): {
    segments: WheelSegment[];
    winningSegmentIndex: number;
  } {
    const segments: WheelSegment[] = [
      { id: 0, label: '2x', multiplier: 2, color: '#FF6B6B' },
      { id: 1, label: '5x', multiplier: 5, color: '#4ECDC4' },
      { id: 2, label: '1x', multiplier: 1, color: '#95E1D3' },
      { id: 3, label: '10x', multiplier: 10, color: '#FFE66D' },
      { id: 4, label: '3x', multiplier: 3, color: '#A8E6CF' },
      { id: 5, label: '25x', multiplier: 25, color: '#FF8B94' },
      { id: 6, label: '2x', multiplier: 2, color: '#B4A7D6' },
      { id: 7, label: '50x', multiplier: 50, color: '#FFD3B6' },
    ];

    // Weighted random selection - higher multipliers less likely
    const winningSegmentIndex = this.selectWheelSegment();

    return { segments, winningSegmentIndex };
  }

  /**
   * Select winning wheel segment with weighted probability
   */
  private static selectWheelSegment(): number {
    const rand = Math.random();

    // Probability distribution
    if (rand < 0.35) return Math.floor(Math.random() * 3); // 1x, 2x, 3x
    if (rand < 0.65) return Math.floor(Math.random() * 2) + 3; // 5x, 10x
    if (rand < 0.90) return 5; // 25x
    return 7; // 50x (10% chance)
  }

  /**
   * Generate free spins bonus
   */
  static generateFreeSpins(
    triggerCount: number
  ): {
    freeSpinsCount: number;
    multiplier: number;
  } {
    // 3 scatters = 10 free spins, 4 = 15, 5 = 20
    let freeSpinsCount = 10;
    let multiplier = 1;

    if (triggerCount >= 5) {
      freeSpinsCount = 20;
      multiplier = 2;
    } else if (triggerCount === 4) {
      freeSpinsCount = 15;
      multiplier = 1.5;
    }

    return { freeSpinsCount, multiplier };
  }

  /**
   * Generate multiplier bonus
   */
  static generateMultiplierBonus(): number {
    const rand = Math.random();

    if (rand < 0.5) return 2;
    if (rand < 0.8) return 3;
    if (rand < 0.95) return 5;
    return 10;
  }

  /**
   * Calculate bonus win amount
   */
  static calculateBonusWin(
    bonusType: BonusType,
    baseAmount: number,
    multiplier: number
  ): number {
    return Math.round(baseAmount * multiplier * 100) / 100;
  }

  /**
   * Get symbol for pick-em value
   */
  private static getSymbolForValue(value: number): string {
    const symbols: { [key: number]: string } = {
      1: '🍒',
      2: '🍋',
      3: '🍊',
      5: '💎',
      10: '⭐',
      25: '👑',
      50: '🏆',
    };

    return symbols[value] || '❓';
  }

  /**
   * Validate bonus completion
   */
  static validateBonusCompletion(
    bonusType: BonusType,
    choices?: BonusChoice[]
  ): { valid: boolean; message: string } {
    if (bonusType === 'pick_em' && choices) {
      const selectedCount = choices.filter((c) => c.isSelected).length;
      if (selectedCount === 0) {
        return { valid: false, message: 'No items selected' };
      }
    }

    return { valid: true, message: 'Bonus valid' };
  }
}

export interface WheelSegment {
  id: number;
  label: string;
  multiplier: number;
  color: string;
}

/**
 * Bonus trigger conditions
 * Determines when a bonus round should be triggered
 */
export class BonusTrigger {
  /**
   * Check if spin triggers a bonus
   */
  static checkTrigger(
    reels: string[][],
    bonusSymbol: string = '🎁'
  ): { triggered: boolean; bonusType: BonusType; scatterCount: number } {
    let scatterCount = 0;

    // Count scatter symbols
    for (const reel of reels) {
      for (const symbol of reel) {
        if (symbol === bonusSymbol) {
          scatterCount++;
        }
      }
    }

    // Trigger conditions
    if (scatterCount >= 5) {
      return { triggered: true, bonusType: 'free_spins', scatterCount };
    } else if (scatterCount === 4) {
      return { triggered: true, bonusType: 'wheel_spin', scatterCount };
    } else if (scatterCount === 3) {
      return { triggered: true, bonusType: 'pick_em', scatterCount };
    }

    return { triggered: false, bonusType: 'pick_em', scatterCount };
  }

  /**
   * Check if bonus round should award multiplier
   */
  static checkMultiplierTrigger(winAmount: number): boolean {
    // 5% chance of multiplier bonus on any win over 100x bet
    return winAmount > 100 && Math.random() < 0.05;
  }
}

/**
 * Bonus round state management
 */
export class BonusRoundState {
  private bonusRound: BonusRound;
  private choices: BonusChoice[] = [];
  private wheelSegments: WheelSegment[] = [];
  private wheelWinningIndex: number = 0;

  constructor(bonusRound: BonusRound) {
    this.bonusRound = bonusRound;
  }

  /**
   * Initialize bonus round based on type
   */
  initialize(difficulty: 'easy' | 'medium' | 'hard' = 'medium'): void {
    switch (this.bonusRound.bonusType) {
      case 'pick_em':
        this.choices = BonusRoundEngine.generatePickEm(
          this.bonusRound.betAmount,
          difficulty
        );
        break;

      case 'wheel_spin':
        const wheel = BonusRoundEngine.generateWheelSpin(this.bonusRound.betAmount);
        this.wheelSegments = wheel.segments;
        this.wheelWinningIndex = wheel.winningSegmentIndex;
        break;

      case 'free_spins':
        // Free spins are handled differently
        break;

      case 'multiplier':
        this.bonusRound.multiplier = BonusRoundEngine.generateMultiplierBonus();
        break;
    }
  }

  /**
   * Make a pick-em selection
   */
  selectPickEm(choiceIndex: number): { value: number; allSelected: boolean } {
    const choice = this.choices[choiceIndex];
    if (!choice) {
      throw new Error('Invalid choice index');
    }

    choice.isSelected = true;
    choice.selectedAt = new Date();

    const allSelected = this.choices.every((c) => c.isSelected);
    return { value: choice.value, allSelected };
  }

  /**
   * Complete wheel spin
   */
  completeWheelSpin(spinsCount: number): number {
    // Simulate wheel spinning and landing on winning segment
    const winningSegment = this.wheelSegments[this.wheelWinningIndex];
    return winningSegment.multiplier;
  }

  /**
   * Get bonus state
   */
  getState(): {
    bonusRound: BonusRound;
    choices?: BonusChoice[];
    wheelSegments?: WheelSegment[];
    wheelWinningIndex?: number;
  } {
    return {
      bonusRound: this.bonusRound,
      choices: this.choices,
      wheelSegments: this.wheelSegments,
      wheelWinningIndex: this.wheelWinningIndex,
    };
  }

  /**
   * Calculate total bonus win
   */
  calculateTotalWin(): number {
    let totalWin = 0;

    switch (this.bonusRound.bonusType) {
      case 'pick_em':
        // Sum all selected pick-em values
        totalWin = this.choices.reduce((sum, choice) => {
          if (choice.isSelected) {
            return sum + BonusRoundEngine.calculateBonusWin('pick_em', this.bonusRound.betAmount, choice.value);
          }
          return sum;
        }, 0);
        break;

      case 'wheel_spin':
        const winningSegment = this.wheelSegments[this.wheelWinningIndex];
        totalWin = BonusRoundEngine.calculateBonusWin(
          'wheel_spin',
          this.bonusRound.betAmount,
          winningSegment.multiplier
        );
        break;

      case 'free_spins':
        // Free spins value calculated during free spin plays
        totalWin = this.bonusRound.bonusWinAmount;
        break;

      case 'multiplier':
        totalWin = BonusRoundEngine.calculateBonusWin(
          'multiplier',
          this.bonusRound.betAmount,
          this.bonusRound.multiplier
        );
        break;
    }

    return totalWin;
  }
}
