import { EventEmitter } from 'events';

const REWARD_PER_SHARE = 0.25; // SC per share
const MAX_SHARES_PER_DAY = 5;
const REWARD_CAP_PER_DAY = REWARD_PER_SHARE * MAX_SHARES_PER_DAY; // 1.25 SC/day

export interface ShareRewardRecord {
  userId: string;
  shareId: string;
  platform: string;
  rewardAmount: number;
  timestamp: Date;
  walletCredited: boolean;
}

export interface DailyShareStats {
  userId: string;
  date: string; // YYYY-MM-DD
  sharesCount: number;
  totalReward: number;
  remainingShares: number;
  remainingReward: number;
  lastResetTime: Date;
}

class ShareRewardsSystem extends EventEmitter {
  private shareRewards: Map<string, ShareRewardRecord[]> = new Map();
  private dailyStats: Map<string, DailyShareStats> = new Map();
  private walletCredits: Map<string, number> = new Map(); // userId -> total credited

  /**
   * Record a share and award reward if eligible
   */
  recordShareReward(userId: string, shareId: string, platform: string): {
    rewarded: boolean;
    amount: number;
    message: string;
    dailyStats: DailyShareStats;
  } {
    const today = this.getTodayString();
    const statsKey = `${userId}-${today}`;

    // Get or create daily stats
    let stats = this.dailyStats.get(statsKey);
    if (!stats) {
      stats = {
        userId,
        date: today,
        sharesCount: 0,
        totalReward: 0,
        remainingShares: MAX_SHARES_PER_DAY,
        remainingReward: REWARD_CAP_PER_DAY,
        lastResetTime: new Date(),
      };
      this.dailyStats.set(statsKey, stats);
    }

    // Check if user has reached daily limit
    if (stats.sharesCount >= MAX_SHARES_PER_DAY) {
      return {
        rewarded: false,
        amount: 0,
        message: `Daily share limit reached (${MAX_SHARES_PER_DAY}/day). Try again tomorrow!`,
        dailyStats: stats,
      };
    }

    // Record the share reward
    const reward: ShareRewardRecord = {
      userId,
      shareId,
      platform,
      rewardAmount: REWARD_PER_SHARE,
      timestamp: new Date(),
      walletCredited: false,
    };

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

    // Update daily stats
    stats.sharesCount++;
    stats.totalReward += REWARD_PER_SHARE;
    stats.remainingShares = MAX_SHARES_PER_DAY - stats.sharesCount;
    stats.remainingReward = REWARD_CAP_PER_DAY - stats.totalReward;

    // Credit wallet
    this.creditWallet(userId, REWARD_PER_SHARE);
    reward.walletCredited = true;

    this.emit('share-reward-earned', {
      userId,
      shareId,
      platform,
      amount: REWARD_PER_SHARE,
      dailyStats: stats,
      timestamp: new Date(),
    });

    return {
      rewarded: true,
      amount: REWARD_PER_SHARE,
      message: `+${REWARD_PER_SHARE} SC earned! (${stats.sharesCount}/${MAX_SHARES_PER_DAY} shares today)`,
      dailyStats: stats,
    };
  }

  /**
   * Credit wallet with share rewards
   */
  private creditWallet(userId: string, amount: number): void {
    const current = this.walletCredits.get(userId) || 0;
    this.walletCredits.set(userId, current + amount);

    this.emit('wallet-credited', {
      userId,
      amount,
      total: current + amount,
      timestamp: new Date(),
    });
  }

  /**
   * Get total share rewards earned by user
   */
  getTotalShareRewards(userId: string): number {
    return this.walletCredits.get(userId) || 0;
  }

  /**
   * Get today's share stats for user
   */
  getTodayStats(userId: string): DailyShareStats | null {
    const today = this.getTodayString();
    const statsKey = `${userId}-${today}`;
    return this.dailyStats.get(statsKey) || null;
  }

  /**
   * Get all share rewards for user
   */
  getUserShareRewards(userId: string): ShareRewardRecord[] {
    return this.shareRewards.get(userId) || [];
  }

  /**
   * Get share rewards for specific date
   */
  getShareRewardsByDate(userId: string, date: string): ShareRewardRecord[] {
    const rewards = this.shareRewards.get(userId) || [];
    return rewards.filter(r => this.formatDate(r.timestamp) === date);
  }

  /**
   * Get share reward statistics
   */
  getShareRewardStats(userId: string): {
    totalRewards: number;
    totalShares: number;
    averageRewardPerShare: number;
    topPlatform: string;
    platformBreakdown: Record<string, number>;
    dailyAverage: number;
  } {
    const rewards = this.shareRewards.get(userId) || [];
    const totalRewards = rewards.reduce((sum, r) => sum + r.rewardAmount, 0);
    const totalShares = rewards.length;

    const platformCounts: Record<string, number> = {};
    for (const reward of rewards) {
      platformCounts[reward.platform] = (platformCounts[reward.platform] || 0) + 1;
    }

    let topPlatform = 'none';
    let maxCount = 0;
    for (const [platform, count] of Object.entries(platformCounts)) {
      if (count > maxCount) {
        maxCount = count;
        topPlatform = platform;
      }
    }

    // Calculate daily average (days since first share)
    let dailyAverage = 0;
    if (rewards.length > 0) {
      const firstShare = rewards[0].timestamp;
      const lastShare = rewards[rewards.length - 1].timestamp;
      const daysDiff = Math.max(1, Math.ceil((lastShare.getTime() - firstShare.getTime()) / (1000 * 60 * 60 * 24)));
      dailyAverage = totalRewards / daysDiff;
    }

    return {
      totalRewards,
      totalShares,
      averageRewardPerShare: totalShares > 0 ? totalRewards / totalShares : 0,
      topPlatform,
      platformBreakdown: platformCounts,
      dailyAverage,
    };
  }

