const { onCall } = require("firebase-functions/v2/https");
const { z } = require("genkit");
const { generateAI, analyseLyrics } = require("../helpers/gemini");
const {
  SUNO_API_BASE,
  SUNO_TIMESTAMPED_LYRICS_PATH,
} = require("../config/suno");
const { SUNO_API_KEY } = require("../config/keys");
const axios = require("axios");
const admin = require("firebase-admin");
const { refList } = require("../index");

exports.generateLyrics = onCall({}, async ({ auth = {}, data = {} }) => {
  try {
    const {
      objective = "",
      context = "",
      style = "",
      audience = "",
      emotion = "",
      structure = ["couplet", "refrain", "couplet", "refrain"],
      rhymes = "",
    } = data;

    console.log("Function generate lyrics start with data", data);

    const system =
      `
Tu es un parolier expert en chanson française moderne et populaire.
Tu écris des chansons marquantes, accessibles, sur des thématiques ` +
      `d'innovation, d'esprit d'équipe et de créativité digitale.
Ton ` +
      `écriture doit toucher à la fois l'humain, le collectif et la ` +
      `passion d'entreprendre.
Tu dois générer un titre accrocheur et ` +
      `mémorable pour la chanson en plus des paroles.
Respecte ` +
      `précisément la structure demandée et fournis le résultat dans un ` +
      `format JSON clair, respectant strictement le schéma demandé.
    `.trim();

    // Construction du prompt utilisateur
    const prompt =
      `
Objectif : ${objective}
Contexte : ${context}
Émotion : ${emotion}
Style musical : ${style}
Audience cible : ${audience}
Structure de la chanson : ${structure.join(" => ")}
Schéma de rimes : ${rhymes}

Génère un titre accrocheur et les paroles de la chanson en suivant ` +
      `strictement cette structure.
Le titre doit être court, ` +
      `mémorable et refléter l'esprit de la musique.
Pour chaque ` +
      `partie ("couplet" ou "refrain"), écris 4 à 16 lignes adaptées, ` +
      `expressives et cohérentes avec le style et l'émotion souhaitée.
`.trim();

    // Définition du schéma zod/genkit pour la validation du retour
    const lyricsSchema = z.object({
      title: z.string().describe("Titre de la chanson, court et accrocheur"),
      lyrics: z
        .array(
          z.object({
            type: z
              .string()
              .describe(
                'Type de section : "couplet" ou "refrain" ' +
                  "selon la structure",
              ),
            lyrics: z
              .string()
              .describe(
                "Paroles de la section, chaque ligne séparée " +
                  "par un retour à la ligne",
              ),
          }),
        )
        .describe(
          "Paroles de la chanson sous forme de tableau de sections " +
            "structurées.",
        ),
      lyricsDescription: z
        .string()
        .describe("Courte déscription qui résume les paroles de la musique"),
      success: z.boolean().describe("Indique si la génération a réussi"),
    });

    return await generateAI({
      system,
      prompt,
      schema: lyricsSchema,
    });
  } catch (e) {
    console.log(e);
  }
});

// Vérifie la toxicité des paroles via Gemini et retourne un résultat structuré
// Nom Cloud Function: lyrics-analyseLyricsToxicity
exports.analyseLyricsToxicity = onCall({}, async ({ data = {} }) => {
  try {
    // Validation d'entrée minimale
    const requestSchema = z.object({
      title: z.string().optional(),
      lyrics: z
        .union([
          z.string(),
          z.object({
            couplet: z.string().optional(),
            refrain: z.string().optional(),
          }),
          z.array(
            z.object({
              type: z.string().optional(),
              lyrics: z.string().optional(),
            }),
          ),
        ])
        .describe("Paroles à analyser (formats supportés)"),
    });

    const parsed = requestSchema.parse(data || {});
    const result = await analyseLyrics({
      title: parsed.title || "",
      lyrics: parsed.lyrics,
    });

    // Prépare un message lisible pour le front
    const highCats = Object.entries(result.categories || {})
      .filter(([, v]) => (typeof v === "number" ? v : 0) >= 0.5)
      .map(([k]) => k)
      .slice(0, 5);

    let errorCode = "OK";
    let message = "Analyse effectuée: aucun blocage.";

    if (result.blocked) {
      errorCode = "TOXIC_CONTENT_BLOCKED";
      const list = highCats.length ? ` (${highCats.join(", ")})` : "";
      message = `Publication bloquée: contenu interdit détecté${list}.`;
    } else if (result.flagged) {
      errorCode = "TOXIC_CONTENT_FLAGGED";
      const list = highCats.length ? ` (${highCats.join(", ")})` : "";
      message = `Attention: contenu potentiellement sensible détecté${list}.`;
    }

    return {
      success: !result.blocked,
      errorCode,
      message,
      result,
    };
  } catch (err) {
    console.error("analyseLyricsToxicity failed", err?.message || err);
    return {
      success: false,
      errorCode: "ANALYSE_FAILED",
      message: "Erreur lors de l'analyse de la toxicité. Réessayez plus tard.",
    };
  }
});

/**
 * Récupère les timestamps (aligned words) pour une génération Suno
 * Attend: { projectId: string }
 */
async function getSunoTimestamps(projectId) {
  try {
    const { sunoTaskId, songIndex } = (
      await refList.projects.doc(projectId).get()
    ).data();
    if (!sunoTaskId) {
      throw new Error("TaskId manquant");
    }

    if (songIndex < 0) {
      throw new Error("musicIndex invalide");
    }

    if (!projectId || typeof projectId !== "string" || !projectId.trim()) {
      throw new Error("projectId manquant ou invalide");
    }

    console.log("🔎 Récupération des timestamps Suno", {
      sunoTaskId,
      songIndex,
    });

    let response;
    let parsed;

    response = await axios.post(
      `${SUNO_API_BASE}${SUNO_TIMESTAMPED_LYRICS_PATH}`,
      { taskId: sunoTaskId, musicIndex: songIndex },
      {
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${SUNO_API_KEY}`,
        },
        timeout: 30000,
      },
    );
    parsed = response.data;
    console.log("📊 Réponse timestamps Suno API:", parsed?.code, parsed?.msg);

    const dataToReturn = parsed?.data || parsed || {};

    await refList.projects.doc(projectId).set(
      {
        musicTimestamps: {
          [songIndex]: dataToReturn,
        },
        updatedAt: admin.firestore.FieldValue.serverTimestamp(),
      },
      { merge: true },
    );
    console.log("💾 Timestamps sauvegardés dans Firestore", {
      projectId,
      songIndex,
    });
    return {
      success: true,
    };
  } catch (error) {
    console.error("❌ Erreur interne getSunoTimestamps:", error);
    return {
      success: false,
      error: {
        message: error.message,
        type: "INTERNAL_ERROR",
      },
    };
  }
}

exports.getSunoTimestamps = getSunoTimestamps;
