// backend/controllers/conversationController.js
const Conversation = require('../models/Conversation');
const Message = require('../models/Message');
const User = require('../models/User'); // Может понадобиться для populate

// @desc    Создать новый диалог (или найти существующий)
// @route   POST /api/conversations
// @access  Private
// Этот эндпоинт может быть вызван, например, когда пользователи мэтчатся,
// или когда один пользователь хочет начать чат с другим из списка мэтчей.
// Мы будем предполагать, что в теле запроса приходит ID другого участника.
const createOrGetConversation = async (req, res, next) => {
  const currentUserId = req.user._id;
  const { otherUserId } = req.body; // ID другого участника

  if (!otherUserId) {
    const error = new Error('Не указан ID другого участника (otherUserId).');
    error.statusCode = 400;
    return next(error);
  }

  if (currentUserId.equals(otherUserId)) {
    const error = new Error('Нельзя создать диалог с самим собой.');
    error.statusCode = 400;
    return next(error);
  }
  
  try {
    // Ищем существующий диалог между этими двумя пользователями
    // Используем $all, чтобы порядок участников в массиве не имел значения
    let conversation = await Conversation.findOne({
      participants: { $all: [currentUserId, otherUserId] }
    })
    .populate('participants', 'name photos') // Загружаем немного данных об участниках
    .populate({ // Загружаем последнее сообщение и данные его отправителя
        path: 'lastMessage',
        populate: { path: 'sender', select: 'name photos' }
    });

    if (conversation) {
      console.log(`[CONV_CTRL] Найден существующий диалог: ${conversation._id}`);
      return res.status(200).json(conversation);
    }

    // Если диалога нет, создаем новый
    console.log(`[CONV_CTRL] Создание нового диалога между ${currentUserId} и ${otherUserId}`);
    conversation = new Conversation({
      participants: [currentUserId, otherUserId]
    });
    await conversation.save();
    
    // Загружаем данные после сохранения, чтобы получить _id и populate участников
    const newConversation = await Conversation.findById(conversation._id)
        .populate('participants', 'name photos')
        // lastMessage пока будет null

    res.status(201).json(newConversation);

  } catch (error) {
    console.error('[CONV_CTRL] Ошибка при создании/получении диалога:', error.message);
    next(error);
  }
};


// @desc    Получить все диалоги текущего пользователя
// @route   GET /api/conversations
// @access  Private
const getUserConversations = async (req, res, next) => {
  try {
    let conversations = await Conversation.find({ participants: req.user._id })
      .populate('participants', 'name photos dateOfBirth gender') // Загружаем нужные поля
      .populate({
        path: 'lastMessage',
        populate: { path: 'sender', select: 'name photos _id' } // Добавил _id отправителя и photos
      })
      .sort({ updatedAt: -1 }); // Сортируем по последнему обновлению (новое сообщение обновит updatedAt)

    // Добавляем mainPhotoUrl и возраст для участников
    conversations = conversations.map(conv => {
      const convObj = conv.toObject(); // Преобразуем в обычный объект для модификации
      convObj.participants = convObj.participants.map(p => {
        let mainPhotoUrl = null;
        if (p.photos && p.photos.length > 0) {
          const profilePic = p.photos.find(photo => photo.isProfilePhoto === true);
          mainPhotoUrl = profilePic ? profilePic.url : p.photos[0].url;
        }
        
        let age = null;
        if (p.dateOfBirth) {
            const birthDate = new Date(p.dateOfBirth);
            const today = new Date();
            age = today.getFullYear() - birthDate.getFullYear();
            const m = today.getMonth() - birthDate.getMonth();
            if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
              age--;
            }
        }
        // Удаляем исходные поля photos и dateOfBirth из участника, если они не нужны напрямую клиенту в этом контексте
        const { photos, dateOfBirth, ...participantRest } = p;
        return { ...participantRest, mainPhotoUrl, age }; // Возвращаем участника с доп. полями
      });

      // Обработка фото для отправителя последнего сообщения, если оно есть
      if (convObj.lastMessage && convObj.lastMessage.sender && convObj.lastMessage.sender.photos && convObj.lastMessage.sender.photos.length > 0) {
        const sender = convObj.lastMessage.sender;
        let senderMainPhotoUrl = null;
        const profilePic = sender.photos.find(photo => photo.isProfilePhoto === true);
        senderMainPhotoUrl = profilePic ? profilePic.url : sender.photos[0].url;
        
        const { photos, ...senderRest } = sender;
        convObj.lastMessage.sender = { ...senderRest, mainPhotoUrl: senderMainPhotoUrl };
      } else if (convObj.lastMessage && convObj.lastMessage.sender) {
        // Если фото нет, убедимся, что mainPhotoUrl null и photos не передается
        const { photos, ...senderRest } = convObj.lastMessage.sender;
        convObj.lastMessage.sender = { ...senderRest, mainPhotoUrl: null };
      }


      return convObj;
    });

    res.status(200).json(conversations);
  } catch (error) {
    console.error('[CONV_CTRL] Ошибка при получении диалогов:', error.message);
    next(error);
  }
};


