const { onCall, onRequest } = require("firebase-functions/v2/https");
const fetch = require("node-fetch");
const admin = require("firebase-admin");
const { logger } = require("firebase-functions/logger");
const { SUNO_API_KEY } = require("../config/keys");

// Initialiser Firestore
const db = admin.firestore();

/**
 * ===== CONFIG GLOBALE =====
 */
const SUNO_API_BASE = "https://api.sunoapi.org";
const SUNO_API_PATH = "/api/v1/generate";
const SUNO_STATUS_PATH = "/api/v1/generate/record-info";
const SUNO_MODEL = "V4_5";
const SUNO_INSTRUMENTAL = false;
const SUNO_CALLBACK_URL =
  "https://us-central1-musicland-d33f9.cloudfunctions.net/music-sunoCallback";

/**
 * Limite la longueur d'une chaîne
 * @param {string} str - La chaîne à limiter
 * @param {number} max - La longueur maximale
 * @return {string} La chaîne limitée
 */
function clampLen(str = "", max) {
  if (!max) return str || "";
  if (!str) return "";
  return str.length <= max ? str : str.slice(0, max);
}

/**
 * Construit le style musical à partir des paramètres
 * @param {Object} params - Les paramètres de style
 * @return {string} Le style formaté
 */
function buildStyle({ genres = [], voice = "", instruments = [], tempo = "" }) {
  const flatGenres = (genres || []).map((g) => ("" + g).trim()).filter(Boolean);
  const flatInstruments = (instruments || [])
    .map((i) => ("" + i).trim())
    .filter(Boolean);

  const styleParts = [
    flatGenres.length ? `Genres: ${flatGenres.join(", ")}` : "",
    tempo ? `Tempo: ${tempo}` : "",
    flatInstruments.length ? `Instruments: ${flatInstruments.join(", ")}` : "",
    voice ? `Vocal: ${voice}` : "",
    "Mix: propre, punchy, large stéréo, radio-ready",
  ].filter(Boolean);

  const style = styleParts.join(" ; ");
  return clampLen(style, 600);
}

/**
 * Convertit les paroles en prompt avec tags
 * @param {Array} lyrics - Tableau des paroles
 * @return {string} Prompt formaté avec tags
 */
function lyricsToTaggedPrompt(lyrics = []) {
  if (!Array.isArray(lyrics) || lyrics.length === 0) {
    return "";
  }

  const sections = lyrics
    .map((section) => {
      if (!section || typeof section !== "object") return "";
      const { type = "verse", content = "" } = section;
      if (!content.trim()) return "";

      const tag = type.toLowerCase();
      return `[${tag}]\n${content.trim()}`;
    })
    .filter(Boolean);

  return sections.join("\n\n");
}

/**
 * Construit le prompt pour Suno
 * @param {Object} params - Paramètres du prompt
 * @return {string} Prompt formaté
 */
function buildSunoPrompt({
  title,
  audience = "",
  projectContext = "",
  emotionGuide = "",
  styleGuide = "",
  taggedLyrics = "",
}) {
  const parts = [
    title ? `Titre: ${title}` : "",
    audience ? `Public cible: ${audience}` : "",
    projectContext ? `Contexte: ${projectContext}` : "",
    emotionGuide ? `Émotion: ${emotionGuide}` : "",
    styleGuide ? `Style: ${styleGuide}` : "",
    taggedLyrics ? `Paroles:\n${taggedLyrics}` : "",
  ].filter(Boolean);

  return parts.join("\n\n");
}

/**
 * Construit les guides de style et d'émotion
 * @param {Object} params - Paramètres des guides
 * @return {Object} Guides formatés
 */
