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;
