// src/services/storageService.js
const fs = require('fs').promises;
const path = require('path');
const { Buffer } = require('buffer');
const config = require('../config');

/**
 * Service de gestion du stockage des fichiers
 */
class StorageService {
  /**
   * Crée un dossier s'il n'existe pas déjà
   * @param {string} dirPath - Chemin du dossier à créer
   * @returns {Promise<string>} Chemin du dossier créé
   */
  static async createDirectory(dirPath) {
    try {
      await fs.access(dirPath);
    } catch (error) {
      if (error.code === 'ENOENT') {
        await fs.mkdir(dirPath, { recursive: true });
      } else {
        throw error;
      }
    }
    return dirPath;
  }

  /**
   * Supprime un dossier et son contenu
   * @param {string} dirPath - Chemin du dossier à supprimer
   */
  static async deleteDirectory(dirPath) {
    try {
      await fs.access(dirPath);
      await fs.rm(dirPath, { recursive: true, force: true });
    } catch (error) {
      if (error.code !== 'ENOENT') {
        throw error;
      }
    }
  }

  /**
   * Cherche toutes les images dans un dossier
   * @param {string} dirPath - Dossier à scanner
   * @returns {Promise<Array<string>>} Liste des chemins d'images trouvées
   */
  static async scanImages(dirPath = 'storage') {
    const basePath = path.join(config.paths.storage, dirPath);
    let results = [];

    try {
      await fs.access(basePath);
    } catch (error) {
      if (error.code === 'ENOENT') {
        await fs.mkdir(basePath, { recursive: true });
      } else {
        throw error;
      }
    }

    async function scanDirectory(directory) {
      const files = await fs.readdir(directory);
      for (const file of files) {
        const filePath = path.join(directory, file);
        const stat = await fs.stat(filePath);
        if (stat.isDirectory()) {
          await scanDirectory(filePath);
        } else if (file.endsWith('.jpg')) {
          results.push(filePath);
        }
      }
    }

    await scanDirectory(basePath);
    return results;
  }

  /**
   * Enregistre un contenu dans un fichier
   * @param {string} filePath - Chemin du fichier
   * @param {Buffer} content - Contenu à enregistrer
   */
  static async saveFile(filePath, content) {
    const dirPath = path.dirname(filePath);
    await this.createDirectory(dirPath);
    if (Buffer.isBuffer(content)) {
      await fs.writeFile(filePath, content);
    } else {
      throw new Error('Le contenu doit être un buffer');
    }
  }

  /**
   * Récupère le contenu d'un fichier
   * @param {string} filePath - Chemin du fichier
   * @returns {Promise<Buffer>} Contenu du fichier
   */
  static async getFile(filePath) {
    return await fs.readFile(filePath);
  }

  /**
   * Supprime un fichier
   * @param {string} filePath - Chemin du fichier à supprimer
   * @returns {Promise<string>} Message de confirmation
   */
  static async deleteFile(filePath) {
    try {
      await fs.access(filePath);
      await fs.rm(filePath);
      return `Fichier ${filePath} supprimé avec succès.`;
    } catch (error) {
      if (error.code === 'ENOENT') {
        return `Fichier ${filePath} inexistant.`;
      } else {
        throw error;
      }
    }
  }

  /**
   * Gestionnaire pour les opérations de projet
   */
  static project = {
    /**
     * Crée le répertoire d'un projet
     * @param {number} projectId - ID du projet
     */
    createProjectDirectory: async function(projectId) {
      const projectPath = path.join(config.paths.storage, `${projectId}`);
      await StorageService.createDirectory(projectPath);
      await StorageService.createDirectory(path.join(projectPath, 'images'));
      await StorageService.createDirectory(path.join(projectPath, 'videos'));
      console.log(`[STORAGE] Répertoire créé : ${projectPath}`);
    },

    /**
     * Supprime le répertoire d'un projet et son contenu
     * @param {number} projectId - ID du projet
     */
    deleteProjectDirectory: async function(projectId) {
      const projectPath = path.join(config.paths.storage, `${projectId}`);
      await StorageService.deleteDirectory(projectPath);
      console.log(`[STORAGE] Répertoire supprimé : ${projectPath}`);
    }
  };

  /**
   * Gestionnaire pour les opérations de mesures (images)
   */
  static measurement = {
    /**
     * Récupère l'image d'une mesure
     * @param {number} projectId - ID du projet
     * @param {number} orderId - ID d'ordre de la mesure
     * @returns {Promise<Buffer>} Contenu de l'image
     */
    getMeasurementImage: async function(projectId, orderId) {
      const imagePath = path.join(config.paths.storage, `${projectId}`, 'images', `${orderId}.jpg`);
      console.log(`[STORAGE] Récupération de l'image : ${imagePath}`);
      return await StorageService.getFile(imagePath);
    },

    /**
     * Enregistre l'image d'une mesure
     * @param {Object} image - Objet image avec buffer
     * @param {number} projectId - ID du projet
     * @param {number} orderId - ID d'ordre de la mesure
     * @returns {Promise<string>} Chemin de l'image enregistrée
     */
    uploadMeasurementImage: async function(image, projectId, orderId) {
      const imagePath = path.join(config.paths.storage, `${projectId}`, 'images', `${orderId}.jpg`);
      console.log(`[STORAGE] Enregistrement de l'image : ${imagePath}`);
      await StorageService.saveFile(imagePath, image.buffer);
      return imagePath;
    }
  };

  /**
   * Gestionnaire pour les opérations de vidéos
   */
  static video = {
    /**
     * Récupère une vidéo
     * @param {number} projectId - ID du projet
     * @param {number} videoId - ID de la vidéo
     * @returns {Promise<Buffer>} Contenu de la vidéo
     */
    getVideo: async function(projectId, videoId) {
      const videoPath = path.join(config.paths.storage, `${projectId}`, 'videos', `${videoId}.mp4`);
      console.log(`[STORAGE] Récupération de la vidéo : ${videoPath}`);
      return await StorageService.getFile(videoPath);
    },

    /**
     * Supprime une vidéo
     * @param {string} videoPath - Chemin de la vidéo à supprimer
     * @returns {Promise<string>} Message de confirmation
     */
    deleteVideo: async function(videoPath) {
      console.log(`[STORAGE] Suppression de la vidéo : ${videoPath}`);
      return await StorageService.deleteFile(videoPath);
    }
  };
}

module.exports = StorageService;