/**
 * Leaderboard Notifications System
 * Real-time notifications for leaderboard rank changes and bonus triggers
 */

import { EventEmitter } from 'events';

export type NotificationType = 'rank_up' | 'rank_down' | 'top_10' | 'top_50' | 'top_100' | 'bonus_trigger' | 'milestone';

export interface LeaderboardNotification {
  id: string;
  userId: number;
  type: NotificationType;
  gameId: string;
  period: 'daily' | 'weekly' | 'monthly' | 'alltime';
  oldRank?: number;
  newRank?: number;
  message: string;
  timestamp: Date;
  read: boolean;
}

export interface BonusNotification {
  id: string;
  userId: number;
  bonusType: string;
  gameId: string;
  multiplier: number;
  message: string;
  timestamp: Date;
  read: boolean;
}

class LeaderboardNotificationsService extends EventEmitter {
  private notifications: Map<number, LeaderboardNotification[]> = new Map();
  private bonusNotifications: Map<number, BonusNotification[]> = new Map();
  private maxNotifications = 100;

  /**
   * Notify player of rank up
   */
  notifyRankUp(userId: number, gameId: string, period: string, oldRank: number, newRank: number) {
    const notification: LeaderboardNotification = {
      id: `rankup_${userId}_${gameId}_${Date.now()}`,
      userId,
      type: 'rank_up',
      gameId,
      period: period as any,
      oldRank,
      newRank,
      message: `🎉 You moved up from rank #${oldRank} to #${newRank} on the ${gameId} leaderboard!`,
      timestamp: new Date(),
      read: false,
    };

    this.addNotification(userId, notification);
    this.emit('rankup', notification);
  }

  /**
   * Notify player of rank down
   */
  notifyRankDown(userId: number, gameId: string, period: string, oldRank: number, newRank: number) {
    const notification: LeaderboardNotification = {
      id: `rankdown_${userId}_${gameId}_${Date.now()}`,
      userId,
      type: 'rank_down',
      gameId,
      period: period as any,
      oldRank,
      newRank,
      message: `📉 You moved down from rank #${oldRank} to #${newRank} on the ${gameId} leaderboard.`,
      timestamp: new Date(),
      read: false,
    };

    this.addNotification(userId, notification);
    this.emit('rankdown', notification);
  }

  /**
   * Notify player of entering top 10
   */
  notifyTopTen(userId: number, gameId: string, period: string, rank: number) {
    const notification: LeaderboardNotification = {
      id: `top10_${userId}_${gameId}_${Date.now()}`,
      userId,
      type: 'top_10',
      gameId,
      period: period as any,
      newRank: rank,
      message: `🏆 Congratulations! You're now in the top 10 on ${gameId}! Rank: #${rank}`,
      timestamp: new Date(),
      read: false,
    };

    this.addNotification(userId, notification);
    this.emit('top10', notification);
  }

  /**
   * Notify player of entering top 50
   */
  notifyTopFifty(userId: number, gameId: string, period: string, rank: number) {
    const notification: LeaderboardNotification = {
      id: `top50_${userId}_${gameId}_${Date.now()}`,
      userId,
      type: 'top_50',
      gameId,
      period: period as any,
      newRank: rank,
      message: `⭐ You're now in the top 50 on ${gameId}! Rank: #${rank}`,
      timestamp: new Date(),
      read: false,
    };

    this.addNotification(userId, notification);
    this.emit('top50', notification);
  }

  /**
   * Notify player of entering top 100
   */
  notifyTopHundred(userId: number, gameId: string, period: string, rank: number) {
    const notification: LeaderboardNotification = {
      id: `top100_${userId}_${gameId}_${Date.now()}`,
      userId,
      type: 'top_100',
      gameId,
      period: period as any,
      newRank: rank,
      message: `✨ You're now in the top 100 on ${gameId}! Rank: #${rank}`,
      timestamp: new Date(),
      read: false,
    };

    this.addNotification(userId, notification);
    this.emit('top100', notification);
  }

