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;