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: String, }, { _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; }; // ✅ FIX: incrementUnread (assicura conversione corretta) ChatSchema.methods.incrementUnread = function (excludeUserId) { const excludeIdStr = excludeUserId.toString(); this.participants.forEach((participantId) => { // Gestisci sia ObjectId che oggetti popolati const id = participantId._id ? participantId._id.toString() : participantId.toString(); if (id !== excludeIdStr) { 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 // ✅ FIX: Gestisce sia ObjectId che oggetti User popolati ChatSchema.methods.hasParticipant = function (userId) { const userIdStr = userId.toString(); return this.participants.some((p) => { // Se p è un oggetto popolato (ha _id), usa p._id // Altrimenti p è già un ObjectId const participantId = p._id ? p._id.toString() : p.toString(); return participantId === userIdStr; }); }; // Metodo per verificare se la chat è bloccata per un utente // ✅ FIX: Metodo isBlockedFor (stesso problema) ChatSchema.methods.isBlockedFor = function (userId) { const userIdStr = userId.toString(); return this.blockedBy.some((id) => { const blockedId = id._id ? id._id.toString() : id.toString(); return blockedId === userIdStr; }); }; // 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;