import { subscribeLiveEvents, subscriberCount } from '@/lib/live-events.js';
import { ensureBridgeStarted } from '@/lib/live-events-bridge.js';
import { requireSession } from '@/lib/auth.js';

export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';

// Cap on simultaneous SSE subscribers for this local-first app. Set above the
// expected concurrent tab count (a few browser tabs + curl probes) but low
// enough that a reconnect storm after a server restart can't spiral.
const MAX_SUBSCRIBERS = 32;

// Global Server-Sent Events bus.
// The dashboard subscribes to this on mount so it can show background activity
// (scheduled agent ticks, sub-agents spawned by the Main Agent, etc.) even when
// the user isn't actively chatting.
export async function GET(req) {
  // Gate the SSE channel — local mode is a pass-through, supabase mode rejects unauthenticated.
  try {
    await requireSession(req);
  } catch (err) {
    if (err && typeof err === 'object' && err.status) {
      return Response.json({ error: err.error || 'unauthorized' }, { status: err.status });
    }
    throw err;
  }

  if (subscriberCount() >= MAX_SUBSCRIBERS) {
    return new Response('Too many live-event subscribers', {
      status: 503,
      headers: { 'Retry-After': '5' },
    });
  }

  // Start the cross-process activity_log tailer (idempotent). Without this,
  // events emitted by the WhatsApp daemon / cron daemon / heartbeat worker
  // never reach the in-process bus, so the dashboard's Operator Command
  // Center stays empty when WhatsApp drives the main agent.
  ensureBridgeStarted();

  const encoder = new TextEncoder();

  let cleanup = () => {};

  const stream = new ReadableStream({
    start(ctrl) {
      let closed = false;
      function safeEnqueue(chunk) {
        if (closed) return;
        if (typeof ctrl.desiredSize === 'number' && ctrl.desiredSize < -32) {
          closed = true;
          cleanup();
          return;
        }
        try {
          ctrl.enqueue(encoder.encode(chunk));
        } catch {
          closed = true;
        }
      }

      // Send a hello so the client knows the channel is open.
      safeEnqueue(`event: ready\ndata: ${JSON.stringify({ ts: Date.now() })}\n\n`);

      const unsubscribe = subscribeLiveEvents((event) => {
        const type = event.type || 'event';
        safeEnqueue(`event: ${type}\ndata: ${JSON.stringify(event)}\n\n`);
      });

      // Keep-alive comment every 20s so proxies don't drop the connection.
      const keepalive = setInterval(() => {
        safeEnqueue(`: keepalive ${Date.now()}\n\n`);
      }, 20000);

      cleanup = () => {
        const wasClosed = closed;
        closed = true;
        clearInterval(keepalive);
        try { unsubscribe(); } catch { /* ignore */ }
        if (!wasClosed) {
          try { ctrl.close(); } catch { /* ignore */ }
        }
      };

      req.signal.addEventListener('abort', cleanup);
    },
    // ReadableStream.cancel() fires when the client disconnects gracefully
    // (no abort signal). Without this, the keepalive interval can outlive
    // the response in dev with HMR.
    cancel() {
      cleanup();
    },
  });

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache, no-transform',
      Connection: 'keep-alive',
      'X-Accel-Buffering': 'no',
    },
  });
}
