import { EventEmitter } from 'events';

export interface GameMetadata {
  id: string;
  name: string;
  description: string;
  category: 'slots' | 'table' | 'live' | 'arcade' | 'specialty' | 'other';
  provider: string;
  version: string;
  releaseDate: Date;
  thumbnail: string;
  isActive: boolean;
  minBet: number;
  maxBet: number;
  rtp: number; // Return to Player percentage
  volatility: 'low' | 'medium' | 'high';
  features: string[];
  paylines?: number;
  reels?: number;
  bonusRounds: boolean;
  freeSpins: boolean;
  progressiveJackpot: boolean;
  multiplayer: boolean;
  mobileSupported: boolean;
  tags: string[];
  createdAt: Date;
  updatedAt: Date;
  statistics?: {
    totalPlays: number;
    totalWins: number;
    averageWin: number;
    playerCount: number;
    rating: number;
  };
}

export interface GameLibrary {
  totalGames: number;
  activeGames: number;
  gamesByCategory: Record<string, number>;
  gamesByProvider: Record<string, number>;
  averageRTP: number;
  totalPlayCount: number;
}

class GameLibraryManagementSystem extends EventEmitter {
  private games = new Map<string, GameMetadata>();
  private gameIndex = new Map<string, string[]>(); // For category/provider indexing

