import { EventEmitter } from 'events';

export interface Achievement {
  id: string;
  name: string;
  description: string;
  icon: string;
  rarity: 'common' | 'rare' | 'epic' | 'legendary';
  reward?: {
    coins?: number;
    xp?: number;
    badge?: string;
  };
  unlockedAt?: Date;
}

export interface AchievementUnlockEvent {
  userId: string;
  achievement: Achievement;
  timestamp: Date;
  notificationSent: boolean;
  shareCount: number;
}

export interface MilestoneEvent {
  userId: string;
  type: 'level' | 'wins' | 'score' | 'streak';
  value: number;
  previousValue: number;
  timestamp: Date;
}

class AchievementUnlockSystem extends EventEmitter {
  private unlocks: Map<string, AchievementUnlockEvent[]> = new Map();
  private milestones: Map<string, MilestoneEvent[]> = new Map();
  private shareStats: Map<string, Record<string, number>> = new Map();

  /**
   * Record an achievement unlock
   */
  recordUnlock(userId: string, achievement: Achievement): AchievementUnlockEvent {
    const event: AchievementUnlockEvent = {
      userId,
      achievement: {
        ...achievement,
        unlockedAt: new Date(),
      },
      timestamp: new Date(),
      notificationSent: false,
      shareCount: 0,
    };

    if (!this.unlocks.has(userId)) {
      this.unlocks.set(userId, []);
    }
    this.unlocks.get(userId)!.push(event);

    // Emit event for real-time updates
    this.emit('achievement-unlocked', event);

    return event;
  }

  /**
   * Record a milestone achievement
   */
  recordMilestone(userId: string, milestone: MilestoneEvent): MilestoneEvent {
    const event: MilestoneEvent = {
      ...milestone,
      timestamp: new Date(),
    };

    if (!this.milestones.has(userId)) {
      this.milestones.set(userId, []);
    }
    this.milestones.get(userId)!.push(event);

    // Emit event for real-time updates
    this.emit('milestone-reached', event);

    return event;
  }

  /**
   * Track achievement shares
   */
  trackShare(userId: string, achievementId: string, platform: string): void {
    if (!this.shareStats.has(userId)) {
      this.shareStats.set(userId, {});
    }

    const stats = this.shareStats.get(userId)!;
    const key = `${achievementId}-${platform}`;
    stats[key] = (stats[key] || 0) + 1;

    // Update unlock share count
    const unlocks = this.unlocks.get(userId) || [];
    const unlock = unlocks.find(u => u.achievement.id === achievementId);
    if (unlock) {
      unlock.shareCount++;
    }

    this.emit('achievement-shared', {
      userId,
      achievementId,
      platform,
      timestamp: new Date(),
    });
  }

  /**
   * Get all unlocks for a user
   */
  getUserUnlocks(userId: string): AchievementUnlockEvent[] {
    return this.unlocks.get(userId) || [];
  }

  /**
   * Get all milestones for a user
   */
  getUserMilestones(userId: string): MilestoneEvent[] {
    return this.milestones.get(userId) || [];
  }

  /**
   * Get share statistics for a user
   */
  getShareStats(userId: string): Record<string, number> {
    return this.shareStats.get(userId) || {};
  }

  /**
   * Get most shared achievements
   */
  getMostSharedAchievements(limit: number = 10): Array<{
    achievementId: string;
    totalShares: number;
    platforms: Record<string, number>;
  }> {
    const stats: Record<
      string,
      { totalShares: number; platforms: Record<string, number> }
    > = {};

    for (const userStats of this.shareStats.values()) {
      for (const [key, count] of Object.entries(userStats)) {
        const [achievementId, platform] = key.split('-');
        if (!stats[achievementId]) {
          stats[achievementId] = { totalShares: 0, platforms: {} };
        }
        stats[achievementId].totalShares += count;
        stats[achievementId].platforms[platform] =
          (stats[achievementId].platforms[platform] || 0) + count;
      }
    }

    return Object.entries(stats)
      .map(([achievementId, data]) => ({
        achievementId,
        ...data,
      }))
      .sort((a, b) => b.totalShares - a.totalShares)
      .slice(0, limit);
  }

  /**
   * Check if user has unlocked an achievement
   */
  hasUnlocked(userId: string, achievementId: string): boolean {
    const unlocks = this.unlocks.get(userId) || [];
    return unlocks.some(u => u.achievement.id === achievementId);
  }

  /**
   * Get unlock count for a user
   */
  getUnlockCount(userId: string): number {
    return (this.unlocks.get(userId) || []).length;
  }

  /**
   * Get recent unlocks across all users
   */
  getRecentUnlocks(limit: number = 20): AchievementUnlockEvent[] {
    const allUnlocks: AchievementUnlockEvent[] = [];
    for (const unlocks of this.unlocks.values()) {
      allUnlocks.push(...unlocks);
    }
    return allUnlocks
      .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
      .slice(0, limit);
  }

  /**
   * Get achievement unlock statistics
   */
  getUnlockStats(): {
    totalUnlocks: number;
    uniqueAchievements: Set<string>;
    byRarity: Record<string, number>;
    averageUnlocksPerUser: number;
  } {
    let totalUnlocks = 0;
    const uniqueAchievements = new Set<string>();
    const byRarity: Record<string, number> = {
      common: 0,
      rare: 0,
      epic: 0,
      legendary: 0,
    };

    for (const unlocks of this.unlocks.values()) {
      totalUnlocks += unlocks.length;
      for (const unlock of unlocks) {
        uniqueAchievements.add(unlock.achievement.id);
        byRarity[unlock.achievement.rarity]++;
      }
    }

    const userCount = this.unlocks.size;
    const averageUnlocksPerUser = userCount > 0 ? totalUnlocks / userCount : 0;

    return {
      totalUnlocks,
      uniqueAchievements,
      byRarity,
      averageUnlocksPerUser,
    };
  }

  /**
   * Send unlock notification
   */
  sendNotification(userId: string, achievementId: string): boolean {
    const unlocks = this.unlocks.get(userId) || [];
    const unlock = unlocks.find(u => u.achievement.id === achievementId);

    if (unlock && !unlock.notificationSent) {
      unlock.notificationSent = true;
      this.emit('notification-sent', {
        userId,
        achievementId,
        timestamp: new Date(),
      });
      return true;
    }

    return false;
  }

  /**
   * Clear all data (for testing)
   */
  clear(): void {
    this.unlocks.clear();
    this.milestones.clear();
    this.shareStats.clear();
  }
}

export const achievementUnlockSystem = new AchievementUnlockSystem();
