const Chat = require('../models/Chat');
const Message = require('../models/Message');
const { User } = require('../models/user');

// ===== GET USER CHATS =====
exports.getUserChats = async (req, res) => {
  try {
    const userId = req.user._id;
    const idapp = req.user.idapp;
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 20;
    const skip = (page - 1) * limit;

    // ✅ Trova chat dove l'utente è partecipante E non l'ha cancellata
    const chats = await Chat.find({
      idapp,
      participants: userId,
      isActive: true,
      deletedBy: { $ne: userId }, // ✅ Escludi chat cancellate
    })
      .populate('participants', 'username name surname profile')
      .populate({
        path: 'rideId',
        select: 'departure destination departureDate departureTime status',
      })
      .sort({ updatedAt: -1 })
      .skip(skip)
      .limit(limit)
      .lean();

    const enrichedChats = chats.map((chat) => {
      let unreadCount = 0;

      if (chat.unreadCount) {
        if (chat.unreadCount instanceof Map) {
          unreadCount = chat.unreadCount.get(userId.toString()) || 0;
        } else if (typeof chat.unreadCount === 'object') {
          // Dopo .lean(), la Map diventa un oggetto plain
          unreadCount = chat.unreadCount[userId.toString()] || 0;
        }
      }
      return {
        ...chat,
        unreadCount,
      };
    });

    res.json({
      success: true,
      data: enrichedChats,
      pagination: {
        page,
        limit,
        hasMore: chats.length === limit,
      },
    });
  } catch (error) {
    console.error('Error fetching chats:', error);
    res.status(500).json({
      success: false,
      message: 'Errore nel recupero delle chat',
      error: error.message,
    });
  }
};

// ===== GET OR CREATE DIRECT CHAT =====
exports.getOrCreateDirectChat = async (req, res) => {
  try {
    const userId = req.user._id;
    const { otherUserId, rideId } = req.body;
    const idapp = req.user.idapp;

    if (!otherUserId) {
      return res.status(400).json({
        success: false,
        message: 'otherUserId è richiesto',
      });
    }

    // Verifica che l'altro utente esista
    const otherUser = await User.findById(otherUserId);
    if (!otherUser) {
      return res.status(404).json({
        success: false,
        message: 'Utente non trovato',
      });
    }

    // Cerca chat esistente
    let chat = await Chat.findOne({
      idapp,
      type: 'direct',
      participants: { $all: [userId, otherUserId], $size: 2 },
    });

    if (!chat) {
      // Crea nuova chat
      chat = new Chat({
        idapp,
        type: 'direct',
        participants: [userId, otherUserId],
        rideId: rideId || null,
        unreadCount: new Map(),
      });
      await chat.save();
    } else if (rideId && !chat.rideId) {
      // Aggiungi rideId se non presente
      chat.rideId = rideId;
      await chat.save();
    }

    // ✅ Se la chat era stata cancellata da uno dei due, rimuovilo da deletedBy
    if (chat.deletedBy && chat.deletedBy.length > 0) {
      const wasDeleted = chat.deletedBy.some((id) => id.toString() === userId.toString());

      if (wasDeleted) {
        chat.deletedBy = chat.deletedBy.filter((id) => id.toString() !== userId.toString());
        await chat.save();
      }
    }

    // Popola i partecipanti
    await chat.populate('participants', 'username name surname profile');
    if (chat.rideId) {
      await chat.populate('rideId', 'departure destination departureDate');
    }

    // Aggiungi unread count
    const chatObj = chat.toObject();
    chatObj.unreadCount = chat.getUnreadForUser(userId);

    res.json({
      success: true,
      data: chatObj,
    });
  } catch (error) {
    console.error('Error getting/creating direct chat:', error);
    res.status(500).json({
      success: false,
      message: 'Errore nella creazione della chat',
      error: error.message,
    });
  }
};

