import { getDb } from "./db";
import { sequences, inscriptions, apprenants, formations, datesFormation, formateurs, questionnaires, envoisQuestionnaires, logsNotifications } from "../drizzle/schema";
import { eq, and, lte, sql } from "drizzle-orm";
import { sendRemerciementPostFormation } from "./emailService";
import { logNotification } from "./notificationLogsDb";
import crypto from "crypto";

/**
 * Génère un token unique pour accéder au questionnaire
 */
function generateToken(): string {
  return crypto.randomBytes(32).toString("hex");
}

/**
 * Récupère ou crée un lien questionnaire pour un apprenant
 */
async function getOrCreateQuestionnaireLink(
  apprenantId: number,
  sequenceId: number
): Promise<string | null> {
  const db = await getDb();
  if (!db) return null;

  try {
    // Chercher un questionnaire de satisfaction actif
    const [questionnaire] = await db
      .select()
      .from(questionnaires)
      .where(
        and(
          eq(questionnaires.type, "satisfaction"),
          eq(questionnaires.actif, true)
        )
      )
      .limit(1);

    if (!questionnaire) {
      console.log("[Remerciements] Aucun questionnaire de satisfaction actif trouvé");
      return null;
    }

    // Vérifier si un envoi existe déjà
    const [envoiExistant] = await db
      .select()
      .from(envoisQuestionnaires)
      .where(
        and(
          eq(envoisQuestionnaires.questionnaireId, questionnaire.id),
          eq(envoisQuestionnaires.apprenantId, apprenantId),
          eq(envoisQuestionnaires.sequenceId, sequenceId)
        )
      )
      .limit(1);

    if (envoiExistant) {
      // Retourner le lien existant
      const baseUrl = process.env.VITE_FRONTEND_URL || "http://localhost:3000";
      return `${baseUrl}/questionnaire/${envoiExistant.token}`;
    }

    // Créer un nouvel envoi
    const token = generateToken();
    await db.insert(envoisQuestionnaires).values({
      questionnaireId: questionnaire.id,
      apprenantId,
      sequenceId,
      token,
      dateEnvoi: new Date(),
      dateReponse: null,
    });

    const baseUrl = process.env.VITE_FRONTEND_URL || "http://localhost:3000";
    return `${baseUrl}/questionnaire/${token}`;
  } catch (error) {
    console.error("[Remerciements] Erreur lors de la création du lien questionnaire:", error);
    return null;
  }
}

/**
 * Vérifie si un remerciement a déjà été envoyé pour une inscription en vérifiant dans la base de données
 */
async function remerciementDejaEnvoye(apprenantId: number, sequenceId: number): Promise<boolean> {
  const db = await getDb();
  if (!db) return false;
  
  try {
    const [existing] = await db
      .select({ id: logsNotifications.id })
      .from(logsNotifications)
      .where(
        and(
          eq(logsNotifications.type, "remerciement"),
          eq(logsNotifications.apprenantId, apprenantId),
          eq(logsNotifications.sequenceId, sequenceId),
          eq(logsNotifications.statut, "success")
        )
      )
      .limit(1);
    
    return !!existing;
  } catch (error) {
    console.error("[Remerciements] Erreur lors de la vérification du log:", error);
    return false;
  }
}

/**
 * Job automatique qui vérifie quotidiennement les séquences terminées
 * et envoie les emails de remerciement aux apprenants
 */
export async function processRemerciementsAutomatiques() {
  console.log("[Remerciements] Démarrage du traitement des remerciements post-formation...");
  
  const db = await getDb();
  if (!db) {
    console.error("[Remerciements] Base de données non disponible");
    return;
  }

  try {
    const now = new Date();
    const hier = new Date();
    hier.setDate(hier.getDate() - 1);
    hier.setHours(23, 59, 59, 999);

    // Récupérer les séquences dont la dernière date est passée (terminées hier ou avant)
    const sequencesTerminees = await db
      .select({
        sequence: sequences,
        formation: formations,
        formateur: formateurs,
        derniereDate: sql<Date>`MAX(${datesFormation.dateFin})`.as('derniereDate'),
      })
      .from(sequences)
      .innerJoin(formations, eq(sequences.formationId, formations.id))
      .leftJoin(formateurs, eq(sequences.formateurId, formateurs.id))
      .innerJoin(datesFormation, eq(sequences.id, datesFormation.sequenceId))
      .where(eq(sequences.statut, 'ouverte')) // Séquences encore ouvertes (pas encore marquées terminées)
      .groupBy(sequences.id, formations.id, formateurs.id)
      .having(lte(sql`MAX(${datesFormation.dateFin})`, hier));

    console.log(`[Remerciements] ${sequencesTerminees.length} séquence(s) terminée(s) trouvée(s)`);

    for (const { sequence, formation, formateur, derniereDate } of sequencesTerminees) {
      await processRemerciementSequence(sequence, formation, formateur, derniereDate);
    }

    console.log("[Remerciements] Traitement terminé");
  } catch (error) {
    console.error("[Remerciements] Erreur lors du traitement des remerciements:", error);
  }
}

