import { NextRequest, NextResponse } from 'next/server';
import { getCurrentUser } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { subscribe } from '@/lib/ai/generationRunner';

/**
 * GET /api/ai/generations/[id]/stream
 *
 * SSE attach to an in-flight generation. The runner that POST
 * /api/ai/generate kicked off lives in this Node process; this
 * endpoint subscribes to its in-memory bus and forwards each delta
 * as an SSE event.
 *
 * Late-joining (after some text has streamed): the runner buffers
 * everything emitted so far, and the subscription replays the buffer
 * on attach, so refresh / new tab catches up cleanly.
 *
 * Already-finished: subscribe() replays the buffer and returns a
 * no-op unsubscribe. We close the connection right after the buffer
 * drains.
 *
 * Cross-process resume (pod restart, separate process): the in-memory
 * bus is empty, so the SSE will be silent. The client should fall
 * back to polling /api/ai/generations/[id] for `progressText` until
 * the row hits a terminal status. The Generate UI does this.
 */

export const dynamic = 'force-dynamic';

export async function GET(
  request: NextRequest,
  { params }: { params: { id: string } },
) {
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

  // Authorize.
  const row = await prisma.aIGeneration.findFirst({
    where: { id: params.id, userId: user.id },
    select: { id: true, status: true, progressText: true, errorMessage: true, parsedProgram: true, tokensIn: true, tokensOut: true, durationMs: true },
  });
  if (!row) return NextResponse.json({ error: 'Not found' }, { status: 404 });

  const encoder = new TextEncoder();
  const send = (controller: ReadableStreamDefaultController, event: string, data: unknown) =>
    controller.enqueue(
      encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`),
    );

  const stream = new ReadableStream<Uint8Array>({
    start(controller) {
      let closed = false;
      const safeClose = () => {
        if (closed) return;
        closed = true;
        try {
          controller.close();
        } catch {
          /* already closed */
        }
      };

      // First: send a `generation` event with the id so clients can
      // confirm what they attached to (and consume the same protocol
      // their old code expected).
      send(controller, 'generation', { id: params.id });

      // If the row already finished while we weren't looking, send
      // its known progress + complete + close. (Cross-process resume
      // OR fast finish before subscribe attached.)
      if (row.status !== 'pending') {
        if (row.progressText) {
          send(controller, 'text', { delta: row.progressText });
        }
        send(controller, 'complete', {
          parsedOk: row.status === 'completed' || row.status === 'applied',
          errorMessage: row.errorMessage ?? undefined,
          tokensIn: row.tokensIn ?? undefined,
          tokensOut: row.tokensOut ?? undefined,
          durationMs: row.durationMs ?? undefined,
        });
        safeClose();
        return;
      }

      const unsub = subscribe(params.id, (d) => {
        if (closed) return;
        if (d.type === 'text') send(controller, 'text', { delta: d.delta });
        else if (d.type === 'usage')
          send(controller, 'usage', {
            tokensIn: d.tokensIn,
            tokensOut: d.tokensOut,
          });
        else if (d.type === 'complete') {
          send(controller, 'complete', {
            parsedOk: d.parsedOk,
            errorMessage: d.errorMessage,
            tokensIn: d.tokensIn,
            tokensOut: d.tokensOut,
            durationMs: d.durationMs,
          });
          safeClose();
        } else if (d.type === 'error') {
          send(controller, 'complete', {
            parsedOk: false,
            errorMessage: d.errorMessage,
          });
          safeClose();
        }
      });

      request.signal.addEventListener('abort', () => {
        unsub();
        safeClose();
      });
    },
  });

  return new Response(stream, {
    status: 200,
    headers: {
      'content-type': 'text/event-stream',
      'cache-control': 'no-store',
      'x-accel-buffering': 'no',
    },
  });
}