// ===== GET CHAT BY ID =====
exports.getChatById = async (req, res) => {
  try {
    const userId = req.user._id;
    const { chatId } = req.params;

    const chat = await Chat.findById(chatId)
      .populate('participants', 'username name surname profile')
      .populate({
        path: 'rideId',
        select: 'departure destination departureDate departureTime status',
      })
      .lean();

    if (!chat) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    // Verifica che l'utente sia partecipante
    const isParticipant = chat.participants.some((p) => {
      const pId = p._id ? p._id.toString() : p.toString();
      return pId === userId.toString();
    });

    if (!isParticipant) {
      return res.status(403).json({
        success: false,
        message: 'Non autorizzato',
      });
    }

    // Verifica se l'utente ha cancellato questa chat
    const wasDeleted = chat.deletedBy?.some((id) => id.toString() === userId.toString());

    if (wasDeleted) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    // Aggiungi unread count per l'utente corrente
    let unreadCount = 0;
    if (chat.unreadCount) {
      if (chat.unreadCount instanceof Map) {
        unreadCount = chat.unreadCount.get(userId.toString()) || 0;
      } else if (typeof chat.unreadCount === 'object') {
        unreadCount = chat.unreadCount[userId.toString()] || 0;
      }
    }

    const chatObj = {
      ...chat,
      unreadCount,
    };

    res.json({
      success: true,
      data: chatObj,
    });
  } catch (error) {
    console.error('Error getting chat by ID:', error);
    res.status(500).json({
      success: false,
      message: 'Errore nel recupero della chat',
      error: error.message,
    });
  }
};

// ===== GET CHAT MESSAGES =====
exports.getChatMessages = async (req, res) => {
  try {
    const userId = req.user._id;
    const { chatId } = req.params;
    const idapp = req.user.idapp;
    const page = parseInt(req.query.page) || 1;
    const { before, after, limit = 50 } = req.query;
    const skip = (page - 1) * limit;

    // Verifica chat e partecipazione
    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({
        success: false,
        message: 'Non autorizzato',
      });
    }

    const query = {
      chatId,
      idapp,
      isDeleted: { $ne: true },
    };

    // clearedBefore
    let clearedDate = null;
    if (chat.clearedBefore) {
      if (chat.clearedBefore instanceof Map) {
        clearedDate = chat.clearedBefore.get(userId.toString());
      } else if (typeof chat.clearedBefore === 'object') {
        clearedDate = chat.clearedBefore[userId.toString()];
      }
    }

    if (clearedDate) {
      query.createdAt = { $gt: new Date(clearedDate) };
    }

    // ✅ Paginazione: before (messaggi più vecchi)
    if (before) {
      query.createdAt = {
        ...query.createdAt,
        $lt: new Date(before),
      };
    }

    // ✅ Polling: after (messaggi più nuovi)
    if (after) {
      query.createdAt = {
        ...query.createdAt,
        $gt: new Date(after), // Messaggi DOPO questo timestamp
      };
    }

    // ✅ Ordina in base alla direzione
    const sortOrder = after ? 1 : -1; // after: asc, before: desc

    const messages = await Message.find(query)
      .sort({ createdAt: sortOrder })
      .limit(parseInt(limit))
      .populate('senderId', 'username name surname profile.img profile.avatar')
      .populate({
        path: 'replyTo',
        select: 'text senderId',
        populate: {
          path: 'senderId',
          select: 'username name',
        },
      })
      .lean();

    // ✅ Se usato after, i messaggi sono già in ordine cronologico
    // Se usato before, invertili
    if (!after) {
      messages.reverse();
    }

    // Marca i messaggi come letti
    await chat.markAsRead(userId);

    res.json({
      success: true,
      data: messages.reverse(),
      pagination: {
        page,
        limit,
        hasMore: messages.length === limit,
      },
    });
  } catch (error) {
    console.error('Error fetching messages:', error);
    res.status(500).json({
      success: false,
      message: 'Errore nel recupero dei messaggi',
      error: error.message,
    });
  }
};

// ===== SEND MESSAGE =====
exports.sendMessage = async (req, res) => {
  try {
    const userId = req.user._id;
    const idapp = req.user.idapp;
    const { chatId } = req.params;
    const { text, type = 'text', metadata } = req.body;

    // Verifica chat
    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({
        success: false,
        message: 'Non autorizzato',
      });
    }

    if (chat.isBlockedFor(userId)) {
      return res.status(403).json({
        success: false,
        message: 'Non puoi inviare messaggi in questa chat',
      });
    }

    // ✅ IMPORTANTE: Se qualcuno aveva cancellato la chat, rimuovilo da deletedBy
    // così la chat riappare nella sua lista
    if (chat.deletedBy && chat.deletedBy.length > 0) {
      const otherParticipants = chat.participants.filter((p) => p.toString() !== userId.toString());

      let needsSave = false;
      otherParticipants.forEach((participantId) => {
        const wasDeleted = chat.deletedBy.some((id) => id.toString() === participantId.toString());
        if (wasDeleted) {
          chat.deletedBy = chat.deletedBy.filter((id) => id.toString() !== participantId.toString());
          needsSave = true;
        }
      });

      if (needsSave) {
        await chat.save();
      }
    }

    // Crea messaggio
    const message = new Message({
      idapp,
      chatId: chat._id,
      senderId: userId,
      text,
      type,
      metadata,
      readBy: [userId],
    });

    await message.save();
    await message.populate('senderId', 'username name surname profile');

    // Aggiorna chat
    await chat.updateLastMessage(message);
    await chat.incrementUnread(userId);

    res.json({
      success: true,
      data: message,
    });
  } catch (error) {
    console.error('Error sending message:', error);
    res.status(500).json({
      success: false,
      message: "Errore nell'invio del messaggio",
      error: error.message,
    });
  }
};

