// src/controllers/imageController.js
const fs = require('fs');
const sharp = require('sharp');
const Measurement = require('../models/Measurement');
const StorageService = require('../services/storageService');
const { sendError, asyncHandler } = require('../utils/errorHandler');
const path = require('path');
const config = require('../config');

/**
 * Contrôleur pour les opérations liées aux images
 */
class ImageController {
  /**
   * Récupère une image par projet et ordre ID
   */
  static getImageByProjectAndOrderId = asyncHandler(async (req, res) => {
    const { projectId, orderId } = req.params;
    
    if (!projectId || !orderId || isNaN(projectId) || isNaN(orderId)) {
      return sendError('IDs de projet ou d\'ordre invalides', res, null, 400);
    }
    
    try {
      const measurement = await Measurement.getMeasurementByProjectAndOrderId(projectId, orderId);
      
      if (!measurement) {
        return sendError('Image non trouvée', res, null, 404);
      }
      
      const imagePath = measurement.path;
      
      // Vérifie si l'image existe
      await fs.promises.access(imagePath, fs.constants.F_OK);
      
      res.download(imagePath);
    } catch (error) {
      if (error.code === 'ENOENT') {
        sendError('Image non trouvée sur le disque', res, error, 404);
      } else {
        sendError('Erreur lors de la récupération de l\'image', res, error, 500);
      }
    }
  });

  /**
   * Récupère une image par son ID de mesure
   */
  static getImageByMeasurementId = asyncHandler(async (req, res) => {
    const measurementId = req.params.measurementId;
    
    if (!measurementId || isNaN(measurementId)) {
      return sendError('ID de mesure invalide', res, null, 400);
    }
    
    try {
      const measurement = await Measurement.getMeasurementById(measurementId);
      
      if (!measurement) {
        return sendError('Image non trouvée', res, null, 404);
      }
      
      const imagePath = measurement.path;
      
      // Vérifie si l'image existe
      await fs.promises.access(imagePath, fs.constants.F_OK);
      
      res.download(imagePath);
    } catch (error) {
      if (error.code === 'ENOENT') {
        sendError('Image non trouvée sur le disque', res, error, 404);
      } else {
        sendError('Erreur lors de la récupération de l\'image', res, error, 500);
      }
    }
  });

  /**
   * Récupère un aperçu redimensionné d'une image
   */
  static getImagePreview = asyncHandler(async (req, res) => {
    const { projectId, orderId } = req.params;
    
    if (!projectId || !orderId || isNaN(projectId) || isNaN(orderId)) {
      return sendError('IDs de projet ou d\'ordre invalides', res, null, 400);
    }
    
    try {
      const measurement = await Measurement.getMeasurementByProjectAndOrderId(projectId, orderId);
      
      if (!measurement) {
        return sendError('Image non trouvée', res, null, 404);
      }
      
      const imagePath = measurement.path;
      
      // Vérifie si l'image existe
      await fs.promises.access(imagePath, fs.constants.F_OK);
      
      // Redimensionne l'image
      const metadata = await sharp(imagePath).metadata();
      const width = Math.floor(metadata.width / 7);
      const height = Math.floor(metadata.height / 7);
      
      const resizedImage = await sharp(imagePath)
        .resize(width, height)
        .jpeg({ quality: 65 })
        .toBuffer();
      
      res.set('Content-Type', 'image/jpeg');
      res.send(resizedImage);
    } catch (error) {
      if (error.code === 'ENOENT') {
        sendError('Image non trouvée sur le disque', res, error, 404);
      } else {
        sendError('Erreur lors de la récupération de l\'aperçu de l\'image', res, error, 500);
      }
    }
  });

  /**
   * Télécharge une nouvelle image avec des données de mesure
   */
  static uploadImage = asyncHandler(async (req, res) => {
    const { projectId, timestamp, temperature, humidity } = req.body;
    const image = req.file;
    
    if (!image || !projectId || !timestamp || !temperature || !humidity) {
      return sendError('Tous les champs sont requis', res, null, 400);
    }
    
    try {
      // Obtention du prochain ordre ID
      const nextOrderId = await Measurement.getNextOrderId(projectId);
      
      if (nextOrderId === null) {
        return sendError('Projet non trouvé', res, null, 404);
      }
      
      // Enregistrement de l'image
      const imagePath = await StorageService.measurement.uploadMeasurementImage(
        image, projectId, nextOrderId
      );
      
      // Création de l'entrée dans la base de données
      const measurement = await Measurement.createMeasurement(
        projectId, timestamp, imagePath, temperature, humidity, nextOrderId
      );
      
      res.json({
        message: 'Mesure téléchargée avec succès',
        path: imagePath,
        id: measurement.id
      });
    } catch (error) {
      sendError('Erreur lors du téléchargement de la mesure', res, error, 500);
    }
  });

  /**
   * Récupère une image d'exemple (pour les tests)
   */
  static getSmileImage = asyncHandler(async (req, res) => {
    const imagePath = path.join(config.paths.samples, 'smile.png');
    
    try {
      await fs.promises.access(imagePath, fs.constants.F_OK);
      res.sendFile(imagePath);
    } catch (error) {
      sendError('Image d\'exemple non trouvée', res, error, 404);
    }
  });
}

module.exports = ImageController;