  /**
   * Notify player of bonus trigger
   */
  notifyBonusTriggered(userId: number, bonusType: string, gameId: string, multiplier: number) {
    const notification: BonusNotification = {
      id: `bonus_${userId}_${gameId}_${Date.now()}`,
      userId,
      bonusType,
      gameId,
      multiplier,
      message: `🎁 Bonus triggered! ${bonusType.replace('-', ' ')} with ${multiplier.toFixed(2)}x multiplier!`,
      timestamp: new Date(),
      read: false,
    };

    this.addBonusNotification(userId, notification);
    this.emit('bonus', notification);
  }

  /**
   * Notify player of milestone
   */
  notifyMilestone(userId: number, gameId: string, milestone: string) {
    const notification: LeaderboardNotification = {
      id: `milestone_${userId}_${gameId}_${Date.now()}`,
      userId,
      type: 'milestone',
      gameId,
      period: 'alltime',
      message: `🎯 Milestone reached: ${milestone}!`,
      timestamp: new Date(),
      read: false,
    };

    this.addNotification(userId, notification);
    this.emit('milestone', notification);
  }

  /**
   * Add notification to user's list
   */
  private addNotification(userId: number, notification: LeaderboardNotification) {
    if (!this.notifications.has(userId)) {
      this.notifications.set(userId, []);
    }

    const userNotifications = this.notifications.get(userId)!;
    userNotifications.unshift(notification);

    // Keep only recent notifications
    if (userNotifications.length > this.maxNotifications) {
      userNotifications.pop();
    }
  }

  /**
   * Add bonus notification to user's list
   */
  private addBonusNotification(userId: number, notification: BonusNotification) {
    if (!this.bonusNotifications.has(userId)) {
      this.bonusNotifications.set(userId, []);
    }

    const userNotifications = this.bonusNotifications.get(userId)!;
    userNotifications.unshift(notification);

    // Keep only recent notifications
    if (userNotifications.length > this.maxNotifications) {
      userNotifications.pop();
    }
  }

  /**
   * Get notifications for user
   */
  getNotifications(userId: number, limit: number = 50): LeaderboardNotification[] {
    const notifications = this.notifications.get(userId) || [];
    return notifications.slice(0, limit);
  }

  /**
   * Get bonus notifications for user
   */
  getBonusNotifications(userId: number, limit: number = 50): BonusNotification[] {
    const notifications = this.bonusNotifications.get(userId) || [];
    return notifications.slice(0, limit);
  }

  /**
   * Get unread notification count
   */
  getUnreadCount(userId: number): number {
    const leaderboardNotifs = this.notifications.get(userId) || [];
    const bonusNotifs = this.bonusNotifications.get(userId) || [];

    const unreadLeaderboard = leaderboardNotifs.filter((n) => !n.read).length;
    const unreadBonus = bonusNotifs.filter((n) => !n.read).length;

    return unreadLeaderboard + unreadBonus;
  }

  /**
   * Mark notification as read
   */
  markAsRead(userId: number, notificationId: string) {
    const notifications = this.notifications.get(userId) || [];
    const notification = notifications.find((n) => n.id === notificationId);
    if (notification) {
      notification.read = true;
    }

    const bonusNotifications = this.bonusNotifications.get(userId) || [];
    const bonusNotif = bonusNotifications.find((n) => n.id === notificationId);
    if (bonusNotif) {
      bonusNotif.read = true;
    }
  }

  /**
   * Mark all notifications as read
   */
  markAllAsRead(userId: number) {
    const notifications = this.notifications.get(userId) || [];
    notifications.forEach((n) => (n.read = true));

    const bonusNotifications = this.bonusNotifications.get(userId) || [];
    bonusNotifications.forEach((n) => (n.read = true));
  }

  /**
   * Clear notifications for user
   */
  clearNotifications(userId: number) {
    this.notifications.delete(userId);
    this.bonusNotifications.delete(userId);
  }

  /**
   * Get all notifications (leaderboard + bonus)
   */
  getAllNotifications(userId: number, limit: number = 100) {
    const leaderboardNotifs = this.getNotifications(userId, limit);
    const bonusNotifs = this.getBonusNotifications(userId, limit);

    // Combine and sort by timestamp
    const combined = [
      ...leaderboardNotifs.map((n) => ({ ...n, category: 'leaderboard' })),
      ...bonusNotifs.map((n) => ({ ...n, category: 'bonus' })),
    ];

    return combined.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()).slice(0, limit);
  }
}

// Export singleton instance
export const leaderboardNotifications = new LeaderboardNotificationsService();