  /**
   * Add game to library
   */
  addGame(game: Omit<GameMetadata, 'id' | 'createdAt' | 'updatedAt'>): GameMetadata {
    const id = `game_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const fullGame: GameMetadata = {
      ...game,
      id,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.games.set(id, fullGame);
    this.indexGame(fullGame);
    this.emit('game:added', fullGame);
    return fullGame;
  }

  /**
   * Update game metadata
   */
  updateGame(gameId: string, updates: Partial<GameMetadata>): GameMetadata | null {
    const game = this.games.get(gameId);
    if (!game) return null;

    const updated: GameMetadata = {
      ...game,
      ...updates,
      updatedAt: new Date(),
    };

    this.games.set(gameId, updated);
    this.emit('game:updated', updated);
    return updated;
  }

  /**
   * Remove game from library
   */
  removeGame(gameId: string): boolean {
    const game = this.games.get(gameId);
    if (!game) return false;

    this.games.delete(gameId);
    this.emit('game:removed', gameId);
    return true;
  }

  /**
   * Get game by ID
   */
  getGame(gameId: string): GameMetadata | null {
    return this.games.get(gameId) || null;
  }

  /**
   * List all games
   */
  listAllGames(): GameMetadata[] {
    return Array.from(this.games.values());
  }

  /**
   * List active games
   */
  listActiveGames(): GameMetadata[] {
    return Array.from(this.games.values()).filter(g => g.isActive);
  }

  /**
   * Filter games by category
   */
  getGamesByCategory(category: string): GameMetadata[] {
    return Array.from(this.games.values()).filter(g => g.category === category);
  }

  /**
   * Filter games by provider
   */
  getGamesByProvider(provider: string): GameMetadata[] {
    return Array.from(this.games.values()).filter(g => g.provider === provider);
  }

  /**
   * Search games
   */
  searchGames(query: string): GameMetadata[] {
    const lowerQuery = query.toLowerCase();
    return Array.from(this.games.values()).filter(
      g =>
        g.name.toLowerCase().includes(lowerQuery) ||
        g.description.toLowerCase().includes(lowerQuery) ||
        g.tags.some(t => t.toLowerCase().includes(lowerQuery))
    );
  }

  /**
   * Filter games by criteria
   */
  filterGames(criteria: {
    category?: string;
    provider?: string;
    minRTP?: number;
    maxRTP?: number;
    volatility?: string;
    bonusRounds?: boolean;
    freeSpins?: boolean;
    progressiveJackpot?: boolean;
    multiplayer?: boolean;
    mobileSupported?: boolean;
    isActive?: boolean;
  }): GameMetadata[] {
    return Array.from(this.games.values()).filter(g => {
      if (criteria.category && g.category !== criteria.category) return false;
      if (criteria.provider && g.provider !== criteria.provider) return false;
      if (criteria.minRTP && g.rtp < criteria.minRTP) return false;
      if (criteria.maxRTP && g.rtp > criteria.maxRTP) return false;
      if (criteria.volatility && g.volatility !== criteria.volatility) return false;
      if (criteria.bonusRounds !== undefined && g.bonusRounds !== criteria.bonusRounds) return false;
      if (criteria.freeSpins !== undefined && g.freeSpins !== criteria.freeSpins) return false;
      if (criteria.progressiveJackpot !== undefined && g.progressiveJackpot !== criteria.progressiveJackpot)
        return false;
      if (criteria.multiplayer !== undefined && g.multiplayer !== criteria.multiplayer) return false;
      if (criteria.mobileSupported !== undefined && g.mobileSupported !== criteria.mobileSupported) return false;
      if (criteria.isActive !== undefined && g.isActive !== criteria.isActive) return false;
      return true;
    });
  }

  /**
   * Get game library statistics
   */
  getLibraryStats(): GameLibrary {
    const games = Array.from(this.games.values());
    const activeGames = games.filter(g => g.isActive);

    const gamesByCategory: Record<string, number> = {};
    const gamesByProvider: Record<string, number> = {};
    let totalRTP = 0;
    let totalPlayCount = 0;

    games.forEach(g => {
      gamesByCategory[g.category] = (gamesByCategory[g.category] || 0) + 1;
      gamesByProvider[g.provider] = (gamesByProvider[g.provider] || 0) + 1;
      totalRTP += g.rtp;
      if (g.statistics) {
        totalPlayCount += g.statistics.totalPlays;
      }
    });

    return {
      totalGames: games.length,
      activeGames: activeGames.length,
      gamesByCategory,
      gamesByProvider,
      averageRTP: games.length > 0 ? totalRTP / games.length : 0,
      totalPlayCount,
    };
  }

  /**
   * Get top games by play count
   */
  getTopGamesByPlayCount(limit: number = 10): GameMetadata[] {
    return Array.from(this.games.values())
      .sort((a, b) => (b.statistics?.totalPlays || 0) - (a.statistics?.totalPlays || 0))
      .slice(0, limit);
  }

  /**
   * Get top games by rating
   */
  getTopGamesByRating(limit: number = 10): GameMetadata[] {
    return Array.from(this.games.values())
      .sort((a, b) => (b.statistics?.rating || 0) - (a.statistics?.rating || 0))
      .slice(0, limit);
  }

  /**
   * Get games by RTP range
   */
  getGamesByRTPRange(minRTP: number, maxRTP: number): GameMetadata[] {
    return Array.from(this.games.values()).filter(g => g.rtp >= minRTP && g.rtp <= maxRTP);
  }

  /**
   * Bulk update games
   */
  bulkUpdateGames(gameIds: string[], updates: Partial<GameMetadata>): GameMetadata[] {
    const updated: GameMetadata[] = [];

    gameIds.forEach(gameId => {
      const game = this.updateGame(gameId, updates);
      if (game) updated.push(game);
    });

    this.emit('games:bulkUpdated', { count: updated.length, updates });
    return updated;
  }

  /**
   * Activate/Deactivate games
   */
  setGameActive(gameId: string, active: boolean): GameMetadata | null {
    return this.updateGame(gameId, { isActive: active });
  }

  /**
   * Bulk activate/deactivate
   */
  bulkSetGameActive(gameIds: string[], active: boolean): GameMetadata[] {
    return this.bulkUpdateGames(gameIds, { isActive: active });
  }

  /**
   * Update game statistics
   */
  updateGameStats(
    gameId: string,
    stats: Partial<GameMetadata['statistics']>
  ): GameMetadata | null {
    const game = this.getGame(gameId);
    if (!game) return null;

    return this.updateGame(gameId, {
      statistics: {
        ...game.statistics,
        ...stats,
      },
    });
  }

  /**
   * Export game library
   */
  exportGameLibrary(format: 'json' | 'csv' = 'json'): string {
    const games = Array.from(this.games.values());

    if (format === 'json') {
      return JSON.stringify(games, null, 2);
    }

    // CSV format
    const headers = ['ID', 'Name', 'Category', 'Provider', 'RTP', 'Active', 'Mobile', 'Bonus', 'Free Spins'];
    const rows = games.map(g => [
      g.id,
      g.name,
      g.category,
      g.provider,
      g.rtp,
      g.isActive,
      g.mobileSupported,
      g.bonusRounds,
      g.freeSpins,
    ]);

    return [headers, ...rows].map(row => row.map(cell => `"${cell}"`).join(',')).join('\n');
  }

  /**
   * Import games from JSON
   */
  importGamesFromJSON(jsonData: string): GameMetadata[] {
    const games = JSON.parse(jsonData);
    const imported: GameMetadata[] = [];

    games.forEach((game: any) => {
      const newGame = this.addGame({
        name: game.name,
        description: game.description,
        category: game.category,
        provider: game.provider,
        version: game.version,
        releaseDate: new Date(game.releaseDate),
        thumbnail: game.thumbnail,
        isActive: game.isActive,
        minBet: game.minBet,
        maxBet: game.maxBet,
        rtp: game.rtp,
        volatility: game.volatility,
        features: game.features,
        paylines: game.paylines,
        reels: game.reels,
        bonusRounds: game.bonusRounds,
        freeSpins: game.freeSpins,
        progressiveJackpot: game.progressiveJackpot,
        multiplayer: game.multiplayer,
        mobileSupported: game.mobileSupported,
        tags: game.tags,
      });
      imported.push(newGame);
    });

    this.emit('games:imported', { count: imported.length });
    return imported;
  }

  /**
   * Private: Index game for faster lookups
   */
  private indexGame(game: GameMetadata): void {
    const categoryKey = `category:${game.category}`;
    const providerKey = `provider:${game.provider}`;

    if (!this.gameIndex.has(categoryKey)) {
      this.gameIndex.set(categoryKey, []);
    }
    if (!this.gameIndex.has(providerKey)) {
      this.gameIndex.set(providerKey, []);
    }

    this.gameIndex.get(categoryKey)!.push(game.id);
    this.gameIndex.get(providerKey)!.push(game.id);
  }
}

export const gameLibraryManagementSystem = new GameLibraryManagementSystem();
