# Marketplace Chat System Documentation

## Overview

The Marketplace Chat System provides direct user-to-user messaging functionality for the GuideMe platform. This system enables users to communicate privately with each other regarding marketplace transactions, without vendor interruption or interference from event/inquiry chats.

## Key Features

- **Direct User-to-User Communication**: Private messaging between any two users
- **Real-time Messaging**: Socket.io integration for instant message delivery
- **Inbox Management**: Paginated inbox with unread message counts
- **Online/Offline Status**: Real-time tracking of user availability
- **Message Types**: Support for text, images, and file attachments
- **Read Receipts**: Track when messages are read
- **Message Deletion**: Users can delete messages and chats for themselves
- **Typing Indicators**: Real-time typing status
- **Reply Functionality**: Users can reply to specific messages
- **File Attachments**: Support for images and documents up to 10MB

## Architecture

### Database Models

#### MarketplaceChatModel
- **Purpose**: Manages chat rooms between two users
- **Key Fields**:
  - `participants`: Array of user participants with join status
  - `lastMessage`: Snapshot of the most recent message
  - `totalMessages`: Counter for total messages in chat
  - `deletedBy`: Track which users have deleted the chat
  - `chatName`: Display name for the chat (default: "Marketplace Chat")

#### MarketplaceChatMessageModel
- **Purpose**: Stores individual messages within chats
- **Key Fields**:
  - `chatId`: Reference to the chat room
  - `sender`: User who sent the message
  - `content`: Message text content
  - `messageType`: text, image, file, or system
  - `attachment`: File attachment details
  - `readBy`: Array of users who have read the message
  - `replyTo`: Reference to replied message
  - `isDeleted`: Soft delete flag
  - `deletedBy`: Track which users have deleted the message

### API Endpoints

All endpoints require authentication and are prefixed with `/api/v1/marketplace/chat/`

#### REST API Endpoints

```
GET    /inbox                    - Get user's inbox chats with pagination
POST   /:userId                  - Create or get chat with another user
GET    /:chatId/messages         - Get chat messages with pagination
POST   /:chatId/messages         - Send text message
POST   /:chatId/attachment       - Send message with file attachment
PUT    /:chatId/read             - Mark all messages in chat as read
DELETE /:chatId                  - Delete chat for current user
DELETE /message/:messageId       - Delete specific message for current user
```

#### Request/Response Examples

##### Get Inbox Chats
```javascript
// Request
GET /api/v1/marketplace/chat/inbox?page=1&limit=20

// Response
{
  "success": true,
  "message": "Inbox chats retrieved successfully",
  "data": {
    "chats": [
      {
        "_id": "chatId",
        "participants": [...],
        "lastMessage": {
          "content": "Hello there!",
          "sender": "userId",
          "sentAt": "2023-12-01T10:30:00Z",
          "messageType": "text"
        },
        "totalMessages": 15,
        "otherParticipant": {
          "userId": "otherUserId",
          "name": "John Doe",
          "email": "john@example.com",
          "profileImage": "https://...",
          "isOnline": true
        },
        "unreadCount": 3,
        "createdAt": "2023-11-30T10:00:00Z",
        "updatedAt": "2023-12-01T10:30:00Z"
      }
    ],
    "pagination": {
      "currentPage": 1,
      "totalPages": 2,
      "totalItems": 25,
      "itemsPerPage": 20
    }
  }
}
```

##### Send Text Message
```javascript
// Request
POST /api/v1/marketplace/chat/chatId/messages
{
  "content": "Hello! I'm interested in your product.",
  "replyTo": "messageId" // Optional
}

// Response
{
  "success": true,
  "message": "Message sent successfully",
  "data": {
    "message": {
      "_id": "messageId",
      "content": "Hello! I'm interested in your product.",
      "sender": {
        "_id": "userId",
        "email": "user@example.com",
        "isOnline": true
      },
      "messageType": "text",
      "createdAt": "2023-12-01T10:30:00Z",
      "readBy": [],
      "replyTo": {
        "_id": "originalMessageId",
        "content": "Original message content",
        "sender": "otherUserId",
        "messageType": "text"
      }
    }
  }
}
```

### Socket.io Events

#### Client to Server Events

##### Join Chat

The `joinMarketplaceChat` event supports three different ways to join a chat:

