import { EventEmitter } from 'events';

interface ShareRewardRecord {
  playerId: string;
  shareId: string;
  platform: 'twitter' | 'facebook' | 'discord' | 'telegram';
  rewardAmount: number;
  timestamp: Date;
  achievementId?: string;
}

interface DailyShareQuota {
  playerId: string;
  date: string;
  sharesCount: number;
  totalRewards: number;
  maxDaily: number;
}

interface ShareRewardLeaderboard {
  playerId: string;
  playerName: string;
  totalShares: number;
  totalRewards: number;
  rank: number;
}

export class ShareRewardIncentivesService extends EventEmitter {
  private shareRewards: Map<string, ShareRewardRecord[]> = new Map();
  private dailyQuotas: Map<string, DailyShareQuota> = new Map();
  private leaderboard: Map<string, ShareRewardLeaderboard> = new Map();

  private readonly REWARD_PER_SHARE = 0.25; // SC per share
  private readonly MAX_DAILY_SHARES = 5;
  private readonly MAX_DAILY_REWARD = 1.25; // 0.25 * 5

  constructor() {
    super();
  }

  /**
   * Record a share and award rewards
   */
  recordShare(
    playerId: string,
    playerName: string,
    platform: 'twitter' | 'facebook' | 'discord' | 'telegram',
    achievementId?: string
  ): { success: boolean; reward: number; message: string } {
    const today = new Date().toISOString().split('T')[0];
    const quotaKey = `${playerId}-${today}`;

    // Get or create daily quota
    if (!this.dailyQuotas.has(quotaKey)) {
      this.dailyQuotas.set(quotaKey, {
        playerId,
        date: today,
        sharesCount: 0,
        totalRewards: 0,
        maxDaily: this.MAX_DAILY_SHARES,
      });
    }

    const quota = this.dailyQuotas.get(quotaKey)!;

    // Check if daily limit reached
    if (quota.sharesCount >= this.MAX_DAILY_SHARES) {
      return {
        success: false,
        reward: 0,
        message: `Daily share limit (${this.MAX_DAILY_SHARES}) reached. Try again tomorrow!`,
      };
    }

    // Calculate reward
    const reward = this.REWARD_PER_SHARE;

    // Create share record
    const shareRecord: ShareRewardRecord = {
      playerId,
      shareId: `share-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      platform,
      rewardAmount: reward,
      timestamp: new Date(),
      achievementId,
    };

    // Store share record
    if (!this.shareRewards.has(playerId)) {
      this.shareRewards.set(playerId, []);
    }
    this.shareRewards.get(playerId)!.push(shareRecord);

    // Update daily quota
    quota.sharesCount += 1;
    quota.totalRewards += reward;

    // Update leaderboard
    this.updateLeaderboard(playerId, playerName, reward);

    // Emit event
    this.emit('share_rewarded', {
      playerId,
      playerName,
      platform,
      reward,
      sharesRemaining: this.MAX_DAILY_SHARES - quota.sharesCount,
    });

    return {
      success: true,
      reward,
      message: `Earned ${reward} SC! ${this.MAX_DAILY_SHARES - quota.sharesCount} shares remaining today.`,
    };
  }

  /**
   * Update leaderboard entry
   */
  private updateLeaderboard(playerId: string, playerName: string, rewardAmount: number) {
    if (!this.leaderboard.has(playerId)) {
      this.leaderboard.set(playerId, {
        playerId,
        playerName,
        totalShares: 0,
        totalRewards: 0,
        rank: 0,
      });
    }

    const entry = this.leaderboard.get(playerId)!;
    entry.totalShares += 1;
    entry.totalRewards += rewardAmount;

    // Recalculate ranks
    this.recalculateLeaderboardRanks();
  }

  /**
   * Recalculate leaderboard ranks
   */
  private recalculateLeaderboardRanks() {
    const sorted = Array.from(this.leaderboard.values())
      .sort((a, b) => b.totalRewards - a.totalRewards);

    sorted.forEach((entry, idx) => {
      entry.rank = idx + 1;
    });
  }

  /**
   * Get player's daily share quota
   */
  getDailyQuota(playerId: string): DailyShareQuota | null {
    const today = new Date().toISOString().split('T')[0];
    const quotaKey = `${playerId}-${today}`;

    return this.dailyQuotas.get(quotaKey) || null;
  }

  /**
   * Get player's share history
   */
  getShareHistory(playerId: string, limit: number = 50): ShareRewardRecord[] {
    const history = this.shareRewards.get(playerId) || [];
    return history.slice(-limit).reverse();
  }

  /**
   * Get player's total rewards
   */
  getPlayerTotalRewards(playerId: string): number {
    const history = this.shareRewards.get(playerId) || [];
    return history.reduce((sum, record) => sum + record.rewardAmount, 0);
  }

  /**
   * Get share leaderboard
   */
  getLeaderboard(limit: number = 100): ShareRewardLeaderboard[] {
    return Array.from(this.leaderboard.values())
      .sort((a, b) => a.rank - b.rank)
      .slice(0, limit);
  }

  /**
   * Get player's leaderboard position
   */
  getPlayerRank(playerId: string): ShareRewardLeaderboard | null {
    return this.leaderboard.get(playerId) || null;
  }

  /**
   * Get platform share statistics
   */
  getPlatformStats() {
    const stats = {
      twitter: 0,
      facebook: 0,
      discord: 0,
      telegram: 0,
      total: 0,
    };

    Array.from(this.shareRewards.values()).forEach((records) => {
      records.forEach((record) => {
        stats[record.platform]++;
        stats.total++;
      });
    });

    return stats;
  }

  /**
   * Get top sharers
   */
  getTopSharers(limit: number = 10): ShareRewardLeaderboard[] {
    return Array.from(this.leaderboard.values())
      .sort((a, b) => b.totalShares - a.totalShares)
      .slice(0, limit);
  }

  /**
   * Get top earners
   */
  getTopEarners(limit: number = 10): ShareRewardLeaderboard[] {
    return Array.from(this.leaderboard.values())
      .sort((a, b) => b.totalRewards - a.totalRewards)
      .slice(0, limit);
  }

  /**
   * Calculate referral bonus
   */
  calculateReferralBonus(referrerShares: number): number {
    // 10% bonus for every 10 successful referrals
    const bonusMultiplier = Math.floor(referrerShares / 10) * 0.1;
    return this.REWARD_PER_SHARE * bonusMultiplier;
  }

  /**
   * Award referral bonus
   */
  awardReferralBonus(
    referrerId: string,
    referrerName: string,
    referralCount: number
  ): { bonus: number; totalBonus: number } {
    const bonus = this.calculateReferralBonus(referralCount);

    if (bonus > 0) {
      this.emit('referral_bonus_awarded', {
        referrerId,
        referrerName,
        referralCount,
        bonus,
      });
    }

    const leaderboardEntry = this.leaderboard.get(referrerId);
    const totalBonus = leaderboardEntry ? leaderboardEntry.totalRewards : 0;

    return { bonus, totalBonus };
  }

  /**
   * Get share reward statistics for period
   */
  getStatistics(startDate?: Date, endDate?: Date) {
    const start = startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // 30 days ago
    const end = endDate || new Date();

    let totalShares = 0;
    let totalRewards = 0;
    let uniqueSharers = new Set<string>();

    Array.from(this.shareRewards.values()).forEach((records) => {
      records.forEach((record) => {
        if (record.timestamp >= start && record.timestamp <= end) {
          totalShares++;
          totalRewards += record.rewardAmount;
          uniqueSharers.add(record.playerId);
        }
      });
    });

    return {
      period: { start, end },
      totalShares,
      totalRewards,
      uniqueSharers: uniqueSharers.size,
      avgRewardPerShare: totalShares > 0 ? totalRewards / totalShares : 0,
      avgSharesPerPlayer: uniqueSharers.size > 0 ? totalShares / uniqueSharers.size : 0,
    };
  }

  /**
   * Reset daily quotas (call daily)
   */
  resetDailyQuotas() {
    const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().split('T')[0];

    // Remove old quotas
    Array.from(this.dailyQuotas.keys()).forEach((key) => {
      const date = key.split('-').slice(1).join('-');
      if (date < yesterday) {
        this.dailyQuotas.delete(key);
      }
    });

    this.emit('daily_quotas_reset');
  }
}

export default ShareRewardIncentivesService;
