All files / src/app/api/chat/start route.ts

0% Statements 0/110
100% Branches 0/0
0% Functions 0/1
0% Lines 0/110

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                                                                                                                                                                                                                             
export const dynamic = 'force-dynamic';

/**
 * Chat Start API
 * POST /api/chat/start - Start a new chat conversation
 */

import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from '@/lib/auth';
import {
  withErrorHandling,
  ApiError,
  ApiSuccessResponse,
  ApiErrorResponse,
} from '@/lib/api';
import { ChatService, generateBotResponse } from '@/services';
import { z } from 'zod';

// ============================================================================
// VALIDATION
// ============================================================================

const StartConversationSchema = z.object({
  message: z.string().min(1, 'Message is required').max(2000),
  visitorId: z.string().optional(),
  relatedOrderId: z.number().optional(),
  metadata: z
    .object({
      currentPage: z.string().optional(),
      userAgent: z.string().optional(),
    })
    .optional(),
});

// ============================================================================
// HANDLERS
// ============================================================================

/**
 * POST /api/chat/start
 * Start a new chat conversation
 */
async function handlePost(
  request: NextRequest
): Promise<NextResponse<ApiSuccessResponse<unknown> | ApiErrorResponse>> {
  const session = await getServerSession();
  const body = await request.json();

  // Validate request body
  const parseResult = StartConversationSchema.safeParse(body);
  if (!parseResult.success) {
    throw ApiError.validation(
      'Invalid request data',
      parseResult.error.issues
    );
  }

  const { message, visitorId, relatedOrderId, metadata } = parseResult.data;

  // Require either userId or visitorId
  const userId = session?.user?.id;
  if (!userId && !visitorId) {
    throw ApiError.badRequest('Either login or provide a visitor ID');
  }

  // Start conversation
  const result = await ChatService.startConversation({
    userId,
    visitorId: userId ? undefined : visitorId,
    initialMessage: message,
    relatedOrderId,
    metadata: {
      ...metadata,
      startedAt: new Date().toISOString(),
    },
  });

  // If new conversation, try bot response
  if (result.isNewConversation) {
    const botResponse = await generateBotResponse(message, userId);

    if (botResponse) {
      const botMessage = await ChatService.sendMessage({
        conversationId: result.conversationId,
        senderType: 'BOT',
        content: botResponse.message,
        contentType: botResponse.contentType,
        attachments: botResponse.attachments as never,
      });

      result.messages.push(botMessage);

      // If bot suggests handoff, update status
      if (botResponse.handoffToAgent) {
        // Conversation already in WAITING status, nothing to update
      }
    }
  }

  return NextResponse.json({
    success: true,
    data: result,
  });
}

// ============================================================================
// EXPORTS
// ============================================================================

export const POST = withErrorHandling(handlePost);