const User = require('../models/User');
const cloudinary = require('../config/cloudinaryConfig'); // Импортируем настроенный Cloudinary SDK
const path = require('path'); // Может понадобиться для получения расширения файла
const ProfileView = require('../models/ProfileView');
const profanityFilter = require('../utils/profanityFilter'); // Импортируем фильтр запрещённых слов

// @desc    Обновить профиль пользователя
// @route   PUT /api/users/profile 
// @access  Private (пользователь должен быть аутентифицирован)
const updateUserProfile = async (req, res, next) => {
  try {
    console.log('Запрос на обновление профиля от пользователя:', req.user._id);
    console.log('Данные для обновления:', req.body);
    
    // req.user должен быть доступен благодаря middleware 'protect'
    const user = await User.findById(req.user._id);

    if (user) {
      // Проверяем имя на запрещённые слова, если оно было изменено
      if (req.body.name && req.body.name !== user.name) {
        if (await profanityFilter.isProfane(req.body.name)) {
          res.status(400);
          throw new Error('Имя содержит запрещённые слова. Пожалуйста, используйте другое имя.');
        }
      }
      
      // Обновляем только те поля, которые пользователь может изменять
      user.name = req.body.name || user.name;
      
      // Обрабатываем dateOfBirth, но не позволяем удалять её
      if (req.body.dateOfBirth && req.body.dateOfBirth !== '') {
        user.dateOfBirth = req.body.dateOfBirth;
      }
      // Примечание: Мы больше не позволяем устанавливать dateOfBirth в undefined
      
      // Обрабатываем gender, учитывая null и пустые строки
      if (req.body.gender === null || req.body.gender === '') {
        user.gender = undefined; // Удаляем поле, если оно пустое или null
      } else if (req.body.gender) {
        user.gender = req.body.gender;
      }
      
      // Проверяем bio на запрещённые слова перед установкой
      if (req.body.bio !== undefined && req.body.bio !== null) {
        if (req.body.bio !== '' && await profanityFilter.isProfane(req.body.bio)) {
          res.status(400);
          throw new Error('Ваша биография содержит запрещённые слова. Пожалуйста, отредактируйте текст.');
        }
        user.bio = req.body.bio;
      }
      
      // Обновление местоположения (если передано)
      if (req.body.location) {
        user.location.city = req.body.location.city || user.location.city;
        user.location.country = req.body.location.country || user.location.country;
      }

      // Обновление предпочтений (если переданы)
      if (req.body.preferences) {
        if (req.body.preferences.gender) {
            user.preferences.gender = req.body.preferences.gender;
        }
        if (req.body.preferences.ageRange) {
            user.preferences.ageRange.min = req.body.preferences.ageRange.min || user.preferences.ageRange.min;
            user.preferences.ageRange.max = req.body.preferences.ageRange.max || user.preferences.ageRange.max;
        }
        // Обновление предпочтений по городу
        if (req.body.preferences.cityPreferences) {
            if (typeof req.body.preferences.cityPreferences.sameCity === 'boolean') {
                user.preferences.cityPreferences.sameCity = req.body.preferences.cityPreferences.sameCity;
            }
            if (Array.isArray(req.body.preferences.cityPreferences.allowedCities)) {
                user.preferences.cityPreferences.allowedCities = req.body.preferences.cityPreferences.allowedCities;
            }
        }
      }

      console.log('Данные пользователя перед сохранением:', user);
      const updatedUser = await user.save();
      console.log('Профиль успешно обновлен:', updatedUser);

      res.status(200).json({
        _id: updatedUser._id,
        name: updatedUser.name,
        email: updatedUser.email,
        dateOfBirth: updatedUser.dateOfBirth,
        gender: updatedUser.gender,
        bio: updatedUser.bio,
        photos: updatedUser.photos,
        location: updatedUser.location,
        preferences: updatedUser.preferences,
        message: 'Профиль успешно обновлен!'
      });
    } else {
      res.status(404);
      throw new Error('Пользователь не найден.');
    }
  } catch (error) {
    console.error(`Ошибка в ${req.method} ${req.originalUrl}:`, error.message); // Более информативный лог

    // Устанавливаем statusCode на объекте ошибки, если он еще не установлен
    // или если мы хотим его переопределить для этого конкретного случая
    if (error.name === 'ValidationError' || error.name === 'CastError') {
      error.statusCode = 400;
    } else if (error.message === 'Пользователь не найден.') { // Если мы сами выбросили эту ошибку с throw
      error.statusCode = 404;
    } else if (!error.statusCode) { 
      // Если это какая-то другая ошибка без явно установленного statusCode,
      // можно считать ее серверной ошибкой.
      error.statusCode = 500; 
    }
    
    // Передаем ошибку (с установленным error.statusCode) в наш центральный errorHandler
    next(error); 
  }
};

