/**
 * PHASE 2: Notification Service
 * Manages real-time event broadcasting using Server-Sent Events (SSE)
 * Each user gets a unique channel for personalized notifications
 */

class NotificationService {
  constructor() {
    // Map of userId -> Set of SSE response objects
    this.subscribers = new Map();
    // Map of userId -> Array of pending events (for offline subscribers)
    this.eventQueue = new Map();
    this.maxQueueSize = 100; // Keep last 100 events per user
  }

  /**
   * Register a new SSE subscriber
   * @param {string} userId - User identifier
   * @param {Response} res - Express response object for SSE
   */
  subscribe(userId, res) {
    if (!this.subscribers.has(userId)) {
      this.subscribers.set(userId, new Set());
      this.eventQueue.set(userId, []);
    }

    this.subscribers.get(userId).add(res);

    // Send queued events to new subscriber
    const queued = this.eventQueue.get(userId) || [];
    queued.forEach(event => {
      this.sendSSE(res, event);
    });

    // Cleanup on disconnect
    res.on('close', () => {
      this.subscribers.get(userId).delete(res);
      if (this.subscribers.get(userId).size === 0) {
        this.subscribers.delete(userId);
      }
    });

    return true;
  }

  /**
   * Broadcast event to all subscribers of a user
   * @param {string} userId - User identifier
   * @param {string} eventType - Event type (e.g., 'project:created', 'log:error')
   * @param {object} data - Event payload
   */
  broadcast(userId, eventType, data) {
    const event = {
      type: eventType,
      timestamp: new Date().toISOString(),
      data
    };

    // Add to queue for offline subscribers
    if (this.eventQueue.has(userId)) {
      const queue = this.eventQueue.get(userId);
      queue.push(event);
      // Keep only last N events
      if (queue.length > this.maxQueueSize) {
        queue.shift();
      }
    }

    // Send to all connected subscribers
    if (this.subscribers.has(userId)) {
      this.subscribers.get(userId).forEach(res => {
        this.sendSSE(res, event);
      });
    }
  }

  /**
   * Broadcast to all users (admin notifications)
   * @param {string} eventType - Event type
   * @param {object} data - Event payload
   */
  broadcastToAll(eventType, data) {
    const event = {
      type: eventType,
      timestamp: new Date().toISOString(),
      data,
      isGlobal: true
    };

    this.subscribers.forEach((subscribers, userId) => {
      subscribers.forEach(res => {
        this.sendSSE(res, event);
      });
    });
  }

  /**
   * Send formatted SSE message
   * @param {Response} res - Express response object
   * @param {object} event - Event object
   */
  sendSSE(res, event) {
    try {
      const message = `data: ${JSON.stringify(event)}\n\n`;
      res.write(message);
    } catch (error) {
      console.error('[NotificationService] Error sending SSE:', error.message);
    }
  }

  /**
   * Get subscriber count (for monitoring)
   * @returns {object} Subscriber statistics
   */
  getStats() {
    const stats = {
      totalSubscribers: 0,
      userCount: 0,
      byUser: {}
    };

    this.subscribers.forEach((subscribers, userId) => {
      const count = subscribers.size;
      stats.totalSubscribers += count;
      stats.byUser[userId] = count;
    });

    stats.userCount = Object.keys(stats.byUser).length;
    return stats;
  }

  /**
   * Cleanup resources (useful for graceful shutdown)
   */
  disconnect() {
    this.subscribers.forEach((subscribers) => {
      subscribers.forEach(res => {
        try {
          res.end();
        } catch (error) {
          // Already closed
        }
      });
    });
    this.subscribers.clear();
    this.eventQueue.clear();
  }
}

// Singleton instance
const notificationService = new NotificationService();

export default notificationService;