  /**
   * Get global share reward statistics
   */
  getGlobalStats(): {
    totalRewardsDistributed: number;
    totalSharesRecorded: number;
    uniqueUsers: number;
    averageRewardsPerUser: number;
    platformBreakdown: Record<string, number>;
  } {
    let totalRewards = 0;
    let totalShares = 0;
    const platformCounts: Record<string, number> = {};

    for (const rewards of this.shareRewards.values()) {
      for (const reward of rewards) {
        totalRewards += reward.rewardAmount;
        totalShares++;
        platformCounts[reward.platform] = (platformCounts[reward.platform] || 0) + 1;
      }
    }

    const uniqueUsers = this.shareRewards.size;

    return {
      totalRewardsDistributed: totalRewards,
      totalSharesRecorded: totalShares,
      uniqueUsers,
      averageRewardsPerUser: uniqueUsers > 0 ? totalRewards / uniqueUsers : 0,
      platformBreakdown: platformCounts,
    };
  }

  /**
   * Get leaderboard of top share reward earners
   */
  getTopEarners(limit: number = 10): Array<{
    userId: string;
    totalRewards: number;
    totalShares: number;
    topPlatform: string;
  }> {
    const earners: Array<{
      userId: string;
      totalRewards: number;
      totalShares: number;
      topPlatform: string;
    }> = [];

    for (const [userId, rewards] of this.shareRewards.entries()) {
      const totalRewards = rewards.reduce((sum, r) => sum + r.rewardAmount, 0);

      const platformCounts: Record<string, number> = {};
      for (const reward of rewards) {
        platformCounts[reward.platform] = (platformCounts[reward.platform] || 0) + 1;
      }

      let topPlatform = 'none';
      let maxCount = 0;
      for (const [platform, count] of Object.entries(platformCounts)) {
        if (count > maxCount) {
          maxCount = count;
          topPlatform = platform;
        }
      }

      earners.push({
        userId,
        totalRewards,
        totalShares: rewards.length,
        topPlatform,
      });
    }

    return earners.sort((a, b) => b.totalRewards - a.totalRewards).slice(0, limit);
  }

  /**
   * Reset daily stats (called at midnight UTC)
   */
  resetDailyStats(): void {
    const today = this.getTodayString();

    // Remove yesterday's stats
    const keysToDelete: string[] = [];
    for (const key of this.dailyStats.keys()) {
      const [, date] = key.split('-');
      if (date !== today) {
        keysToDelete.push(key);
      }
    }

    keysToDelete.forEach(key => this.dailyStats.delete(key));

    this.emit('daily-stats-reset', { timestamp: new Date() });
  }

  /**
   * Check if user can share today
   */
  canShareToday(userId: string): {
    canShare: boolean;
    sharesRemaining: number;
    rewardRemaining: number;
  } {
    const stats = this.getTodayStats(userId);

    if (!stats) {
      return {
        canShare: true,
        sharesRemaining: MAX_SHARES_PER_DAY,
        rewardRemaining: REWARD_CAP_PER_DAY,
      };
    }

    return {
      canShare: stats.sharesCount < MAX_SHARES_PER_DAY,
      sharesRemaining: stats.remainingShares,
      rewardRemaining: stats.remainingReward,
    };
  }

  /**
   * Get share reward progress towards daily cap
   */
  getDailyProgress(userId: string): {
    sharesUsed: number;
    sharesMax: number;
    rewardUsed: number;
    rewardMax: number;
    percentComplete: number;
  } {
    const stats = this.getTodayStats(userId);

    if (!stats) {
      return {
        sharesUsed: 0,
        sharesMax: MAX_SHARES_PER_DAY,
        rewardUsed: 0,
        rewardMax: REWARD_CAP_PER_DAY,
        percentComplete: 0,
      };
    }

    return {
      sharesUsed: stats.sharesCount,
      sharesMax: MAX_SHARES_PER_DAY,
      rewardUsed: stats.totalReward,
      rewardMax: REWARD_CAP_PER_DAY,
      percentComplete: (stats.sharesCount / MAX_SHARES_PER_DAY) * 100,
    };
  }

  /**
   * Clear all data (for testing)
   */
  clear(): void {
    this.shareRewards.clear();
    this.dailyStats.clear();
    this.walletCredits.clear();
  }

  // Private helper methods

  private getTodayString(): string {
    return this.formatDate(new Date());
  }

  private formatDate(date: Date): string {
    const year = date.getUTCFullYear();
    const month = String(date.getUTCMonth() + 1).padStart(2, '0');
    const day = String(date.getUTCDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  }
}

export const shareRewardsSystem = new ShareRewardsSystem();