function buildGuides({
  genres = [],
  tempo = "",
  voice = "",
  instruments = [],
}) {
  const styleElements = [];

  if (genres && genres.length > 0) {
    styleElements.push(`Genres: ${genres.join(", ")}`);
  }

  if (tempo) {
    const tempoGuide = tempo.toLowerCase().includes("lent")
      ? "Rythme lent et contemplatif"
      : tempo.toLowerCase().includes("rapide")
        ? "Rythme énergique et dynamique"
        : `Tempo ${tempo.toLowerCase()}.`;
    styleElements.push(tempoGuide);
  }

  if (instruments && instruments.length > 0) {
    styleElements.push(`Instruments principaux: ${instruments.join(", ")}`);
  }

  if (voice) {
    styleElements.push(`Style vocal: ${voice}`);
  }

  return {
    styleGuide: styleElements.join(" "),
    emotionGuide: "",
  };
}

/**
 * Fonction principale de génération de musique
 */
exports.generateMusic = onCall(
  { region: "europe-west1" },
  async ({ data = {} }) => {
    try {
      const {
        title = "",
        lyrics = [],
        genres = [],
        voice = "",
        instruments = [],
        tempo = "",
        audience = "",
        projectContext = "",
      } = data;

      const { styleGuide, emotionGuide } = buildGuides({
        genres,
        voice,
        instruments,
        tempo,
      });
      const taggedLyrics = lyricsToTaggedPrompt(lyrics);

      const safeTitle = clampLen(title, 80);

      // Construire les informations de contexte pour le style (sans les paroles)
      const contextInfo = buildSunoPrompt({
        title: safeTitle,
        audience,
        projectContext,
        emotionGuide,
        styleGuide,
        taggedLyrics: "", // Ne pas inclure les paroles dans le contexte
      });

      // Le style combine les informations de genre ET le contexte
      const baseStyle = buildStyle({ genres, voice, instruments, tempo });
      const enhancedStyle = contextInfo
        ? `${baseStyle}. ${contextInfo}`
        : baseStyle;

      const payload = {
        customMode: true,
        model: SUNO_MODEL,
        title: safeTitle,
        style: clampLen(enhancedStyle, 600),
        instrumental: SUNO_INSTRUMENTAL,
        callBackUrl: SUNO_CALLBACK_URL || "",
      };

      // Les paroles vont dans le prompt, pas les instructions de style
      if (!SUNO_INSTRUMENTAL && taggedLyrics) {
        payload.prompt = clampLen(taggedLyrics, 3000);
      }

      const response = await fetch(`${SUNO_API_BASE}${SUNO_API_PATH}`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${SUNO_API_KEY}`,
        },
        body: JSON.stringify(payload),
      });

      const raw = await response.text();
      let parsed;

      try {
        parsed = JSON.parse(raw);
      } catch (parseError) {
        console.error("❌ Erreur de parsing JSON:", parseError);
        const { HttpsError } = require("firebase-functions/v2/https");
        throw new HttpsError(
          "internal",
          `Réponse API invalide: ${raw.substring(0, 200)}...`,
        );
      }

      if (!response.ok) {
        console.error("❌ Erreur API Suno:", {
          status: response.status,
          statusText: response.statusText,
          body: parsed || raw,
        });
        throw new Error(
          `Erreur API Suno (${response.status}): ${
            (parsed && parsed.error) || response.statusText
          }`,
        );
      }

      return {
        success: true,
        request: {
          model: SUNO_MODEL,
          instrumental: SUNO_INSTRUMENTAL,
          title: safeTitle,
          style: enhancedStyle,
          prompt: SUNO_INSTRUMENTAL ? undefined : taggedLyrics,
        },
        response: parsed || { raw },
      };
    } catch (error) {
      console.error("❌ Erreur lors de la génération de musique:", error);
      throw new Error(
        `Erreur lors de la génération de musique: ${error.message}`,
      );
    }
  },
);

/**
 * Fonction pour suivre le statut d'une génération de musique Suno
 */
exports.getSunoStatus = onCall(
  { region: "europe-west1" },
  async ({ data = {} }) => {
    try {
      const { taskId } = data;

      if (!taskId) {
        throw new Error("TaskId manquant");
      }

      logger.info("🔍 Vérification du statut Suno", { taskId });

      const response = await fetch(
        `${SUNO_API_BASE}${SUNO_STATUS_PATH}?taskId=${taskId}`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${SUNO_API_KEY}`,
          },
        },
      );

      const raw = await response.text();
      let parsed;

      try {
        parsed = JSON.parse(raw);
      } catch (parseError) {
        console.error("❌ Erreur de parsing JSON:", parseError);
        throw new Error(`Réponse API invalide: ${raw.substring(0, 200)}...`);
      }

      if (!response.ok) {
        console.error("❌ Erreur API Suno Status:", {
          status: response.status,
          statusText: response.statusText,
          body: parsed || raw,
        });

        // Gestion spéciale pour les taskId de test
        if (response.status === 404 && taskId.includes("test")) {
          return {
            success: true,
            taskId,
            data: {
              status: "not_found",
              message: "TaskId de test - tâche non trouvée dans l'API Suno",
              isTestId: true,
            },
          };
        }

        throw new Error(
          `Erreur API Suno Status (${response.status}): ${
            (parsed && parsed.error) || response.statusText
          }`,
        );
      }

      logger.info("✅ Statut Suno récupéré", {
        taskId,
        status: parsed && parsed.status,
      });

      return {
        success: true,
        taskId,
        data: parsed,
      };
    } catch (error) {
      console.error("❌ Erreur lors de la vérification du statut:", error);
      throw new Error(
        `Erreur lors de la vérification du statut: ${error.message}`,
      );
    }
  },
);

