import { EventEmitter } from 'events';

interface PushNotification {
  id: string;
  userId: string;
  title: string;
  body: string;
  icon?: string;
  badge?: string;
  tag?: string;
  timestamp: Date;
  read: boolean;
  type: 'share_reward' | 'achievement' | 'tier_up' | 'tournament' | 'game' | 'system';
  data?: Record<string, any>;
}

interface NotificationPreference {
  userId: string;
  shareRewards: boolean;
  achievements: boolean;
  tierUps: boolean;
  tournaments: boolean;
  games: boolean;
  system: boolean;
  channels: {
    push: boolean;
    email: boolean;
    inApp: boolean;
  };
}

export class PushNotificationsService extends EventEmitter {
  private notifications: Map<string, PushNotification[]> = new Map();
  private preferences: Map<string, NotificationPreference> = new Map();
  private subscriptions: Map<string, Set<string>> = new Map(); // userId -> subscriptionIds

  constructor() {
    super();
  }

  /**
   * Send push notification
   */
  async sendNotification(
    userId: string,
    title: string,
    body: string,
    type: PushNotification['type'],
    data?: Record<string, any>,
    options?: { icon?: string; badge?: string; tag?: string }
  ): Promise<{ success: boolean; notificationId: string }> {
    // Check preferences
    const prefs = this.getPreferences(userId);
    if (!this.shouldSendNotification(prefs, type)) {
      return { success: false, notificationId: '' };
    }

    const notification: PushNotification = {
      id: `notif-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      userId,
      title,
      body,
      icon: options?.icon,
      badge: options?.badge,
      tag: options?.tag,
      timestamp: new Date(),
      read: false,
      type,
      data,
    };

    // Store notification
    if (!this.notifications.has(userId)) {
      this.notifications.set(userId, []);
    }
    this.notifications.get(userId)!.push(notification);

    // Send via channels
    if (prefs.channels.push) {
      await this.sendPushNotification(userId, notification);
    }
    if (prefs.channels.email) {
      await this.sendEmailNotification(userId, notification);
    }
    if (prefs.channels.inApp) {
      this.broadcastInAppNotification(userId, notification);
    }

    // Emit event
    this.emit('notification_sent', {
      userId,
      notificationId: notification.id,
      type,
    });

    return { success: true, notificationId: notification.id };
  }

  /**
   * Check if notification should be sent based on preferences
   */
  private shouldSendNotification(prefs: NotificationPreference, type: string): boolean {
    switch (type) {
      case 'share_reward':
        return prefs.shareRewards;
      case 'achievement':
        return prefs.achievements;
      case 'tier_up':
        return prefs.tierUps;
      case 'tournament':
        return prefs.tournaments;
      case 'game':
        return prefs.games;
      case 'system':
        return prefs.system;
      default:
        return true;
    }
  }

  /**
   * Send push notification (browser push)
   */
  private async sendPushNotification(userId: string, notification: PushNotification) {
    try {
      // In production, use Web Push API
      // For now, emit event for WebSocket broadcasting
      this.emit('push_notification', {
        userId,
        notification,
      });
    } catch (error) {
      console.error('Failed to send push notification:', error);
    }
  }

  /**
   * Send email notification
   */
  private async sendEmailNotification(userId: string, notification: PushNotification) {
    try {
      // In production, use email service (Brevo, SendGrid, etc.)
      this.emit('email_notification', {
        userId,
        notification,
      });
    } catch (error) {
      console.error('Failed to send email notification:', error);
    }
  }

  /**
   * Broadcast in-app notification via WebSocket
   */
  private broadcastInAppNotification(userId: string, notification: PushNotification) {
    this.emit('in_app_notification', {
      userId,
      notification,
    });
  }

  /**
   * Get user's notifications
   */
  getNotifications(userId: string, limit: number = 50, unreadOnly: boolean = false): PushNotification[] {
    const userNotifications = this.notifications.get(userId) || [];
    let filtered = userNotifications;

    if (unreadOnly) {
      filtered = filtered.filter((n) => !n.read);
    }

    return filtered.slice(-limit).reverse();
  }

  /**
   * Mark notification as read
   */
  markAsRead(userId: string, notificationId: string): boolean {
    const userNotifications = this.notifications.get(userId);
    if (!userNotifications) return false;

    const notification = userNotifications.find((n) => n.id === notificationId);
    if (notification) {
      notification.read = true;
      return true;
    }

    return false;
  }

  /**
   * Mark all notifications as read
   */
  markAllAsRead(userId: string): number {
    const userNotifications = this.notifications.get(userId) || [];
    let count = 0;

    userNotifications.forEach((n) => {
      if (!n.read) {
        n.read = true;
        count++;
      }
    });

    return count;
  }

  /**
   * Get unread notification count
   */
  getUnreadCount(userId: string): number {
    const userNotifications = this.notifications.get(userId) || [];
    return userNotifications.filter((n) => !n.read).length;
  }

  /**
   * Get or create notification preferences
   */
  getPreferences(userId: string): NotificationPreference {
    if (!this.preferences.has(userId)) {
      this.preferences.set(userId, {
        userId,
        shareRewards: true,
        achievements: true,
        tierUps: true,
        tournaments: true,
        games: true,
        system: true,
        channels: {
          push: true,
          email: false,
          inApp: true,
        },
      });
    }

    return this.preferences.get(userId)!;
  }

  /**
   * Update notification preferences
   */
  updatePreferences(userId: string, updates: Partial<NotificationPreference>): NotificationPreference {
    const prefs = this.getPreferences(userId);

    Object.assign(prefs, updates);

    this.emit('preferences_updated', {
      userId,
      preferences: prefs,
    });

    return prefs;
  }

  /**
   * Subscribe to notifications
   */
  subscribe(userId: string, subscriptionId: string): void {
    if (!this.subscriptions.has(userId)) {
      this.subscriptions.set(userId, new Set());
    }

    this.subscriptions.get(userId)!.add(subscriptionId);

    this.emit('subscription_added', {
      userId,
      subscriptionId,
    });
  }

  /**
   * Unsubscribe from notifications
   */
  unsubscribe(userId: string, subscriptionId: string): void {
    const subs = this.subscriptions.get(userId);
    if (subs) {
      subs.delete(subscriptionId);
    }

    this.emit('subscription_removed', {
      userId,
      subscriptionId,
    });
  }

  /**
   * Get subscriptions for user
   */
  getSubscriptions(userId: string): string[] {
    const subs = this.subscriptions.get(userId);
    return subs ? Array.from(subs) : [];
  }

  /**
   * Send share reward notification
   */
  async notifyShareReward(
    userId: string,
    playerName: string,
    platform: string,
    reward: number,
    sharesRemaining: number
  ): Promise<{ success: boolean; notificationId: string }> {
    return this.sendNotification(
      userId,
      '🎉 Share Reward Earned!',
      `You earned ${reward} SC for sharing on ${platform}. ${sharesRemaining} shares remaining today.`,
      'share_reward',
      {
        platform,
        reward,
        sharesRemaining,
      },
      {
        icon: '🎉',
        tag: 'share-reward',
      }
    );
  }

  /**
   * Send achievement unlock notification
   */
  async notifyAchievementUnlock(
    userId: string,
    achievementName: string,
    reward: number
  ): Promise<{ success: boolean; notificationId: string }> {
    return this.sendNotification(
      userId,
      '🏆 Achievement Unlocked!',
      `You unlocked "${achievementName}" and earned ${reward} SC!`,
      'achievement',
      {
        achievementName,
        reward,
      },
      {
        icon: '🏆',
        tag: 'achievement',
      }
    );
  }

  /**
   * Send tier up notification
   */
  async notifyTierUp(
    userId: string,
    newTier: string,
    benefits: string[]
  ): Promise<{ success: boolean; notificationId: string }> {
    return this.sendNotification(
      userId,
      '⭐ Tier Upgraded!',
      `Congratulations! You've reached ${newTier} tier. Enjoy exclusive benefits!`,
      'tier_up',
      {
        newTier,
        benefits,
      },
      {
        icon: '⭐',
        tag: 'tier-up',
      }
    );
  }

