import { getDb, creditWallet, writeAuditLog } from './db.ts';
import { eq } from 'drizzle-orm';

export interface ProgressiveJackpot {
  id: number;
  gameId: number;
  currentAmount: number;
  baseAmount: number;
  contributionRate: number;
  lastWinnerUserId?: number;
  lastWinAmount?: number;
  lastWinAt?: Date;
  totalContributed: number;
  createdAt: Date;
  updatedAt: Date;
}

export interface JackpotWin {
  id: number;
  jackpotId: number;
  userId: number;
  winAmount: number;
  spinId: string;
  wonAt: Date;
}

/**
 * Progressive Jackpot Manager
 * Tracks and manages progressive jackpots across all games
 */
export class ProgressiveJackpotManager {
  private jackpots: Map<number, ProgressiveJackpot> = new Map();

  /**
   * Initialize jackpot for a game
   */
  async initializeJackpot(
    gameId: number,
    baseAmount: number = 10000,
    contributionRate: number = 0.01
  ): Promise<ProgressiveJackpot> {
    const db = await getDb();
    if (!db) throw new Error('Database connection failed');

    const jackpot: ProgressiveJackpot = {
      id: gameId, // Use gameId as ID for simplicity
      gameId,
      currentAmount: baseAmount,
      baseAmount,
      contributionRate,
      totalContributed: 0,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.jackpots.set(gameId, jackpot);
    return jackpot;
  }

  /**
   * Get current jackpot amount
   */
  getJackpotAmount(gameId: number): number {
    const jackpot = this.jackpots.get(gameId);
    return jackpot?.currentAmount || 0;
  }

  /**
   * Add bet contribution to jackpot
   */
  addBetContribution(gameId: number, betAmount: number): void {
    const jackpot = this.jackpots.get(gameId);
    if (!jackpot) return;

    const contribution = betAmount * jackpot.contributionRate;
    jackpot.currentAmount += contribution;
    jackpot.totalContributed += contribution;
    jackpot.updatedAt = new Date();
  }

  /**
   * Check if jackpot should be won
   * Probability increases with jackpot size
   */
  checkJackpotWin(gameId: number, betAmount: number): boolean {
    const jackpot = this.jackpots.get(gameId);
    if (!jackpot) return false;

    // Base probability: 0.001% (1 in 100,000)
    // Increases with jackpot size: +0.0001% per $1000
    const baseProbability = 0.00001;
    const sizeBonus = (jackpot.currentAmount - jackpot.baseAmount) / 1000 * 0.000001;
    const totalProbability = baseProbability + sizeBonus;

    return Math.random() < totalProbability;
  }

  /**
   * Win the jackpot
   */
  async winJackpot(
    gameId: number,
    userId: number,
    spinId: string
  ): Promise<{ winAmount: number; newJackpotAmount: number }> {
    const db = await getDb();
    if (!db) throw new Error('Database connection failed');

    const jackpot = this.jackpots.get(gameId);
    if (!jackpot) throw new Error('Jackpot not found');

    const winAmount = jackpot.currentAmount;

    // Credit the winner
    await creditWallet(
      userId,
      'SC',
      winAmount,
      'jackpot_win',
      `Progressive Jackpot Won on Game ${gameId}`,
      String(userId)
    );

    // Log the win
    await writeAuditLog({
      actorId: userId,
      actorRole: 'user',
      action: 'jackpot_win',
      category: 'gaming',
      details: {
        gameId,
        jackpotAmount: winAmount,
        spinId,
      },
    });

    // Update jackpot
    jackpot.lastWinnerUserId = userId;
    jackpot.lastWinAmount = winAmount;
    jackpot.lastWinAt = new Date();
    jackpot.currentAmount = jackpot.baseAmount; // Reset to base
    jackpot.updatedAt = new Date();

    return {
      winAmount,
      newJackpotAmount: jackpot.baseAmount,
    };
  }

  /**
   * Get jackpot statistics
   */
  getJackpotStats(gameId: number): {
    currentAmount: number;
    baseAmount: number;
    totalContributed: number;
    lastWinAmount?: number;
    lastWinAt?: Date;
    timeSinceLastWin?: string;
  } {
    const jackpot = this.jackpots.get(gameId);
    if (!jackpot) {
      return {
        currentAmount: 0,
        baseAmount: 0,
        totalContributed: 0,
      };
    }

    let timeSinceLastWin: string | undefined;
    if (jackpot.lastWinAt) {
      const now = new Date();
      const diffMs = now.getTime() - jackpot.lastWinAt.getTime();
      const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
      const diffHours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));

      if (diffDays > 0) {
        timeSinceLastWin = `${diffDays}d ${diffHours}h ago`;
      } else {
        timeSinceLastWin = `${diffHours}h ago`;
      }
    }