const getUsersForSwiping = async (req, res, next) => {
  try {
    const currentUserId = req.user._id;
    
    // Получаем данные текущего пользователя для фильтрации рекомендаций
    const currentUser = await User.findById(currentUserId)
      .select('preferences location dateOfBirth liked passed');

    if (!currentUser) {
      const error = new Error('Пользователь не найден.');
      error.statusCode = 404;
      return next(error);
    }

    // Вычисляем возраст текущего пользователя
    let currentUserAge = null;
    if (currentUser.dateOfBirth) {
      const birthDate = new Date(currentUser.dateOfBirth);
      const today = new Date();
      currentUserAge = today.getFullYear() - birthDate.getFullYear();
      const m = today.getMonth() - birthDate.getMonth();
      if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
        currentUserAge--;
      }
    }

    // Автоматически устанавливаем возрастные предпочтения ±2 года, если они не заданы
    let ageRangeMin = 18;
    let ageRangeMax = 99;
    
    if (currentUser.preferences?.ageRange?.min && currentUser.preferences?.ageRange?.max) {
      // Используем пользовательские настройки
      ageRangeMin = currentUser.preferences.ageRange.min;
      ageRangeMax = currentUser.preferences.ageRange.max;
    } else if (currentUserAge) {
      // Устанавливаем ±2 года от возраста пользователя по умолчанию
      ageRangeMin = Math.max(18, currentUserAge - 2);
      ageRangeMax = Math.min(99, currentUserAge + 2);
      console.log(`[USER_CTRL] Автоматически установлен возрастной диапазон: ${ageRangeMin}-${ageRangeMax} для пользователя ${currentUserAge} лет`);
    }

    // Строим базовый фильтр
    let matchFilter = {
      _id: { 
        $ne: currentUserId,
        $nin: [...(currentUser.liked || []), ...(currentUser.passed || [])] // Исключаем уже просмотренных
      },
      isActive: true, // Только активные пользователи
      isAdmin: { $ne: true } // Не включать администраторов в выборку
    };

    // Фильтрация по полу согласно предпочтениям
    if (currentUser.preferences?.gender && currentUser.preferences.gender !== 'any') {
      matchFilter.gender = currentUser.preferences.gender;
    }

    // Улучшенная фильтрация по городу
    const cityFilter = [];
    
    // Если включена настройка "только мой город" и город указан
    if (currentUser.preferences?.cityPreferences?.sameCity !== false && currentUser.location?.city) {
      cityFilter.push(currentUser.location.city);
    }
    
    // Добавляем дополнительные разрешенные города
    if (currentUser.preferences?.cityPreferences?.allowedCities?.length > 0) {
      cityFilter.push(...currentUser.preferences.cityPreferences.allowedCities);
    }
    
    // Применяем фильтр по городу только если есть что фильтровать
    if (cityFilter.length > 0) {
      // Убираем дубликаты
      const uniqueCities = [...new Set(cityFilter)];
      matchFilter['location.city'] = { $in: uniqueCities };
      console.log(`[USER_CTRL] Фильтрация по городам: ${uniqueCities.join(', ')}`);
    }

    // Получаем пользователей с базовой фильтрацией
    const users = await User.find(matchFilter)
      .select('name dateOfBirth gender bio photos location preferences.ageRange preferences.gender');

    // Дополнительная фильтрация по возрасту и взаимным предпочтениям
    const filteredUsers = users.filter(user => {
      // Вычисляем возраст пользователя
      let userAge = null;
      if (user.dateOfBirth) {
        const birthDate = new Date(user.dateOfBirth);
        const today = new Date();
        userAge = today.getFullYear() - birthDate.getFullYear();
        const m = today.getMonth() - birthDate.getMonth();
        if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
          userAge--;
        }
      }

      // Проверяем возрастные предпочтения текущего пользователя
      if (userAge) {
        if (userAge < ageRangeMin || userAge > ageRangeMax) {
          return false;
        }
      }

      // Проверяем взаимные предпочтения по полу
      if (user.preferences?.gender && user.preferences.gender !== 'any' && currentUser.gender) {
        if (user.preferences.gender !== currentUser.gender) {
          return false;
        }
      }

      // Проверяем взаимные возрастные предпочтения
      if (currentUserAge && user.preferences?.ageRange) {
        const { min = 18, max = 99 } = user.preferences.ageRange;
        if (currentUserAge < min || currentUserAge > max) {
          return false;
        }
      }

      return true;
    });

    // Формируем ответ с дополнительными данными
    const usersWithAgeAndPhoto = filteredUsers.map(user => {
      let age = null;
      if (user.dateOfBirth) {
        const birthDate = new Date(user.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--;
        }
      }

      // Логика выбора главной фотографии
      let mainPhotoUrl = null;
      if (user.photos && user.photos.length > 0) {
        const profilePic = user.photos.find(photo => photo.isProfilePhoto === true);
        mainPhotoUrl = profilePic ? profilePic.url : user.photos[0].url;
      }

      return {
        _id: user._id,
        name: user.name,
        age: age,
        gender: user.gender,
        bio: user.bio,
        mainPhotoUrl: mainPhotoUrl,
        photos: user.photos,
        location: user.location
      };
    });

    // Улучшенная сортировка пользователей
    const sortedUsers = usersWithAgeAndPhoto.sort((a, b) => {
      // 1. Приоритет пользователям из того же города
      const aInSameCity = a.location?.city === currentUser.location?.city;
      const bInSameCity = b.location?.city === currentUser.location?.city;
      
      if (aInSameCity && !bInSameCity) return -1;
      if (!aInSameCity && bInSameCity) return 1;
      
      // 2. Если оба из одного города или оба из разных, сортируем по близости возраста
      if (currentUserAge && a.age && b.age) {
        const aDiff = Math.abs(a.age - currentUserAge);
        const bDiff = Math.abs(b.age - currentUserAge);
        if (aDiff !== bDiff) {
          return aDiff - bDiff;
        }
      }
      
      // 3. Приоритет пользователям с фотографиями
      const aHasPhotos = a.photos && a.photos.length > 0;
      const bHasPhotos = b.photos && b.photos.length > 0;
      
      if (aHasPhotos && !bHasPhotos) return -1;
      if (!aHasPhotos && bHasPhotos) return 1;
      
      // 4. Приоритет пользователям с био
      const aHasBio = a.bio && a.bio.trim().length > 0;
      const bHasBio = b.bio && b.bio.trim().length > 0;
      
      if (aHasBio && !bHasBio) return -1;
      if (!aHasBio && bHasBio) return 1;
      
      return 0;
    });
    
    console.log(`[USER_CTRL] Найдено ${sortedUsers.length} пользователей для рекомендаций (возраст: ${ageRangeMin}-${ageRangeMax})`);
    res.status(200).json(sortedUsers);

  } catch (error) {
    console.error('Ошибка при получении пользователей для свайпа:', error.message);
    next(error);
  }
};

