/**
 * Redis Caching System
 * Performance optimization with Redis caching for leaderboards, analytics, and real-time data
 */

export type CacheKeyType = 'leaderboard' | 'analytics' | 'player' | 'game' | 'tournament' | 'session';
export type CacheTTL = 'short' | 'medium' | 'long' | 'permanent';

export interface CacheEntry<T = any> {
  key: string;
  value: T;
  ttl: number; // seconds
  createdAt: Date;
  expiresAt: Date;
  hits: number;
  keyType: CacheKeyType;
}

export interface CacheStats {
  totalKeys: number;
  hitRate: number; // percentage
  missRate: number; // percentage
  totalHits: number;
  totalMisses: number;
  memoryUsage: number; // bytes
  averageResponseTime: number; // ms
}

export interface CacheConfig {
  host: string;
  port: number;
  password?: string;
  db: number;
  maxMemory: string; // e.g., "256mb"
  evictionPolicy: 'allkeys-lru' | 'allkeys-lfu' | 'volatile-lru' | 'volatile-lfu' | 'volatile-ttl';
  enableCompression: boolean;
}

/**
 * Cache TTL configuration
 */
export const CACHE_TTL_CONFIG: Record<CacheTTL, number> = {
  short: 60, // 1 minute
  medium: 300, // 5 minutes
  long: 3600, // 1 hour
  permanent: 86400 * 30, // 30 days
};

/**
 * Create cache entry
 */
export function createCacheEntry<T>(
  key: string,
  value: T,
  ttl: CacheTTL,
  keyType: CacheKeyType
): CacheEntry<T> {
  const ttlSeconds = CACHE_TTL_CONFIG[ttl];
  const now = new Date();
  const expiresAt = new Date(now.getTime() + ttlSeconds * 1000);

  return {
    key,
    value,
    ttl: ttlSeconds,
    createdAt: now,
    expiresAt,
    hits: 0,
    keyType,
  };
}

/**
 * Cache key generators
 */
export const CacheKeyGenerators = {
  leaderboard: (gameId: string, period: string): string =>
    `leaderboard:${gameId}:${period}`,

  playerStats: (playerId: number): string =>
    `player:${playerId}:stats`,

  playerBalance: (playerId: number): string =>
    `player:${playerId}:balance`,

  gameDetails: (gameId: string): string =>
    `game:${gameId}:details`,

  tournamentLeaderboard: (tournamentId: string): string =>
    `tournament:${tournamentId}:leaderboard`,

  sessionData: (sessionId: string): string =>
    `session:${sessionId}:data`,

  analyticsReport: (period: string): string =>
    `analytics:${period}:report`,

  userSessions: (userId: number): string =>
    `user:${userId}:sessions`,

  gameStats: (gameId: string): string =>
    `game:${gameId}:stats`,

  topPlayers: (limit: number): string =>
    `top:players:${limit}`,

  activeGames: (): string =>
    'active:games',

  systemHealth: (): string =>
    'system:health',
};

/**
 * Cache invalidation patterns
 */
export const CacheInvalidationPatterns = {
  playerUpdated: (playerId: number): string[] => [
    CacheKeyGenerators.playerStats(playerId),
    CacheKeyGenerators.playerBalance(playerId),
    CacheKeyGenerators.userSessions(playerId),
  ],

  gameUpdated: (gameId: string): string[] => [
    CacheKeyGenerators.gameDetails(gameId),
    CacheKeyGenerators.gameStats(gameId),
    CacheKeyGenerators.activeGames(),
  ],

  leaderboardUpdated: (gameId: string): string[] => [
    CacheKeyGenerators.leaderboard(gameId, 'daily'),
    CacheKeyGenerators.leaderboard(gameId, 'weekly'),
    CacheKeyGenerators.leaderboard(gameId, 'monthly'),
    CacheKeyGenerators.leaderboard(gameId, 'alltime'),
    CacheKeyGenerators.topPlayers(10),
    CacheKeyGenerators.topPlayers(50),
    CacheKeyGenerators.topPlayers(100),
  ],

  tournamentUpdated: (tournamentId: string): string[] => [
    CacheKeyGenerators.tournamentLeaderboard(tournamentId),
  ],

  analyticsUpdated: (): string[] => [
    CacheKeyGenerators.analyticsReport('daily'),
    CacheKeyGenerators.analyticsReport('weekly'),
    CacheKeyGenerators.analyticsReport('monthly'),
  ],
};

