import { Controller, Get, Post, Patch, Body, Param, Query, UseGuards, HttpCode, HttpStatus, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery, ApiParam, } from '@nestjs/swagger'; import { MessagesService } from './messages.service'; import { CreateMessageDto, StartConversationDto } from './dto'; import { JwtAuthGuard } from '../auth/guards'; import { CurrentUser } from '../auth/decorators'; import { UserRole } from '@prisma/client'; @ApiTags('Messages') @Controller('messages') @UseGuards(JwtAuthGuard) @ApiBearerAuth('JWT-auth') export class MessagesController { constructor(private readonly messagesService: MessagesService) {} // ========================================== // GET CONVERSATIONS LIST // ========================================== @Get('conversations') @ApiOperation({ summary: 'Get all conversations for the current user' }) @ApiResponse({ status: 200, description: 'List of conversations', schema: { example: [ { id: 'conv-uuid', lastMessageAt: '2024-01-01T00:00:00.000Z', lastMessageText: 'Hello!', unreadCount: 2, otherParty: { id: 'agent-uuid', name: 'John Doe', avatar: 'https://...', headline: 'Real Estate Agent', isOnline: true, }, }, ], }, }) async getConversations( @CurrentUser('id') userId: string, @CurrentUser('role') role: UserRole, ) { return this.messagesService.getConversations(userId, role); } // ========================================== // START OR GET CONVERSATION // ========================================== @Post('conversations') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Start or get existing conversation with an agent' }) @ApiResponse({ status: 200, description: 'Conversation created or retrieved', }) @ApiResponse({ status: 403, description: 'Connection not accepted', }) async startConversation( @CurrentUser('id') userId: string, @Body() dto: StartConversationDto, ) { return this.messagesService.getOrCreateConversation(userId, dto.agentProfileId); } // ========================================== // GET CONVERSATION DETAILS // ========================================== @Get('conversations/:id') @ApiOperation({ summary: 'Get a specific conversation' }) @ApiParam({ name: 'id', description: 'Conversation ID' }) @ApiResponse({ status: 200, description: 'Conversation details', }) @ApiResponse({ status: 404, description: 'Conversation not found', }) async getConversation( @Param('id') conversationId: string, @CurrentUser('id') userId: string, ) { return this.messagesService.getConversationById(conversationId, userId); } // ========================================== // GET MESSAGES FOR CONVERSATION // ========================================== @Get('conversations/:id/messages') @ApiOperation({ summary: 'Get messages for a conversation' }) @ApiParam({ name: 'id', description: 'Conversation ID' }) @ApiQuery({ name: 'page', required: false, type: Number }) @ApiQuery({ name: 'limit', required: false, type: Number }) @ApiResponse({ status: 200, description: 'List of messages with pagination', schema: { example: { messages: [ { id: 'msg-uuid', content: 'Hello!', messageType: 'TEXT', status: 'READ', createdAt: '2024-01-01T00:00:00.000Z', sender: { id: 'user-uuid', role: 'USER', userProfile: { firstName: 'Jane', lastName: 'Doe', }, }, }, ], pagination: { page: 1, limit: 50, total: 100, pages: 2, }, }, }, }) async getMessages( @Param('id') conversationId: string, @CurrentUser('id') userId: string, @Query('page') page?: string, @Query('limit') limit?: string, ) { return this.messagesService.getMessages( conversationId, userId, page ? parseInt(page, 10) : 1, limit ? parseInt(limit, 10) : 50, ); } // ========================================== // SEND MESSAGE (REST FALLBACK) // ========================================== @Post('conversations/:id/messages') @HttpCode(HttpStatus.CREATED) @ApiOperation({ summary: 'Send a message (REST fallback - prefer WebSocket)' }) @ApiParam({ name: 'id', description: 'Conversation ID' }) @ApiResponse({ status: 201, description: 'Message created', }) async sendMessage( @Param('id') conversationId: string, @CurrentUser('id') userId: string, @Body() dto: CreateMessageDto, ) { return this.messagesService.createMessage(conversationId, userId, dto); } // ========================================== // MARK MESSAGES AS READ // ========================================== @Patch('conversations/:id/read') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Mark all messages in conversation as read' }) @ApiParam({ name: 'id', description: 'Conversation ID' }) @ApiResponse({ status: 200, description: 'Messages marked as read', }) async markAsRead( @Param('id') conversationId: string, @CurrentUser('id') userId: string, ) { return this.messagesService.markMessagesAsRead(conversationId, userId); } // ========================================== // GET UNREAD COUNT // ========================================== @Get('unread-count') @ApiOperation({ summary: 'Get total unread message count' }) @ApiResponse({ status: 200, description: 'Unread count', schema: { example: { unreadCount: 5 }, }, }) async getUnreadCount( @CurrentUser('id') userId: string, @CurrentUser('role') role: UserRole, ) { const unreadCount = await this.messagesService.getTotalUnreadCount(userId, role); return { unreadCount }; } }