const uploadUserProfilePhoto = async (req, res, next) => {
  try {
    const user = await User.findById(req.user._id);

    if (!user) {
      const error = new Error('Пользователь не найден.');
      error.statusCode = 404;
      return next(error);
    }

    if (!req.file) { // req.file будет добавлен multer'ом
      const error = new Error('Файл для загрузки не найден.');
      error.statusCode = 400;
      return next(error);
    }

    console.log('[USER_CTRL] Получен файл для загрузки:', req.file.originalname, 'Размер:', req.file.size);

    // Проверяем инициализацию Cloudinary
    if (!cloudinary || !cloudinary.uploader) {
      console.error('[USER_CTRL] Ошибка: Cloudinary не настроен');
      const error = new Error('Ошибка настройки службы хранения файлов.');
      error.statusCode = 500;
      return next(error);
    }

    // Загрузка файла в Cloudinary
    const b64 = Buffer.from(req.file.buffer).toString("base64");
    let dataURI = "data:" + req.file.mimetype + ";base64," + b64;
    
    const result = await cloudinary.uploader.upload(dataURI, {
      folder: `dating_app/user_photos/${user._id}`,
      resource_type: 'image',
    });

    console.log('[USER_CTRL] Файл успешно загружен в Cloudinary:', result.secure_url);

    const newPhoto = {
      url: result.secure_url,
      public_id: result.public_id,
      // Если это первая фотография, делаем ее главной. Иначе - нет.
      isProfilePhoto: user.photos.length === 0, 
    };

    // Добавляем новое фото в массив фотографий пользователя
    user.photos.push(newPhoto);
    await user.save();
    
    // Получаем обновленного пользователя с обновленным массивом фотографий
    const updatedUser = await User.findById(req.user._id).lean(); // .lean() для простого объекта
    
    // Важно! Явно создаем массив allPhotos для ответа, чтобы убедиться, что структура каждого объекта фото совпадает
    const allPhotos = updatedUser.photos.map(photo => ({
      _id: photo._id, // Добавляем _id для фото
      url: photo.url,
      public_id: photo.public_id,
      isProfilePhoto: photo.isProfilePhoto
    }));

    // Найдем только что добавленное фото в обновленном массиве, чтобы вернуть его с _id
    const addedPhotoWithId = allPhotos.find(p => p.public_id === newPhoto.public_id);

    // Возвращаем ответ с точной структурой, ожидаемой тестами
    res.status(200).json({
      message: 'Фотография успешно загружена!',
      photo: addedPhotoWithId, // Возвращаем фото с _id
      allPhotos: allPhotos
    });

  } catch (error) {
    console.error('[USER_CTRL] Ошибка при загрузке фотографии:', error.message, error.stack);
    if (error.http_code) {
        error.statusCode = error.http_code;
    }
    next(error);
  }
};