/**
 * Cloud Function pour recevoir les callbacks de l'API Suno
 * Cette fonction est appelée par l'API Suno lorsque la génération
 * de musique est terminée
 */
exports.sunoCallback = onRequest(
  {
    region: "europe-west1",
    cors: true,
    methods: ["POST"],
  },
  async (req, res) => {
    try {
      logger.info("🎵 Callback Suno reçu", { data: req.body });

      // Vérifier que c'est une requête POST
      if (req.method !== "POST") {
        logger.warn("⚠️ Méthode non autorisée:", req.method);
        return res.status(405).json({ error: "Méthode non autorisée" });
      }

      // Extraire les données du callback
      const {
        id,
        status,
        audio_url: audioUrl,
        video_url: videoUrl,
        image_url: imageUrl,
        lyric,
        title,
        tags,
        duration,
        error_message: errorMessage,
      } = req.body;

      // Vérifier que l'ID est présent
      if (!id) {
        logger.error("❌ ID manquant dans le callback");
        return res.status(400).json({ error: "ID manquant" });
      }

      // Chercher le document correspondant dans Firestore
      const musicRef = db.collection("music").doc(id);
      const musicDoc = await musicRef.get();

      if (!musicDoc.exists) {
        logger.error("❌ Document non trouvé pour l'ID:", id);
        return res.status(404).json({ error: "Document non trouvé" });
      }

      // Préparer les données de mise à jour
      const updateData = {
        status: status,
        updatedAt: admin.firestore.FieldValue.serverTimestamp(),
      };

      // Ajouter les URLs si disponibles
      if (audioUrl) {
        updateData.audioUrl = audioUrl;
      }
      if (videoUrl) {
        updateData.videoUrl = videoUrl;
      }
      if (imageUrl) {
        updateData.imageUrl = imageUrl;
      }
      if (lyric) {
        updateData.lyrics = lyric;
      }
      if (title) {
        updateData.title = title;
      }
      if (tags) {
        updateData.style = tags;
      }
      if (duration) {
        updateData.duration = duration;
      }
      if (errorMessage) {
        updateData.errorMessage = errorMessage;
      }

      // Mettre à jour le document dans Firestore
      await musicRef.update(updateData);

      logger.info("✅ Document mis à jour avec succès", {
        id: id,
        status: status,
      });

      // Répondre avec succès
      res.status(200).json({
        success: true,
        message: "Callback traité avec succès",
        id: id,
        status: status,
      });
    } catch (error) {
      logger.error("❌ Erreur lors du traitement du callback:", error);
      res.status(500).json({
        error: "Erreur interne du serveur",
        message: error.message,
      });
    }
  },
);