    return {
      currentAmount: jackpot.currentAmount,
      baseAmount: jackpot.baseAmount,
      totalContributed: jackpot.totalContributed,
      lastWinAmount: jackpot.lastWinAmount,
      lastWinAt: jackpot.lastWinAt,
      timeSinceLastWin,
    };
  }

  /**
   * Get all active jackpots
   */
  getAllJackpots(): ProgressiveJackpot[] {
    return Array.from(this.jackpots.values());
  }

  /**
   * Get jackpot leaderboard (largest jackpots)
   */
  getJackpotLeaderboard(limit: number = 10): Array<{
    gameId: number;
    amount: number;
    lastWinAt?: Date;
  }> {
    return Array.from(this.jackpots.values())
      .sort((a, b) => b.currentAmount - a.currentAmount)
      .slice(0, limit)
      .map((j) => ({
        gameId: j.gameId,
        amount: j.currentAmount,
        lastWinAt: j.lastWinAt,
      }));
  }
}

/**
 * Global jackpot manager instance
 */
export const jackpotManager = new ProgressiveJackpotManager();

/**
 * Initialize all game jackpots
 */
export async function initializeAllJackpots(): Promise<void> {
  const gameConfigs = [
    { gameId: 1, baseAmount: 5000, name: 'Classic 3-Reel' },
    { gameId: 2, baseAmount: 10000, name: 'Treasure Quest' },
    { gameId: 3, baseAmount: 15000, name: 'Cosmic Spins' },
    { gameId: 4, baseAmount: 20000, name: "Dragon's Gold" },
    { gameId: 5, baseAmount: 25000, name: 'Lucky 7s' },
  ];

  for (const config of gameConfigs) {
    await jackpotManager.initializeJackpot(config.gameId, config.baseAmount);
  }
}

/**
 * Jackpot notification system
 */
export interface JackpotNotification {
  type: 'update' | 'win' | 'milestone';
  gameId: number;
  amount: number;
  message: string;
  timestamp: Date;
}

export class JackpotNotificationManager {
  private listeners: Map<number, (notification: JackpotNotification) => void> = new Map();

  /**
   * Subscribe to jackpot updates for a game
   */
  subscribe(gameId: number, callback: (notification: JackpotNotification) => void): void {
    this.listeners.set(gameId, callback);
  }

  /**
   * Unsubscribe from jackpot updates
   */
  unsubscribe(gameId: number): void {
    this.listeners.delete(gameId);
  }

  /**
   * Notify listeners of jackpot update
   */
  notifyUpdate(gameId: number, amount: number): void {
    const callback = this.listeners.get(gameId);
    if (callback) {
      callback({
        type: 'update',
        gameId,
        amount,
        message: `Jackpot updated to ${amount.toFixed(2)} SC`,
        timestamp: new Date(),
      });
    }
  }

  /**
   * Notify listeners of jackpot win
   */
  notifyWin(gameId: number, amount: number, winnerName: string): void {
    const callback = this.listeners.get(gameId);
    if (callback) {
      callback({
        type: 'win',
        gameId,
        amount,
        message: `🎉 ${winnerName} won ${amount.toFixed(2)} SC!`,
        timestamp: new Date(),
      });
    }
  }

  /**
   * Notify listeners of milestone reached
   */
  notifyMilestone(gameId: number, amount: number, milestone: number): void {
    const callback = this.listeners.get(gameId);
    if (callback) {
      callback({
        type: 'milestone',
        gameId,
        amount,
        message: `🚀 Jackpot reached ${milestone.toFixed(0)} SC!`,
        timestamp: new Date(),
      });
    }
  }
}

export const jackpotNotificationManager = new JackpotNotificationManager();
