const fp = require('fastify-plugin');
const { OpenAI } = require('openai');
const fs = require('fs');
const util = require('util');
const { pipeline } = require('stream');
const pump = util.promisify(pipeline);
const fetch = require('node-fetch');
const { Readable } = require('stream');
const { uploadFile, getFileUrl } = require('../utils/storage');
const path = require('path');
const os = require('os');

module.exports = fp(async function (fastify, opts) {
  const openai = new OpenAI({
    apiKey: process.env.OPENAI_API_KEY
  });

  fastify.decorate('openai', openai);

  // Fonction utilitaire pour convertir un buffer en stream
  const bufferToStream = (buffer) => {
    const readable = new Readable();
    readable.push(buffer);
    readable.push(null);
    return readable;
  };

  // Fonction pour télécharger un fichier temporaire
  const downloadToTemp = async (url, extension = '.tmp') => {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`Échec du téléchargement: ${response.statusText}`);
    }

    const buffer = await response.arrayBuffer();
    const tempFilePath = path.join(os.tmpdir(), `openai-${Date.now()}${extension}`);
    fs.writeFileSync(tempFilePath, Buffer.from(buffer));

    return {
      path: tempFilePath,
      buffer: Buffer.from(buffer),
      cleanup: () => {
        try {
          fs.unlinkSync(tempFilePath);
        } catch (err) {
          fastify.log.error(`Erreur lors de la suppression du fichier temporaire: ${err.message}`);
        }
      }
    };
  };

  // Transcription audio avec Whisper
  fastify.decorate('transcribeAudio', async (audioInput) => {
    let tempFile = null;
    let audioPath = null;

    try {
      // Déterminer le type d'entrée audio
      if (typeof audioInput === 'string') {
        // C'est déjà un chemin de fichier
        audioPath = audioInput;
      } else if (audioInput && audioInput.url) {
        // C'est un résultat de Minio avec une URL
        tempFile = await downloadToTemp(audioInput.url, '.mp3');
        audioPath = tempFile.path;
      } else if (audioInput && audioInput.localPath) {
        // C'est un résultat local
        audioPath = audioInput.localPath;
      } else {
        throw new Error("Format d'entrée audio non valide");
      }

      // Effectuer la transcription
      const transcription = await openai.audio.transcriptions.create({
        file: fs.createReadStream(audioPath),
        model: 'whisper-1',
      });

      return transcription.text;
    } catch (error) {
      fastify.log.error(`Erreur lors de la transcription audio: ${error.message}`);
      throw error;
    } finally {
      // Nettoyer le fichier temporaire si nécessaire
      if (tempFile) {
        tempFile.cleanup();
      }
    }
  });

  // Génération de recette avec GPT-4o-mini
  fastify.decorate('generateRecipe', async (ingredients, prompt) => {
    try {
      const completion = await openai.chat.completions.create({
        model: "gpt-4o-mini",
        messages: [
          {
            role: "system",
            content: "Tu es un chef cuisinier expert qui crée des recettes délicieuses et faciles à réaliser. Tu dois toujours répondre avec un objet JSON valide contenant les champs suivants: titre, ingredients, etapes, temps_preparation (en minutes), temps_cuisson (en minutes), portions, difficulte (facile, moyen, difficile), et conseils."
          },
          {
            role: "user",
            content: `Voici les ingrédients disponibles: ${ingredients}. ${prompt || 'Propose une recette avec ces ingrédients.'} Réponds uniquement avec un objet JSON.`
          }
        ],
        response_format: { type: "json_object" },
      });

      const recipeData = JSON.parse(completion.choices[0].message.content);

      // Génération de l'image du plat avec DALL-E
      const imageResponse = await openai.images.generate({
        model: "dall-e-3",
        prompt: `Une photo culinaire professionnelle et appétissante du plat "${recipeData.titre}". Le plat est présenté sur une belle assiette, avec un éclairage professionnel, style photographie gastronomique.`,
        n: 1,
        size: "1024x1024",
      });

      // Télécharger l'image depuis l'URL OpenAI
      const imageUrl = imageResponse.data[0].url;
      const response = await fetch(imageUrl);
      const imageBuffer = Buffer.from(await response.arrayBuffer());

      // Préparer le fichier pour Minio
      const sanitizedTitle = recipeData.titre.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase();
      const fileName = `${sanitizedTitle}-${Date.now()}.jpg`;
      const folderPath = 'recipes';

      // Créer un objet file compatible avec uploadFile
      const file = {
        filename: fileName,
        file: bufferToStream(imageBuffer)
      };

      // Uploader vers Minio
      const filePath = await uploadFile(file, folderPath);
      const minioUrl = await getFileUrl(filePath);

      // Ajouter l'URL à l'objet recette
      recipeData.image_url = minioUrl;

      return recipeData;
    } catch (error) {
      fastify.log.error(`Erreur lors de la génération de recette: ${error.message}`);
      throw error;
    }
  });

  // Gestion du téléchargement de fichiers audio
  fastify.decorate('saveAudioFile', async (file) => {
    try {
      // Vérifier que le fichier est valide
      if (!file || !file.filename) {
        throw new Error("Fichier audio invalide");
      }

      // Préparer le nom de fichier
      const fileName = `${Date.now()}-${file.filename}`;
      const folderPath = 'audio';

      // Si le fichier est déjà un stream, l'utiliser directement
      // Sinon, le convertir en stream
      const fileToUpload = {
        filename: fileName,
        file: file.file || bufferToStream(file)
      };

      // Uploader vers Minio
      const filePath = await uploadFile(fileToUpload, folderPath);
      const minioUrl = await getFileUrl(filePath);

      return {
        success: true,
        url: minioUrl,
        path: filePath
      };
    } catch (error) {
      fastify.log.error(`Erreur lors de l'upload audio: ${error.message}`);

      // Fallback au stockage local
      try {
        const uploadDir = './uploads';
        if (!fs.existsSync(uploadDir)) {
          fs.mkdirSync(uploadDir, { recursive: true });
        }

        const filename = `${Date.now()}-${file.filename}`;
        const filepath = `${uploadDir}/${filename}`;

        // Gérer différents types d'entrée
        if (Buffer.isBuffer(file.file)) {
          fs.writeFileSync(filepath, file.file);
        } else if (file.file && typeof file.file.pipe === 'function') {
          await pump(file.file, fs.createWriteStream(filepath));
        } else if (Buffer.isBuffer(file)) {
          fs.writeFileSync(filepath, file);
        } else {
          throw new Error("Format de fichier non pris en charge");
        }

        return {
          success: true,
          localPath: filepath,
          isLocal: true
        };
      } catch (localError) {
        fastify.log.error(`Erreur lors du stockage local: ${localError.message}`);
        return {
          success: false,
          error: `Erreur Minio: ${error.message}. Erreur locale: ${localError.message}`
        };
      }
    }
  });
});