/**
 * Cache statistics tracker
 */
export class CacheStatsTracker {
  private totalHits = 0;
  private totalMisses = 0;
  private responseTimes: number[] = [];

  recordHit(): void {
    this.totalHits++;
  }

  recordMiss(): void {
    this.totalMisses++;
  }

  recordResponseTime(ms: number): void {
    this.responseTimes.push(ms);
    if (this.responseTimes.length > 10000) {
      this.responseTimes.shift();
    }
  }

  getStats(memoryUsage: number): CacheStats {
    const total = this.totalHits + this.totalMisses;
    const hitRate = total > 0 ? (this.totalHits / total) * 100 : 0;
    const missRate = total > 0 ? (this.totalMisses / total) * 100 : 0;
    const avgResponseTime =
      this.responseTimes.length > 0
        ? this.responseTimes.reduce((a, b) => a + b, 0) / this.responseTimes.length
        : 0;

    return {
      totalKeys: total,
      hitRate,
      missRate,
      totalHits: this.totalHits,
      totalMisses: this.totalMisses,
      memoryUsage,
      averageResponseTime: avgResponseTime,
    };
  }

  reset(): void {
    this.totalHits = 0;
    this.totalMisses = 0;
    this.responseTimes = [];
  }
}

/**
 * Leaderboard caching
 */
export interface LeaderboardCache {
  gameId: string;
  period: 'daily' | 'weekly' | 'monthly' | 'alltime';
  rankings: Array<{
    rank: number;
    playerId: number;
    username: string;
    score: number;
  }>;
  lastUpdated: Date;
  expiresAt: Date;
}

export function createLeaderboardCache(
  gameId: string,
  period: 'daily' | 'weekly' | 'monthly' | 'alltime',
  rankings: Array<{ rank: number; playerId: number; username: string; score: number }>
): LeaderboardCache {
  const ttl = CACHE_TTL_CONFIG.medium; // 5 minutes for leaderboards
  const now = new Date();

  return {
    gameId,
    period,
    rankings,
    lastUpdated: now,
    expiresAt: new Date(now.getTime() + ttl * 1000),
  };
}

/**
 * Analytics caching
 */
export interface AnalyticsCache {
  period: 'daily' | 'weekly' | 'monthly';
  totalPlayers: number;
  activePlayers: number;
  totalRevenue: number;
  newPlayers: number;
  churnRate: number;
  lastUpdated: Date;
  expiresAt: Date;
}

export function createAnalyticsCache(
  period: 'daily' | 'weekly' | 'monthly',
  totalPlayers: number,
  activePlayers: number,
  totalRevenue: number,
  newPlayers: number,
  churnRate: number
): AnalyticsCache {
  const ttl = CACHE_TTL_CONFIG.long; // 1 hour for analytics
  const now = new Date();

  return {
    period,
    totalPlayers,
    activePlayers,
    totalRevenue,
    newPlayers,
    churnRate,
    lastUpdated: now,
    expiresAt: new Date(now.getTime() + ttl * 1000),
  };
}

/**
 * Session caching
 */
export interface SessionCache {
  sessionId: string;
  playerId: number;
  username: string;
  loginTime: Date;
  lastActivityTime: Date;
  expiresAt: Date;
  data: Record<string, any>;
}

export function createSessionCache(
  sessionId: string,
  playerId: number,
  username: string,
  data: Record<string, any> = {}
): SessionCache {
  const ttl = CACHE_TTL_CONFIG.medium; // 5 minutes for sessions
  const now = new Date();

  return {
    sessionId,
    playerId,
    username,
    loginTime: now,
    lastActivityTime: now,
    expiresAt: new Date(now.getTime() + ttl * 1000),
    data,
  };
}

/**
 * Cache warming strategies
 */
export interface CacheWarmingStrategy {
  name: string;
  description: string;
  keys: string[];
  frequency: string; // cron expression
  priority: 'high' | 'medium' | 'low';
}