1. **By Other User ID** (`otherUserId`): Creates a new chat if one doesn't exist between you and the other user, or joins the existing chat.
2. **By Receiver ID** (`receiverId`): Alternative naming for the same functionality as `otherUserId`.
3. **By Chat ID** (`chatId`): Joins an existing chat using its specific chat ID. User must be a participant in the chat.

##### Join Chat
```javascript
// Option 1: Join by other user ID (creates new chat if doesn't exist)
socket.emit('joinMarketplaceChat', {
  otherUserId: 'userId'  // or receiverId: 'userId'
}, (response) => {
  if (response.success) {
    console.log('Joined chat:', response.data.chat);
    console.log('Other participant:', response.data.otherParticipant);
    console.log('Recent messages:', response.data.recentMessages);
  }
});

// Option 2: Join by existing chat ID
socket.emit('joinMarketplaceChat', {
  chatId: 'existingChatId'
}, (response) => {
  if (response.success) {
    console.log('Joined chat:', response.data.chat);
    console.log('Other participant:', response.data.otherParticipant);
    console.log('Recent messages:', response.data.recentMessages);
  }
});

// Option 3: Join by receiver ID (alternative naming)
socket.emit('joinMarketplaceChat', {
  receiverId: 'userId'
}, (response) => {
  if (response.success) {
    console.log('Joined chat:', response.data.chat);
    console.log('Other participant:', response.data.otherParticipant);
    console.log('Recent messages:', response.data.recentMessages);
  }
});
```

##### Get Inbox Chats
```javascript
socket.emit('getInboxChats', {
  page: 1,
  limit: 20
}, (response) => {
  if (response.success) {
    console.log('Inbox chats:', response.data.chats);
    console.log('Pagination:', response.data.pagination);
  }
});
```

##### Send Message
```javascript
socket.emit('sendMarketplaceChatMessage', {
  chatId: 'chatId',
  content: 'Hello there!',
  messageType: 'text',
  replyTo: 'messageId' // Optional
}, (response) => {
  if (response.success) {
    console.log('Message sent:', response.data);
  }
});
```

##### Mark Chat as Read
```javascript
socket.emit('markMarketplaceChatAsRead', {
  chatId: 'chatId'
}, (response) => {
  if (response.success) {
    console.log('Marked as read:', response.data.markedMessagesCount);
  }
});
```

##### Typing Indicator
```javascript
socket.emit('marketplaceChatTyping', {
  chatId: 'chatId',
  isTyping: true
});
```

##### Mark Message as Seen
```javascript
socket.emit('marketplaceChatMessageSeen', {
  chatId: 'chatId',
  messageId: 'messageId'
}, (response) => {
  if (response.success) {
    console.log('Message marked as seen');
  }
});
```

##### Leave Chat
```javascript
socket.emit('leaveMarketplaceChat', {
  chatId: 'chatId'
}, (response) => {
  if (response.success) {
    console.log('Left chat successfully');
  }
});
```

#### Server to Client Events

##### New Message Received
```javascript
socket.on('NewMarketplaceMessage', (data) => {
  console.log('New message received:', data.message);
  console.log('In chat:', data.chatId);
  // Update UI with new message
});
```

##### Chat Joined
```javascript
socket.on('MarketplaceChatJoined', (data) => {
  console.log('User joined chat:', data.participant);
  console.log('Chat ID:', data.chatId);
  console.log('Joined at:', data.joinedAt);
});
```

##### Chat Left
```javascript
socket.on('MarketplaceChatLeft', (data) => {
  console.log('User left chat:', data.participant);
  console.log('Chat ID:', data.chatId);
  console.log('Left at:', data.leftAt);
});
```

##### Messages Read
```javascript
socket.on('MarketplaceChatRead', (data) => {
  console.log('Messages read by:', data.readBy);
  console.log('Chat ID:', data.chatId);
  console.log('Read at:', data.readAt);
  // Update UI to show read status
});
```

##### Typing Indicator
```javascript
socket.on('MarketplaceChatTyping', (data) => {
  console.log('User typing:', data.user);
  console.log('Is typing:', data.isTyping);
  console.log('Chat ID:', data.chatId);
  // Show/hide typing indicator
});
```