// @desc    Получить сообщения для конкретного диалога (с пагинацией)
// @route   GET /api/conversations/:conversationId/messages
// @access  Private
const getMessagesForConversation = async (req, res, next) => {
  const { conversationId } = req.params;
  const currentUserId = req.user._id;

  // Пагинация (пример)
  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 20; // Например, 20 сообщений на страницу
  const skip = (page - 1) * limit;

  try {
    // 1. Проверить, является ли текущий пользователь участником этого диалога
    // и сразу загрузить участников
    const conversation = await Conversation.findById(conversationId)
      .populate('participants', 'name photos dateOfBirth gender'); // Загружаем участников здесь

    if (!conversation || !conversation.participants.some(p => p._id.equals(currentUserId))) {
      const error = new Error('Диалог не найден или у вас нет к нему доступа.');
      error.statusCode = 404; // Или 403 Forbidden
      return next(error);
    }

    // 2. Получить сообщения с пагинацией, отсортированные по дате создания (старые -> новые)
    // Чтобы отображать в чате снизу вверх, или новые -> старые для отображения сверху вниз
    const messages = await Message.find({ conversationId: conversationId })
      .populate('sender', 'name photos _id') // Загружаем данные отправителя, включая _id
      .sort({ createdAt: -1 }) // Сначала новые, если нужно отображать с конца
      .skip(skip)
      .limit(limit);
    
    // Обработка сообщений для добавления mainPhotoUrl отправителю и добавления status
    const processedMessages = messages.map(msg => {
      const msgObj = msg.toObject(); // Преобразуем в обычный объект для модификации
      
      // Добавляем mainPhotoUrl для отправителя сообщения
      if (msgObj.sender && msgObj.sender.photos && msgObj.sender.photos.length > 0) {
        let senderMainPhotoUrl = null;
        const profilePic = msgObj.sender.photos.find(photo => photo.isProfilePhoto === true);
        senderMainPhotoUrl = profilePic ? profilePic.url : msgObj.sender.photos[0].url;
        msgObj.sender.mainPhotoUrl = senderMainPhotoUrl;
      } else if (msgObj.sender) {
        // Если у отправителя нет фото, явно устанавливаем mainPhotoUrl в null
        msgObj.sender.mainPhotoUrl = null;
      }
      
      // Добавляем информацию о статусе сообщения
      // Если статус не установлен, определяем его на основе readBy
      if (!msgObj.status) {
        if (msgObj.readBy && msgObj.readBy.length > 0) {
          msgObj.status = 'read';
        } else {
          msgObj.status = 'delivered';
        }
      }
      
      return msgObj;
    });

    const totalMessages = await Message.countDocuments({ conversationId: conversationId });

    // Обработка данных диалога для добавления mainPhotoUrl и возраста участникам
    const convObject = conversation.toObject();
    convObject.participants = convObject.participants.map(p => {
      let mainPhotoUrl = null;
      if (p.photos && p.photos.length > 0) {
        const profilePic = p.photos.find(photo => photo.isProfilePhoto === true);
        mainPhotoUrl = profilePic ? profilePic.url : p.photos[0].url;
      }
      
      let age = null;
      if (p.dateOfBirth) {
          const birthDate = new Date(p.dateOfBirth);
          const today = new Date();
          age = today.getFullYear() - birthDate.getFullYear();
          const m = today.getMonth() - birthDate.getMonth();
          if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
            age--;
          }
      }
      const { photos, dateOfBirth, ...participantRest } = p; // p здесь это Mongoose документ, нужно p.toObject() или работать с полями напрямую
      return { 
        _id: p._id, 
        name: p.name, 
        gender: p.gender, 
        mainPhotoUrl, 
        age 
      };
    });


    res.status(200).json({
      conversation: convObject, // <--- ВОТ ЗДЕСЬ ДОБАВЛЯЕМ ДАННЫЕ ДИАЛОГА
      messages: processedMessages.reverse(), // reverse(), чтобы старые были в начале массива (для типичного отображения чата)
      currentPage: page,
      totalPages: Math.ceil(totalMessages / limit),
      totalMessages
    });
  } catch (error) {
    console.error(`[CONV_CTRL] Ошибка при получении сообщений для диалога ${conversationId}:`, error.message);
    next(error);
  }
};