  /**
   * Send tournament notification
   */
  async notifyTournamentEvent(
    userId: string,
    tournamentName: string,
    event: 'started' | 'ending_soon' | 'ended' | 'rank_changed',
    details?: Record<string, any>
  ): Promise<{ success: boolean; notificationId: string }> {
    const titles = {
      started: `🎮 Tournament Started: ${tournamentName}`,
      ending_soon: `⏰ Tournament Ending Soon: ${tournamentName}`,
      ended: `🏁 Tournament Ended: ${tournamentName}`,
      rank_changed: `📊 Your Rank Changed: ${tournamentName}`,
    };

    return this.sendNotification(
      userId,
      titles[event],
      `Check out the tournament details and compete for prizes!`,
      'tournament',
      {
        tournamentName,
        event,
        ...details,
      },
      {
        tag: `tournament-${event}`,
      }
    );
  }

  /**
   * Clear old notifications (keep last 100)
   */
  clearOldNotifications(): void {
    this.notifications.forEach((notifs, userId) => {
      if (notifs.length > 100) {
        this.notifications.set(userId, notifs.slice(-100));
      }
    });

    this.emit('notifications_cleared');
  }

  /**
   * Get notification statistics
   */
  getStatistics() {
    let totalNotifications = 0;
    let totalUnread = 0;
    const typeDistribution: Record<string, number> = {};

    this.notifications.forEach((notifs) => {
      notifs.forEach((n) => {
        totalNotifications++;
        if (!n.read) totalUnread++;
        typeDistribution[n.type] = (typeDistribution[n.type] || 0) + 1;
      });
    });

    return {
      totalNotifications,
      totalUnread,
      totalUsers: this.notifications.size,
      typeDistribution,
      avgNotificationsPerUser: this.notifications.size > 0 ? totalNotifications / this.notifications.size : 0,
    };
  }
}

export default PushNotificationsService;
