import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import jwt from 'jsonwebtoken';
import { env } from '../../../config/env';
import { UserRole } from '@prisma/client';

/**
 * Chat Notifications SSE Routes
 *
 * Provides per-user SSE streams for real-time chat reply notifications.
 * Since EventSource can't send Authorization headers, JWT is passed as query param.
 */

interface TokenPayload {
  id: string;
  email: string;
  role: UserRole;
}

// In-memory subscriber map: userId → Set of SSE writers
const subscribers = new Map<string, Set<(data: string) => void>>();

/**
 * Notify a user of a chat reply via SSE
 */
export function notifyUser(userId: string, notification: {
  type: 'chat_reply';
  videoId: number;
  videoTitle: string;
  commentId: number;
  commenterName: string;
  contentPreview: string;
}): void {
  const writers = subscribers.get(userId);
  if (!writers || writers.size === 0) return;

  const data = JSON.stringify(notification);
  for (const write of writers) {
    try {
      write(data);
    } catch {
      // Writer disconnected, will be cleaned up
    }
  }
}

export async function chatNotificationsRoutes(fastify: FastifyInstance) {
  /**
   * GET /notifications/stream?sig=...&exp=...&uid=...
   * Per-user SSE stream for chat reply notifications. Uses path-scoped signed
   * URL (replaces legacy ?token=JWT path on 2026-04-12) since EventSource
   * cannot set Authorization headers.
   */
  fastify.get(
    '/notifications/stream',
    async (
      request: FastifyRequest<{ Querystring: { sig?: string; exp?: string; uid?: string } }>,
      reply: FastifyReply
    ) => {
      const { verifyMediaSignature } = await import('../../../utils/signed-url');
      const result = verifyMediaSignature(request.url, request.query as Record<string, string | undefined>);
      if (!result.valid) {
        return reply.code(401).send({ message: 'Invalid or expired signed URL' });
      }
      const userId = result.userId;

      // Set SSE headers
      reply.raw.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'X-Accel-Buffering': 'no',
      });

      // Writer function for this connection
      const writer = (data: string) => {
        reply.raw.write(`data: ${data}\n\n`);
      };

      // Register subscriber
      if (!subscribers.has(userId)) {
        subscribers.set(userId, new Set());
      }
      subscribers.get(userId)!.add(writer);

      // Send connection confirmation
      reply.raw.write(`data: ${JSON.stringify({ type: 'connected', userId })}\n\n`);

      // Keep-alive ping every 30 seconds
      const pingInterval = setInterval(() => {
        try {
          reply.raw.write(': ping\n\n');
        } catch {
          // Connection closed
        }
      }, 30000);

      // Cleanup on disconnect
      request.raw.on('close', () => {
        clearInterval(pingInterval);
        const writers = subscribers.get(userId);
        if (writers) {
          writers.delete(writer);
          if (writers.size === 0) {
            subscribers.delete(userId);
          }
        }
      });
    }
  );
}
