/**
 * Fastify plugin that registers an SSE endpoint.
 * Product backends configure the path and optional auth check.
 */

import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { SSEHub } from './hub.js';

export interface SSEClient {
  id: string;
  userId?: string;
}

export interface SSEPluginOptions {
  /** Route path for the SSE endpoint (default: /events/stream) */
  path?: string;
  /** Extract userId from request (optional, enables per-user targeting) */
  getUserId?: (req: FastifyRequest) => string | undefined;
  /** Heartbeat interval in ms (default: 30000, set 0 to disable) */
  heartbeatIntervalMs?: number;
  /** The SSE hub instance to use (creates one if not provided) */
  hub?: SSEHub;
}

export async function ssePlugin(
  app: FastifyInstance,
  options: SSEPluginOptions = {}
): Promise<void> {
  const path = options.path ?? '/events/stream';
  const heartbeatMs = options.heartbeatIntervalMs ?? 30_000;
  const hub = options.hub ?? new SSEHub();

  // Decorate app with the hub so routes can push events
  if (!app.hasDecorator('sseHub')) {
    app.decorate('sseHub', hub);
  }

  // Register SSE endpoint
  app.get(path, async (req: FastifyRequest, reply: FastifyReply) => {
    const userId = options.getUserId?.(req);

    // Hijack the raw response for SSE streaming
    const raw = reply.raw;
    hub.addClient(raw, userId);

    // Prevent Fastify from sending its own response
    reply.hijack();
  });

  // Heartbeat timer
  let heartbeatTimer: ReturnType<typeof setInterval> | undefined;
  if (heartbeatMs > 0) {
    heartbeatTimer = setInterval(() => hub.heartbeat(), heartbeatMs);
  }

  // Cleanup on close
  app.addHook('onClose', async () => {
    if (heartbeatTimer) clearInterval(heartbeatTimer);
    hub.disconnectAll();
  });
}