// @desc    Удалить сообщение
// @route   DELETE /api/conversations/:conversationId/messages/:messageId
// @access  Private
const deleteMessage = async (req, res, next) => {
  const { conversationId, messageId } = req.params;
  const currentUserId = req.user._id;

  try {
    const conversation = await Conversation.findById(conversationId);
    if (!conversation) {
      const error = new Error('Диалог не найден.');
      error.statusCode = 404;
      return next(error);
    }

    if (!conversation.participants.includes(currentUserId)) {
      const error = new Error('Вы не являетесь участником этого диалога.');
      error.statusCode = 403;
      return next(error);
    }

    const message = await Message.findById(messageId);
    if (!message) {
      const error = new Error('Сообщение не найдено.');
      error.statusCode = 404;
      return next(error);
    }

    if (!message.sender.equals(currentUserId)) {
      const error = new Error('Вы можете удалять только свои сообщения.');
      error.statusCode = 403;
      return next(error);
    }

    // Проверяем, является ли удаляемое сообщение последним в диалоге
    const isLastMessage = conversation.lastMessage && conversation.lastMessage.equals(messageId);

    await Message.findByIdAndDelete(messageId);

    // Если удаленное сообщение было последним, обновить lastMessage в диалоге
    if (isLastMessage) {
      const newLastMessage = await Message.findOne({ conversationId })
        .sort({ createdAt: -1 }); // Находим самое новое сообщение      
      conversation.lastMessage = newLastMessage ? newLastMessage._id : null;
      await conversation.save();
    }
    
    // Эмитим событие удаления сообщения в комнату диалога
    // Предполагается, что `io` доступен через `req.app.get('io')`
    const io = req.app.get('io');
    if (io) {
      io.to(conversationId).emit('messageDeleted', { 
        messageId, 
        conversationId,
        deleterId: currentUserId 
      });
      console.log(`[CONV_CTRL] Emitted messageDeleted to room ${conversationId} for message ${messageId}`);
    } else {
      console.warn('[CONV_CTRL] Socket.io instance (io) not found on req.app. Could not emit messageDeleted.');
    }

    res.status(200).json({ message: 'Сообщение успешно удалено.' });

  } catch (error) {
    console.error(`[CONV_CTRL] Ошибка при удалении сообщения ${messageId} из диалога ${conversationId}:`, error.message);
    next(error);
  }
};

// @desc    Редактировать сообщение
// @route   PUT /api/conversations/:conversationId/messages/:messageId
// @access  Private
const editMessage = async (req, res, next) => {
  const { conversationId, messageId } = req.params;
  const { text } = req.body;
  const currentUserId = req.user._id;

  if (!text || text.trim() === '') {
    const error = new Error('Текст сообщения не может быть пустым.');
    error.statusCode = 400;
    return next(error);
  }

  try {
    const conversation = await Conversation.findById(conversationId);
    if (!conversation) {
      const error = new Error('Диалог не найден.');
      error.statusCode = 404;
      return next(error);
    }

    if (!conversation.participants.includes(currentUserId)) {
      const error = new Error('Вы не являетесь участником этого диалога.');
      error.statusCode = 403;
      return next(error);
    }

    const message = await Message.findById(messageId);
    if (!message) {
      const error = new Error('Сообщение не найдено.');
      error.statusCode = 404;
      return next(error);
    }

    if (!message.sender.equals(currentUserId)) {
      const error = new Error('Вы можете редактировать только свои сообщения.');
      error.statusCode = 403;
      return next(error);
    }

    // Ограничение по времени на редактирование (например, 24 часа)
    // const twentyFourHours = 24 * 60 * 60 * 1000;
    // if (new Date() - new Date(message.createdAt) > twentyFourHours) {
    //   const error = new Error('Сообщение не может быть отредактировано по истечении 24 часов.');
    //   error.statusCode = 403;
    //   return next(error);
    // }

    message.text = text.trim();
    message.isEdited = true;
    message.editedAt = new Date();
    
    const updatedMessage = await message.save();
    
    // Загружаем данные отправителя для ответа клиенту
    await updatedMessage.populate('sender', 'name photos _id');


    // Эмитим событие редактирования сообщения в комнату диалога
    const io = req.app.get('io');
    if (io) {
      io.to(conversationId).emit('messageEdited', { 
        message: updatedMessage.toObject(), // Отправляем обновленное сообщение целиком
        conversationId,
      });
      console.log(`[CONV_CTRL] Emitted messageEdited to room ${conversationId} for message ${messageId}`);
    } else {
      console.warn('[CONV_CTRL] Socket.io instance (io) not found on req.app. Could not emit messageEdited.');
    }

    res.status(200).json(updatedMessage);

  } catch (error) {
    console.error(`[CONV_CTRL] Ошибка при редактировании сообщения ${messageId} из диалога ${conversationId}:`, error.message);
    next(error);
  }
};


module.exports = {
  createOrGetConversation,
  getUserConversations,
  getMessagesForConversation,
  deleteMessage,
  editMessage, // <-- Добавляем новый метод
};