export const CACHE_WARMING_STRATEGIES: CacheWarmingStrategy[] = [
  {
    name: 'Top Leaderboards',
    description: 'Warm cache with top 10, 50, 100 players for each game',
    keys: [
      CacheKeyGenerators.topPlayers(10),
      CacheKeyGenerators.topPlayers(50),
      CacheKeyGenerators.topPlayers(100),
    ],
    frequency: '*/5 * * * *', // Every 5 minutes
    priority: 'high',
  },
  {
    name: 'Daily Analytics',
    description: 'Warm cache with daily analytics report',
    keys: [CacheKeyGenerators.analyticsReport('daily')],
    frequency: '0 1 * * *', // 1 AM daily
    priority: 'high',
  },
  {
    name: 'Active Games',
    description: 'Warm cache with active games list',
    keys: [CacheKeyGenerators.activeGames()],
    frequency: '*/10 * * * *', // Every 10 minutes
    priority: 'medium',
  },
  {
    name: 'System Health',
    description: 'Warm cache with system health metrics',
    keys: [CacheKeyGenerators.systemHealth()],
    frequency: '*/1 * * * *', // Every minute
    priority: 'high',
  },
];

/**
 * Cache eviction policies
 */
export interface EvictionPolicy {
  name: string;
  description: string;
  algorithm: 'LRU' | 'LFU' | 'TTL' | 'FIFO';
  maxMemory: string;
}

export const EVICTION_POLICIES: EvictionPolicy[] = [
  {
    name: 'allkeys-lru',
    description: 'Evict any key using LRU when max memory is reached',
    algorithm: 'LRU',
    maxMemory: '256mb',
  },
  {
    name: 'volatile-lru',
    description: 'Evict keys with TTL using LRU when max memory is reached',
    algorithm: 'LRU',
    maxMemory: '256mb',
  },
  {
    name: 'allkeys-lfu',
    description: 'Evict any key using LFU when max memory is reached',
    algorithm: 'LFU',
    maxMemory: '512mb',
  },
];

/**
 * Cache health monitoring
 */
export interface CacheHealth {
  status: 'healthy' | 'degraded' | 'offline';
  uptime: number; // percentage
  memoryUsage: number; // percentage
  evictionRate: number; // evictions per second
  responseTime: number; // ms
  lastCheck: Date;
}

export function checkCacheHealth(
  uptime: number,
  memoryUsage: number,
  evictionRate: number,
  responseTime: number
): CacheHealth {
  let status: 'healthy' | 'degraded' | 'offline' = 'healthy';

  if (uptime < 50) {
    status = 'offline';
  } else if (memoryUsage > 90 || evictionRate > 1000 || responseTime > 100) {
    status = 'degraded';
  }

  return {
    status,
    uptime,
    memoryUsage,
    evictionRate,
    responseTime,
    lastCheck: new Date(),
  };
}

/**
 * Cache optimization recommendations
 */
export interface CacheOptimizationRecommendation {
  issue: string;
  severity: 'critical' | 'warning' | 'info';
  recommendation: string;
  expectedImprovement: string;
}

export function generateCacheOptimizationRecommendations(
  stats: CacheStats,
  health: CacheHealth
): CacheOptimizationRecommendation[] {
  const recommendations: CacheOptimizationRecommendation[] = [];

  if (stats.hitRate < 50) {
    recommendations.push({
      issue: 'Low cache hit rate',
      severity: 'warning',
      recommendation: 'Increase cache TTL or implement cache warming strategies',
      expectedImprovement: '20-30% improvement in response times',
    });
  }

  if (health.memoryUsage > 85) {
    recommendations.push({
      issue: 'High memory usage',
      severity: 'critical',
      recommendation: 'Increase max memory or implement more aggressive eviction policy',
      expectedImprovement: 'Prevent cache evictions and performance degradation',
    });
  }

  if (health.responseTime > 50) {
    recommendations.push({
      issue: 'Slow cache response times',
      severity: 'warning',
      recommendation: 'Check network latency or consider Redis cluster setup',
      expectedImprovement: '50% reduction in response times',
    });
  }

  if (health.evictionRate > 100) {
    recommendations.push({
      issue: 'High eviction rate',
      severity: 'warning',
      recommendation: 'Increase max memory or optimize cache key usage',
      expectedImprovement: 'Reduce cache misses by 30-40%',
    });
  }

  return recommendations;
}