// ===== MARK MESSAGES AS READ =====
exports.markAsRead = async (req, res) => {
  try {
    const userId = req.user._id;
    const { chatId } = req.params;

    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({
        success: false,
        message: 'Non autorizzato',
      });
    }

    // Marca come letti
    await chat.markAsRead(userId);

    // Aggiorna anche i singoli messaggi
    await Message.updateMany(
      {
        chatId: chat._id,
        senderId: { $ne: userId },
        readBy: { $ne: userId },
      },
      {
        $addToSet: { readBy: userId },
      }
    );

    res.json({
      success: true,
      message: 'Messaggi marcati come letti',
    });
  } catch (error) {
    console.error('Error marking as read:', error);
    res.status(500).json({
      success: false,
      message: 'Errore nella marcatura dei messaggi',
      error: error.message,
    });
  }
};

// ===== DELETE CHAT (SOFT DELETE) =====
exports.deleteChat = async (req, res) => {
  try {
    const userId = req.user._id;
    const { chatId } = req.params;

    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({
        success: false,
        message: 'Non autorizzato',
      });
    }

    // ✅ Soft delete: aggiungi userId a deletedBy
    if (!chat.deletedBy) {
      chat.deletedBy = [];
    }

    const alreadyDeleted = chat.deletedBy.some((id) => id.toString() === userId.toString());

    if (!alreadyDeleted) {
      chat.deletedBy.push(userId);
    }

    // ✅ Salva il timestamp di quando l'utente ha cancellato
    // così quando riappare la chat, vedrà solo messaggi nuovi
    if (!chat.clearedBefore) {
      chat.clearedBefore = new Map();
    }
    chat.clearedBefore.set(userId.toString(), new Date());

    await chat.save();

    res.json({
      success: true,
      message: 'Chat eliminata',
    });
  } catch (error) {
    console.error('Error deleting chat:', error);
    res.status(500).json({
      success: false,
      message: "Errore nell'eliminazione della chat",
      error: error.message,
    });
  }
};

// ===== TOGGLE MUTE CHAT =====
exports.toggleMuteChat = async (req, res) => {
  try {
    const userId = req.user._id;
    const { chatId } = req.params;
    const { mute } = req.body;

    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({
        success: false,
        message: 'Non autorizzato',
      });
    }

    if (!chat.mutedBy) {
      chat.mutedBy = [];
    }

    if (mute) {
      // Aggiungi a mutedBy se non presente
      const alreadyMuted = chat.mutedBy.some((id) => id.toString() === userId.toString());
      if (!alreadyMuted) {
        chat.mutedBy.push(userId);
      }
    } else {
      // Rimuovi da mutedBy
      chat.mutedBy = chat.mutedBy.filter((id) => id.toString() !== userId.toString());
    }

    await chat.save();

    res.json({
      success: true,
      message: mute ? 'Chat silenziata' : 'Notifiche attivate',
      data: { muted: mute },
    });
  } catch (error) {
    console.error('Error toggling mute:', error);
    res.status(500).json({
      success: false,
      message: "Errore nell'aggiornamento",
      error: error.message,
    });
  }
};

// ===== GET UNREAD COUNT =====
exports.getUnreadCount = async (req, res) => {
  try {
    const userId = req.user._id;
    const idapp = req.user.idapp;

    const chats = await Chat.find({
      idapp,
      participants: userId,
      isActive: true,
      deletedBy: { $ne: userId },
    }).lean();

    let totalUnread = 0;
    chats.forEach((chat) => {
      const unread = chat.unreadCount?.get(userId.toString()) || 0;
      totalUnread += unread;
    });

    res.json({
      success: true,
      data: {
        totalUnread,
        chatCount: chats.length,
      },
    });
  } catch (error) {
    console.error('Error getting unread count:', error);
    res.status(500).json({
      success: false,
      message: 'Errore nel conteggio messaggi non letti',
      error: error.message,
    });
  }
};

/**
 * @desc    Marca una chat come letta
 * @route   PUT /api/viaggi/chats/:chatId/read
 * @access  Private
 */
