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

// @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) {
      // Обновляем только те поля, которые пользователь может изменять
      user.name = req.body.name || user.name;
      
      // Обрабатываем dateOfBirth, учитывая null и пустые строки
      if (req.body.dateOfBirth === null || req.body.dateOfBirth === '') {
        user.dateOfBirth = undefined; // Удаляем поле, если оно пустое или null
      } else if (req.body.dateOfBirth) {
        user.dateOfBirth = req.body.dateOfBirth;
      }
      
      // Обрабатываем 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, учитывая null и пустые строки
      if (req.body.bio === null) {
        user.bio = ''; // Устанавливаем пустую строку, если null
      } else {
        user.bio = req.body.bio || user.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;
        }
      }

      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;

    // TODO: Более сложная логика фильтрации и сортировки
    const users = await User.find({ 
        _id: { $ne: currentUserId },
        // Можно добавить условие, чтобы у пользователя было хотя бы одно фото
        // 'photos.0': { $exists: true } // Если нужно показывать только тех, у кого есть фото
    })
      .select('name dateOfBirth gender bio photos preferences.ageRange'); // photos все еще нужны для выбора главной

    const usersWithAgeAndPhoto = users.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);
        if (profilePic) {
          mainPhotoUrl = profilePic.url;
        } else {
          // Если нет явно помеченного главного фото, берем первое из массива
          mainPhotoUrl = user.photos[0].url;
        }
      }
      // -----------------------------------------

      return {
        _id: user._id,
        name: user.name,
        age: age,
        gender: user.gender,
        bio: user.bio,
        mainPhotoUrl: mainPhotoUrl, // <--- Добавляем URL главной фотографии
        // photos: user.photos, // Отправлять весь массив фото здесь, возможно, избыточно для карточки свайпа
                                // Если нужна только одна фото, то mainPhotoUrl достаточно.
                                // Если нужны несколько превью - можно вернуть ограниченное количество.
      };
    });
    
    res.status(200).json(usersWithAgeAndPhoto);

  } 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);
  }
};


module.exports = {
  updateUserProfile,
  getUsersForSwiping,
  uploadUserProfilePhoto,
  setMainPhoto, // <--- Добавлено
  deletePhoto,  // <--- Добавлено
  // getUserById,
};