##### Message Seen
```javascript
socket.on('MarketplaceChatMessageSeen', (data) => {
  console.log('Message seen by:', data.seenBy);
  console.log('Message ID:', data.messageId);
  console.log('Chat ID:', data.chatId);
  console.log('Seen at:', data.seenAt);
  // Update UI to show message seen status
});
```

### Online/Offline Status

#### Automatic Status Updates
- **Online**: Set when user connects to socket
- **Offline**: Set when user disconnects from socket

#### Status in Responses
All user data in responses includes the `isOnline` field:
```javascript
{
  "userId": "userId",
  "name": "John Doe",
  "email": "john@example.com",
  "profileImage": "https://...",
  "isOnline": true
}
```

### File Attachments

#### Supported File Types
- **Images**: JPEG, JPG, PNG, GIF, WebP
- **Documents**: PDF, DOC, DOCX, TXT

#### File Upload Process
1. Use multipart/form-data with field name `attachment`
2. Include optional `content` field for message text
3. File size limit: 10MB
4. Files are processed and stored with media references

#### Example Upload
```javascript
const formData = new FormData();
formData.append('attachment', fileInput.files[0]);
formData.append('content', 'Here is the document you requested');

fetch('/api/v1/marketplace/chat/chatId/attachment', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`
  },
  body: formData
});
```

## Security Features

### Authentication
- JWT token required for all API endpoints
- Socket.io authentication via token
- User session validation

### Authorization
- Users can only access their own chats
- Participants validation for all chat operations
- Message sender validation

### Data Protection
- Soft delete functionality
- User-specific message deletion
- Chat restoration from deleted state

## Error Handling

### Common Error Responses
```javascript
{
  "success": false,
  "message": "Chat not found",
  "statusCode": 404
}
```

### Socket Error Handling
```javascript
socket.emit('joinMarketplaceChat', data, (response) => {
  if (!response.success) {
    console.error('Error:', response.message);
    // Handle error in UI
  }
});
```

## Performance Considerations

### Pagination
- Default limit: 20 items per page for inbox
- Default limit: 50 messages per page for chat messages
- Efficient database queries with proper indexing

### Real-time Updates
- Socket rooms for efficient message delivery
- Personal user rooms for notifications
- Optimized database queries

### File Handling
- Memory storage for file processing
- Efficient file type validation
- Automatic file size limiting

## Usage Examples

### Basic Chat Implementation

```javascript
class MarketplaceChat {
  constructor(socket, token) {
    this.socket = socket;
    this.token = token;
    this.currentChatId = null;
    this.setupEventListeners();
  }

  setupEventListeners() {
    this.socket.on('NewMarketplaceMessage', (data) => {
      this.displayMessage(data.message);
    });

    this.socket.on('MarketplaceChatTyping', (data) => {
      this.showTypingIndicator(data.user, data.isTyping);
    });

    this.socket.on('MarketplaceChatRead', (data) => {
      this.markMessagesAsRead(data.chatId);
    });

    this.socket.on('MarketplaceChatMessageSeen', (data) => {
      this.markMessageAsSeen(data.messageId, data.seenBy);
    });
  }

  async loadInbox() {
    return new Promise((resolve) => {
      this.socket.emit('getInboxChats', { page: 1, limit: 20 }, (response) => {
        if (response.success) {
          this.displayInbox(response.data.chats);
          resolve(response.data);
        }
      });
    });
  }

  async joinChat(options) {
    return new Promise((resolve) => {
      // options can be: { otherUserId: 'id' }, { receiverId: 'id' }, or { chatId: 'id' }
      this.socket.emit('joinMarketplaceChat', options, (response) => {
        if (response.success) {
          this.currentChatId = response.data.chat._id;
          this.displayMessages(response.data.recentMessages);
          resolve(response.data);
        }
      });
    });
  }

  async joinChatByUserId(userId) {
    return this.joinChat({ otherUserId: userId });
  }

  async joinChatByReceiverId(receiverId) {
    return this.joinChat({ receiverId: receiverId });
  }

  async joinChatById(chatId) {
    return this.joinChat({ chatId: chatId });
  }

  sendMessage(content, replyTo = null) {
    if (!this.currentChatId) return;

    this.socket.emit('sendMarketplaceChatMessage', {
      chatId: this.currentChatId,
      content,
      messageType: 'text',
      replyTo
    }, (response) => {
      if (response.success) {
        this.displayMessage(response.data, true); // Mark as sent by current user
      }
    });
  }