exports.markChatAsRead = async (req, res) => {
  try {
    const { chatId } = req.params;
    const userId = req.user._id;

    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({
        success: false,
        message: 'Chat non trovata',
      });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({
        success: false,
        message: 'Non sei autorizzato',
      });
    }

    // Reset unread count
    if (!chat.unreadCount) {
      chat.unreadCount = new Map();
    }
    chat.unreadCount.set(userId.toString(), 0);
    chat.markModified('unreadCount');
    await chat.save();

    // Marca messaggi come letti
    await Message.updateMany(
      {
        chatId,
        senderId: { $ne: userId },
        readBy: { $ne: userId },
      },
      {
        $addToSet: { readBy: userId },
      }
    );

    res.json({
      success: true,
      message: 'Chat marcata come letta',
    });
  } catch (error) {
    console.error('Errore marca come letto:', error);
    res.status(500).json({
      success: false,
      message: 'Errore',
      error: error.message,
    });
  }
};

/**
 * @desc    Muta/smuta notifiche
 * @route   PUT /api/viaggi/chats/:chatId/mute
 * @access  Private
 */
exports.toggleMuteChat = async (req, res) => {
  try {
    const { chatId } = req.params;
    const { mute } = req.body;
    const userId = req.user._id;

    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({ success: false, message: 'Chat non trovata' });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({ success: false, message: 'Non sei autorizzato' });
    }

    if (!chat.mutedBy) {
      chat.mutedBy = [];
    }

    const isMuted = chat.mutedBy.some((mid) => mid.toString() === userId.toString());

    if (mute && !isMuted) {
      chat.mutedBy.push(userId);
    } else if (!mute && isMuted) {
      chat.mutedBy = chat.mutedBy.filter((mid) => mid.toString() !== userId.toString());
    }

    await chat.save();

    res.json({
      success: true,
      message: mute ? 'Notifiche disattivate' : 'Notifiche attivate',
      data: { muted: mute },
    });
  } catch (error) {
    console.error('Errore mute chat:', error);
    res.status(500).json({ success: false, message: 'Errore', error: error.message });
  }
};

/**
 * @desc    Elimina un messaggio (soft delete)
 * @route   DELETE /api/viaggi/chats/:chatId/messages/:messageId
 * @access  Private
 */
exports.deleteMessage = async (req, res) => {
  try {
    const { chatId, messageId } = req.params;
    const userId = req.user._id;

    const message = await Message.findById(messageId);

    if (!message) {
      return res.status(404).json({ success: false, message: 'Messaggio non trovato' });
    }

    if (message.chatId.toString() !== chatId) {
      return res.status(400).json({ success: false, message: 'Messaggio non appartiene a questa chat' });
    }

    if (message.senderId.toString() !== userId.toString()) {
      return res.status(403).json({ success: false, message: 'Non sei autorizzato' });
    }

    message.isDeleted = true;
    message.deletedAt = new Date();
    message.text = 'Messaggio eliminato';
    await message.save();

    res.json({ success: true, message: 'Messaggio eliminato' });
  } catch (error) {
    console.error('Errore eliminazione messaggio:', error);
    res.status(500).json({ success: false, message: 'Errore', error: error.message });
  }
};

/**
 * @desc    Blocca/sblocca una chat
 * @route   PUT /api/viaggi/chats/:chatId/block
 * @access  Private
 */
exports.toggleBlockChat = async (req, res) => {
  try {
    const { chatId } = req.params;
    const { block } = req.body;
    const userId = req.user._id;

    const chat = await Chat.findById(chatId);
    if (!chat) {
      return res.status(404).json({ success: false, message: 'Chat non trovata' });
    }

    if (!chat.hasParticipant(userId)) {
      return res.status(403).json({ success: false, message: 'Non sei autorizzato' });
    }

    if (!chat.blockedBy) {
      chat.blockedBy = [];
    }

    const isBlocked = chat.blockedBy.some((bid) => bid.toString() === userId.toString());

    if (block && !isBlocked) {
      chat.blockedBy.push(userId);
    } else if (!block && isBlocked) {
      chat.blockedBy = chat.blockedBy.filter((bid) => bid.toString() !== userId.toString());
    }

    await chat.save();

    res.json({
      success: true,
      message: block ? 'Chat bloccata' : 'Chat sbloccata',
      data: { blocked: block },
    });
  } catch (error) {
    console.error('Errore blocco chat:', error);
    res.status(500).json({ success: false, message: 'Errore', error: error.message });
  }
};

module.exports = exports;