async function processRemerciementSequence(
  sequence: any, 
  formation: any, 
  formateur: any | null,
  derniereDate: Date
) {
  console.log(`[Remerciements] Traitement de la séquence: ${sequence.nom} (terminée le ${derniereDate})`);

  const db = await getDb();
  if (!db) return;

  try {
    // Récupérer les inscriptions confirmées pour cette séquence
    const inscriptionsConfirmees = await db
      .select({
        inscription: inscriptions,
        apprenant: apprenants,
      })
      .from(inscriptions)
      .innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id))
      .where(
        and(
          eq(inscriptions.sequenceId, sequence.id),
          eq(inscriptions.statut, 'confirmee')
        )
      );

    console.log(`[Remerciements] ${inscriptionsConfirmees.length} inscription(s) confirmée(s) pour ${sequence.nom}`);

    let envoyesCount = 0;
    let errorsCount = 0;

    for (const { inscription, apprenant } of inscriptionsConfirmees) {
      // Vérifier si le remerciement a déjà été envoyé (vérification en base de données)
      const dejaEnvoye = await remerciementDejaEnvoye(apprenant.id, sequence.id);
      if (dejaEnvoye) {
        console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}`);
        continue;
      }

      try {
        // Générer le lien questionnaire
        const lienQuestionnaire = await getOrCreateQuestionnaireLink(apprenant.id, sequence.id);

        await sendRemerciementPostFormation({
          apprenantEmail: apprenant.email,
          apprenantNom: apprenant.nom,
          apprenantPrenom: apprenant.prenom,
          apprenantFonction: apprenant.fonction,
          formationNom: formation.nom,
          sequenceNom: sequence.nom,
          formateurNom: formateur?.nom,
          lienQuestionnaire: lienQuestionnaire || undefined,
        });

        // Logger la notification (sert aussi de marqueur pour éviter les doublons)
        await logNotification({
          type: "remerciement",
          sequenceId: sequence.id,
          apprenantId: apprenant.id,
          emailDestinataire: apprenant.email,
          sujet: `Merci pour votre participation - ${formation.nom}`,
          statut: "success",
          metadata: { lienQuestionnaire },
        });

        envoyesCount++;
        console.log(`[Remerciements] Email envoyé à ${apprenant.email}`);
      } catch (error: any) {
        // Logger l'échec
        await logNotification({
          type: "remerciement",
          sequenceId: sequence.id,
          apprenantId: apprenant.id,
          emailDestinataire: apprenant.email,
          sujet: `Merci pour votre participation - ${formation.nom}`,
          statut: "failed",
          messageErreur: error.message,
        });

        errorsCount++;
        console.error(`[Remerciements] Erreur envoi à ${apprenant.email}:`, error);
      }
    }

    console.log(`[Remerciements] Séquence ${sequence.nom}: ${envoyesCount} envoyé(s), ${errorsCount} erreur(s)`);

    // Optionnel: Marquer la séquence comme terminée
    // await db.update(sequences).set({ statut: 'terminee' }).where(eq(sequences.id, sequence.id));

  } catch (error) {
    console.error(`[Remerciements] Erreur pour la séquence ${sequence.nom}:`, error);
  }
}

/**
 * Envoie manuellement un email de remerciement pour une séquence spécifique
 * Utilisé par l'interface admin pour envoyer les remerciements à la demande
 */
export async function envoyerRemerciementsSequence(sequenceId: number): Promise<{ sent: number; failed: number }> {
  const db = await getDb();
  if (!db) {
    throw new Error("Base de données non disponible");
  }

  // Récupérer la séquence avec formation et formateur
  const sequenceData = await db
    .select({
      sequence: sequences,
      formation: formations,
      formateur: formateurs,
    })
    .from(sequences)
    .innerJoin(formations, eq(sequences.formationId, formations.id))
    .leftJoin(formateurs, eq(sequences.formateurId, formateurs.id))
    .where(eq(sequences.id, sequenceId))
    .limit(1);

  if (sequenceData.length === 0) {
    throw new Error("Séquence introuvable");
  }

  const { sequence, formation, formateur } = sequenceData[0];

  // Récupérer les inscriptions confirmées
  const inscriptionsConfirmees = await db
    .select({
      inscription: inscriptions,
      apprenant: apprenants,
    })
    .from(inscriptions)
    .innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id))
    .where(
      and(
        eq(inscriptions.sequenceId, sequenceId),
        eq(inscriptions.statut, 'confirmee')
      )
    );

  let sent = 0;
  let failed = 0;

  for (const { inscription, apprenant } of inscriptionsConfirmees) {
    // Vérifier si le remerciement a déjà été envoyé
    const dejaEnvoye = await remerciementDejaEnvoye(apprenant.id, sequenceId);
    if (dejaEnvoye) {
      console.log(`[Remerciements] Remerciement déjà envoyé pour ${apprenant.email}, ignoré`);
      continue;
    }

    try {
      // Générer le lien questionnaire
      const lienQuestionnaire = await getOrCreateQuestionnaireLink(apprenant.id, sequenceId);

      await sendRemerciementPostFormation({
        apprenantEmail: apprenant.email,
        apprenantNom: apprenant.nom,
        apprenantPrenom: apprenant.prenom,
        apprenantFonction: apprenant.fonction,
        formationNom: formation.nom,
        sequenceNom: sequence.nom,
        formateurNom: formateur?.nom,
        lienQuestionnaire: lienQuestionnaire || undefined,
      });

      // Logger la notification
      await logNotification({
        type: "remerciement",
        sequenceId,
        apprenantId: apprenant.id,
        emailDestinataire: apprenant.email,
        sujet: `Merci pour votre participation - ${formation.nom}`,
        statut: "success",
        metadata: { lienQuestionnaire },
      });

      sent++;
    } catch (error: any) {
      // Logger l'échec
      await logNotification({
        type: "remerciement",
        sequenceId,
        apprenantId: apprenant.id,
        emailDestinataire: apprenant.email,
        sujet: `Merci pour votre participation - ${formation.nom}`,
        statut: "failed",
        messageErreur: error.message,
      });

      console.error(`[Remerciements] Erreur envoi à ${apprenant.email}:`, error);
      failed++;
    }
  }

  return { sent, failed };
}