// @desc    Установить фотографию как главную
// @route   PUT /api/users/profile/photo/:photoId/set-main
// @access  Private
const setMainPhoto = async (req, res, next) => {
  try {
    const user = await User.findById(req.user._id);
    const { photoId } = req.params;

    if (!user) {
      const error = new Error('Пользователь не найден.');
      error.statusCode = 404;
      return next(error);
    }

    let photoFound = false;
    user.photos.forEach(photo => {
      if (photo._id.toString() === photoId) {
        photo.isProfilePhoto = true;
        photoFound = true;
      } else {
        photo.isProfilePhoto = false;
      }
    });

    if (!photoFound) {
      const error = new Error('Фотография не найдена.');
      error.statusCode = 404;
      return next(error);
    }

    await user.save();
    const updatedUser = await User.findById(req.user._id).lean();

    res.status(200).json({
      message: 'Главная фотография успешно обновлена.',
      photos: updatedUser.photos.map(p => ({_id: p._id, url: p.url, public_id: p.public_id, isProfilePhoto: p.isProfilePhoto }))
    });

  } catch (error) {
    console.error('[USER_CTRL] Ошибка при установке главной фотографии:', error.message);
    next(error);
  }
};

// @desc    Удалить фотографию пользователя
// @route   DELETE /api/users/profile/photo/:photoId
// @access  Private
const deletePhoto = async (req, res, next) => {
  try {
    const user = await User.findById(req.user._id);
    const { photoId } = req.params;

    if (!user) {
      const error = new Error('Пользователь не найден.');
      error.statusCode = 404;
      return next(error);
    }

    const photoIndex = user.photos.findIndex(p => p._id.toString() === photoId);

    if (photoIndex === -1) {
      const error = new Error('Фотография не найдена.');
      error.statusCode = 404;
      return next(error);
    }

    const photoToDelete = user.photos[photoIndex];

    // Удаление из Cloudinary
    if (photoToDelete.public_id) {
      try {
        await cloudinary.uploader.destroy(photoToDelete.public_id);
        console.log(`[USER_CTRL] Фото ${photoToDelete.public_id} удалено из Cloudinary.`);
      } catch (cloudinaryError) {
        console.error('[USER_CTRL] Ошибка при удалении фото из Cloudinary:', cloudinaryError.message);
        // Не прерываем процесс, если фото не удалось удалить из Cloudinary, но логируем ошибку
        // Можно добавить более сложную логику обработки, например, пометить фото для последующего удаления
      }
    }

    // Удаление из массива photos пользователя
    user.photos.splice(photoIndex, 1);

    // Если удаленная фотография была главной и остались другие фотографии,
    // делаем первую из оставшихся главной.
    if (photoToDelete.isProfilePhoto && user.photos.length > 0) {
      user.photos[0].isProfilePhoto = true;
    }

    await user.save();
    const updatedUser = await User.findById(req.user._id).lean();

    res.status(200).json({
      message: 'Фотография успешно удалена.',
      photos: updatedUser.photos.map(p => ({_id: p._id, url: p.url, public_id: p.public_id, isProfilePhoto: p.isProfilePhoto }))
    });

  } catch (error) {
    console.error('[USER_CTRL] Ошибка при удалении фотографии:', error.message);
    next(error);
  }
};

