const mongoose = require('mongoose'); const Schema = mongoose.Schema; const LastMessageSchema = new Schema({ text: { type: String, trim: true }, senderId: { type: Schema.Types.ObjectId, ref: 'User' }, timestamp: { type: Date, default: Date.now }, type: { type: String, enum: ['text', 'ride_share', 'location', 'image', 'system'], default: 'text' } }, { _id: false }); const ChatSchema = new Schema({ idapp: { type: String, required: true, index: true }, participants: [{ type: Schema.Types.ObjectId, ref: 'User', required: true }], rideId: { type: Schema.Types.ObjectId, ref: 'Ride', index: true // Opzionale: chat collegata a un viaggio specifico }, rideRequestId: { type: Schema.Types.ObjectId, ref: 'RideRequest' }, type: { type: String, enum: ['direct', 'ride', 'group'], default: 'direct' }, title: { type: String, trim: true // Solo per chat di gruppo }, lastMessage: { type: LastMessageSchema }, unreadCount: { type: Map, of: Number, default: new Map() // { odIdUtente: numeroMessaggiNonLetti } }, isActive: { type: Boolean, default: true }, mutedBy: [{ type: Schema.Types.ObjectId, ref: 'User' }], blockedBy: [{ type: Schema.Types.ObjectId, ref: 'User' }], metadata: { type: Schema.Types.Mixed } }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } }); // Indici ChatSchema.index({ participants: 1 }); ChatSchema.index({ idapp: 1, participants: 1 }); ChatSchema.index({ idapp: 1, updatedAt: -1 }); // Virtual per contare messaggi non letti totali ChatSchema.virtual('totalUnread').get(function() { if (!this.unreadCount) return 0; let total = 0; this.unreadCount.forEach(count => { total += count; }); return total; }); // Metodo per ottenere unread count per un utente specifico ChatSchema.methods.getUnreadForUser = function(userId) { if (!this.unreadCount) return 0; return this.unreadCount.get(userId.toString()) || 0; }; // Metodo per incrementare unread count ChatSchema.methods.incrementUnread = function(excludeUserId) { this.participants.forEach(participantId => { const id = participantId.toString(); if (id !== excludeUserId.toString()) { const current = this.unreadCount.get(id) || 0; this.unreadCount.set(id, current + 1); } }); return this.save(); }; // Metodo per resettare unread count per un utente ChatSchema.methods.markAsRead = function(userId) { this.unreadCount.set(userId.toString(), 0); return this.save(); }; // Metodo per aggiornare ultimo messaggio ChatSchema.methods.updateLastMessage = function(message) { this.lastMessage = { text: message.text, senderId: message.senderId, timestamp: message.createdAt || new Date(), type: message.type || 'text' }; return this.save(); }; // Metodo per verificare se un utente è partecipante ChatSchema.methods.hasParticipant = function(userId) { return this.participants.some( p => p.toString() === userId.toString() ); }; // Metodo per verificare se la chat è bloccata per un utente ChatSchema.methods.isBlockedFor = function(userId) { return this.blockedBy.some( id => id.toString() === userId.toString() ); }; // Metodo statico per trovare o creare una chat diretta ChatSchema.statics.findOrCreateDirect = async function(idapp, userId1, userId2, rideId = null) { // Cerca chat esistente tra i due utenti let chat = await this.findOne({ idapp, type: 'direct', participants: { $all: [userId1, userId2], $size: 2 } }); if (!chat) { chat = new this({ idapp, type: 'direct', participants: [userId1, userId2], rideId, unreadCount: new Map() }); await chat.save(); } else if (rideId && !chat.rideId) { // Aggiorna con rideId se fornito chat.rideId = rideId; await chat.save(); } return chat; }; // Metodo statico per ottenere tutte le chat di un utente ChatSchema.statics.getChatsForUser = function(idapp, userId) { return this.find({ idapp, participants: userId, isActive: true, blockedBy: { $ne: userId } }) .populate('participants', 'username name surname profile.avatar') .populate('rideId', 'departure destination dateTime') .sort({ updatedAt: -1 }); }; // Metodo statico per creare chat di gruppo per un viaggio ChatSchema.statics.createRideGroupChat = async function(idapp, rideId, title, participantIds) { const chat = new this({ idapp, type: 'group', rideId, title, participants: participantIds, unreadCount: new Map() }); return chat.save(); }; const Chat = mongoose.model('Chat', ChatSchema); module.exports = Chat;