import { auth } from '@clerk/nextjs/server';
import * as grpc from '@grpc/grpc-js';
import { NextResponse } from 'next/server';

import {
  GenerateServerStreamRequest,
  StudioApiGrpcServiceClient,
} from '@/proto_gen/generate';

// TODO change endpoint name to something more descriptive

const getAuthToken = async () => {
  const { userId, getToken } = await auth();
  if (userId) {
    return await getToken();
  }
  return null;
};

const createClient = async () => {
  const token = await getAuthToken();
  const metadata = new grpc.Metadata();
  metadata.add('authorization', `Bearer ${token}`);
  const apiBase = process.env.STREAMING_API_BASE || 'localhost:50051';
  const client = new StudioApiGrpcServiceClient(
    apiBase,
    apiBase.startsWith('localhost')
      ? grpc.credentials.createInsecure()
      : grpc.credentials.createSsl()
  );
  return {
    client,
    metadata,
  };
};

export async function POST(request: Request) {
  const { params } = await request.json();

  const stream = new TransformStream();
  const writer = stream.writable.getWriter();
  const encoder = new TextEncoder();

  const { client, metadata } = await createClient();

  const req = GenerateServerStreamRequest.create(params);
  const call = client.generateClipServerStream(req, metadata);

  call.on('data', async (response: { data: string; sequence: number }) => {
    await writer.write(
      encoder.encode(JSON.stringify({ ...response, type: 'data' }) + '\n')
    );
  });

  call.on('end', async () => {
    await writer.write(encoder.encode(JSON.stringify({ type: 'end' }) + '\n'));
    await writer.close();
  });

  call.on('error', async (error: Error) => {
    await writer.write(
      encoder.encode(
        JSON.stringify({ type: 'error', message: error.message }) + '\n'
      )
    );
    await writer.close();
  });

  return new NextResponse(stream.readable, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      Connection: 'keep-alive',
    },
  });
}