// @desc    Получить профиль пользователя по ID (для просмотра чужих профилей)
// @route   GET /api/users/:userId
// @access  Private
const getUserById = async (req, res, next) => {
  try {
    const { userId } = req.params;
    const currentUserId = req.user._id;

    // Проверяем, что пользователь не запрашивает свой собственный профиль
    // (для этого есть отдельный роут /auth/me)
    if (currentUserId.equals(userId)) {
      const error = new Error('Для получения своего профиля используйте /auth/me');
      error.statusCode = 400;
      return next(error);
    }

    // Находим пользователя по ID
    const user = await User.findById(userId)
      .select('name dateOfBirth gender bio photos location createdAt');

    if (!user) {
      const error = new Error('Пользователь не найден.');
      error.statusCode = 404;
      return next(error);
    }

    // Вычисляем возраст, если указана дата рождения
    let age = null;
    if (user.dateOfBirth) {
      const birthDate = new Date(user.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 userProfile = {
      _id: user._id,
      name: user.name,
      age: age,
      gender: user.gender,
      bio: user.bio,
      photos: user.photos,
      location: user.location,
      memberSince: user.createdAt
    };

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

  } catch (error) {
    console.error('[USER_CTRL] Ошибка при получении профиля пользователя:', error.message);
    next(error);
  }
};

// @desc    Записать просмотр профиля пользователя
// @route   POST /api/users/:userId/view
// @access  Private
const recordProfileView = async (req, res, next) => {
  try {
    const { userId } = req.params;
    const viewerId = req.user._id;
    const { source = 'other' } = req.body;

    // Проверяем, что пользователь не пытается просматривать свой собственный профиль
    if (viewerId.equals(userId)) {
      return res.status(200).json({ message: 'Просмотр собственного профиля не записывается' });
    }

    // Проверяем, существует ли пользователь, чей профиль просматривают
    const profileOwner = await User.findById(userId);
    if (!profileOwner) {
      const error = new Error('Пользователь не найден.');
      error.statusCode = 404;
      return next(error);
    }

    // Проверяем, был ли уже просмотр от этого пользователя в последние 5 минут
    // Это предотвращает спам просмотров при обновлении страницы
    const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
    const recentView = await ProfileView.findOne({
      viewer: viewerId,
      profileOwner: userId,
      viewedAt: { $gte: fiveMinutesAgo }
    });

    if (recentView) {
      console.log(`[USER_CTRL] Недавний просмотр уже существует для пользователя ${viewerId} -> ${userId}`);
      return res.status(200).json({ message: 'Просмотр уже записан' });
    }

    // Создаем новую запись просмотра
    const newView = new ProfileView({
      viewer: viewerId,
      profileOwner: userId,
      source: source,
      viewedAt: new Date()
    });

    await newView.save();
    
    console.log(`[USER_CTRL] Записан просмотр профиля ${userId} пользователем ${viewerId}, источник: ${source}`);
    
    res.status(200).json({ 
      message: 'Просмотр профиля записан',
      viewId: newView._id
    });

  } catch (error) {
    console.error('[USER_CTRL] Ошибка при записи просмотра профиля:', error.message);
    next(error);
  }
};

// @desc    Получить статистику пользователя для главной страницы
// @route   GET /api/users/stats
// @access  Private
const getUserStats = async (req, res, next) => {
  try {
    const currentUserId = req.user._id;
    
    // 1. Получаем количество лайков (кто лайкнул текущего пользователя)
    const likesCount = await User.countDocuments({
      liked: currentUserId
    });
    
    // 2. Получаем количество совпадений (matches)
    const matchesCount = await User.findById(currentUserId)
      .select('matches')
      .then(user => user?.matches?.length || 0);
    
    // 3. Получаем количество непрочитанных сообщений
    const Conversation = require('../models/Conversation');
    const Message = require('../models/Message');
    
    // Находим все диалоги пользователя
    const userConversations = await Conversation.find({
      participants: currentUserId
    }).select('_id');
    
    const conversationIds = userConversations.map(conv => conv._id);
    
    // Считаем непрочитанные сообщения в этих диалогах
    const unreadMessagesCount = await Message.countDocuments({
      conversationId: { $in: conversationIds },
      sender: { $ne: currentUserId }, // Сообщения от других пользователей
      readBy: { $ne: currentUserId }  // Которые текущий пользователь не читал
    });
    
    // 4. Получаем общее количество сообщений пользователя
    const totalMessagesCount = await Message.countDocuments({
      conversationId: { $in: conversationIds },
      sender: currentUserId // Только сообщения, отправленные текущим пользователем
    });
    
    // 5. Получаем количество просмотров профиля
    const profileViewsCount = await ProfileView.countDocuments({
      profileOwner: currentUserId
    });
    
    const stats = {
      profileViews: profileViewsCount,
      likes: likesCount,
      matches: matchesCount,
      unreadMessages: unreadMessagesCount,
      totalMessages: totalMessagesCount // Добавляем новое значение в ответ
    };
    
    console.log(`[USER_CTRL] Статистика пользователя ${currentUserId}:`, stats);
    
    res.status(200).json(stats);
    
  } catch (error) {
    console.error('[USER_CTRL] Ошибка при получении статистики пользователя:', error.message);
    next(error);
  }
};

module.exports = {
  updateUserProfile,
  getUsersForSwiping,
  uploadUserProfilePhoto,
  setMainPhoto,
  deletePhoto,
  getUserById,
  getUserStats,
  recordProfileView, // <--- Добавляем новую функцию
};