  markAsRead() {
    if (!this.currentChatId) return;

    this.socket.emit('markMarketplaceChatAsRead', {
      chatId: this.currentChatId
    });
  }

  sendTypingIndicator(isTyping) {
    if (!this.currentChatId) return;

    this.socket.emit('marketplaceChatTyping', {
      chatId: this.currentChatId,
      isTyping
    });
  }

  markMessageAsSeen(messageId) {
    if (!this.currentChatId) return;

    this.socket.emit('marketplaceChatMessageSeen', {
      chatId: this.currentChatId,
      messageId
    });
  }

  displayMessage(message, isSent = false) {
    // Implement UI message display
    console.log('Display message:', message);
  }

  displayInbox(chats) {
    // Implement UI inbox display
    console.log('Display inbox:', chats);
  }

  displayMessages(messages) {
    // Implement UI messages display
    console.log('Display messages:', messages);
  }

  showTypingIndicator(user, isTyping) {
    // Implement typing indicator UI
    console.log('Typing indicator:', user, isTyping);
  }

  markMessagesAsRead(chatId) {
    // Implement read status UI update
    console.log('Mark messages as read:', chatId);
  }

  markMessageAsSeen(messageId, seenBy) {
    // Implement message seen status UI update
    console.log('Mark message as seen:', messageId, 'by:', seenBy);
  }
}

// Usage
const socket = io('http://localhost:3050', {
  auth: { token: userToken }
});

const chat = new MarketplaceChat(socket, userToken);

// Load user's inbox
chat.loadInbox();

// Join chat with another user (multiple ways)
chat.joinChatByUserId('otherUserId');
// or
chat.joinChatByReceiverId('receiverId');
// or 
chat.joinChatById('existingChatId');

// Send message
chat.sendMessage('Hello there!');

// Mark a message as seen
chat.markMessageAsSeen('messageId');
```

## Database Indexes

### Performance Optimization
```javascript
// MarketplaceChatModel indexes
{ 'participants.userId': 1 }
{ 'lastMessage.sentAt': -1 }
{ 'participants.userId': 1, 'participants.isActive': 1 }
{ isDeleted: 1 }

// MarketplaceChatMessageModel indexes
{ chatId: 1, createdAt: -1 }
{ sender: 1 }
{ isDeleted: 1 }
{ 'readBy.userId': 1 }
{ messageType: 1 }
```

## Monitoring and Analytics

### Key Metrics to Track
- Active chat sessions
- Message delivery rates
- User online/offline patterns
- File upload success rates
- Error rates by endpoint

### Logging
- All socket events are logged
- Database operations include error logging
- File upload operations are logged

## Migration from Existing Systems

### Differences from Event/Inquiry Chats
- **No Group Functionality**: Only two participants per chat
- **No Admin Roles**: All participants have equal permissions
- **Simplified Structure**: No external entity references
- **Enhanced Privacy**: User-specific deletion and restoration

### Data Migration Considerations
- No direct migration needed from existing chat systems
- New chat system operates independently
- Users start with empty inbox

## Future Enhancements

### Planned Features
- Message search functionality
- Chat archiving
- Message reactions/emojis
- Voice message support
- Image/video preview
- Push notifications
- Message encryption
- Bulk message operations

### API Versioning
- Current version: v1
- Backward compatibility maintained
- Deprecation notices for breaking changes

## Troubleshooting

### Common Issues

#### Messages Not Delivering
1. Check socket connection status
2. Verify user authentication
3. Confirm chat room membership
4. Check network connectivity

#### File Upload Failures
1. Verify file size (< 10MB)
2. Check file type support
3. Ensure proper form data format
4. Check server storage space

#### Typing Indicators Not Working
1. Verify socket connection
2. Check chat room membership
3. Ensure proper event emission
4. Verify UI event handling

### Debug Mode
Enable debug logging by setting environment variables:
```bash
DEBUG=socket.io:*
NODE_ENV=development
```

## Conclusion

The Marketplace Chat System provides a robust, scalable solution for user-to-user communication within the GuideMe platform. With real-time messaging, file sharing, and comprehensive API coverage, it enables seamless marketplace interactions while maintaining security and performance standards.

For technical support or questions about implementation, please refer to the existing codebase or contact the development team.