import { getDb } from "./db";
import { sequences, inscriptions, apprenants, formations, datesFormation, attestations, historiqueAttestations } from "../drizzle/schema";
import { eq, and, lte, sql, isNull } from "drizzle-orm";
import { sendAttestationEmail } from "./emailService";
import { enregistrerEnvoiAttestation } from "./attestationsDb";

/**
 * Vérifie si une attestation a déjà été envoyée pour une inscription
 */
async function attestationDejaEnvoyee(apprenantId: number, sequenceId: number): Promise<boolean> {
  const db = await getDb();
  if (!db) return false;
  
  try {
    const [existing] = await db
      .select({ id: historiqueAttestations.id })
      .from(historiqueAttestations)
      .where(
        and(
          eq(historiqueAttestations.apprenantId, apprenantId),
          eq(historiqueAttestations.sequenceId, sequenceId),
          eq(historiqueAttestations.statut, "envoye")
        )
      )
      .limit(1);
    
    return !!existing;
  } catch (error) {
    console.error("[Attestations Auto] Erreur lors de la vérification de l'historique:", error);
    return false;
  }
}

/**
 * Job automatique qui vérifie quotidiennement les séquences terminées
 * et envoie les attestations aux apprenants pour les formations en mode envoi automatique
 */
export async function processAttestationsAutomatiques() {
  console.log("[Attestations Auto] Démarrage du traitement des attestations automatiques...");
  
  const db = await getDb();
  if (!db) {
    console.error("[Attestations Auto] 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)
    // ET dont la formation a le mode d'envoi automatique activé
    const sequencesTerminees = await db
      .select({
        sequence: sequences,
        formation: formations,
        derniereDate: sql<Date>`MAX(${datesFormation.dateFin})`.as('derniereDate'),
      })
      .from(sequences)
      .innerJoin(formations, eq(sequences.formationId, formations.id))
      .innerJoin(datesFormation, eq(sequences.id, datesFormation.sequenceId))
      .where(
        and(
          eq(formations.modeEnvoi, 'auto'), // Seulement les formations en mode envoi automatique
          eq(sequences.statut, 'ouverte') // Séquences encore ouvertes
        )
      )
      .groupBy(sequences.id, formations.id)
      .having(lte(sql`MAX(${datesFormation.dateFin})`, hier));

    console.log(`[Attestations Auto] ${sequencesTerminees.length} séquence(s) terminée(s) avec envoi automatique trouvée(s)`);

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

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

async function processAttestationSequence(
  sequence: any, 
  formation: any, 
  derniereDate: Date
) {
  console.log(`[Attestations Auto] 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 avec leurs attestations
    const inscriptionsAvecAttestations = await db
      .select({
        inscription: inscriptions,
        apprenant: apprenants,
        attestation: attestations,
      })
      .from(inscriptions)
      .innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id))
      .leftJoin(attestations, eq(inscriptions.id, attestations.inscriptionId))
      .where(
        and(
          eq(inscriptions.sequenceId, sequence.id),
          eq(inscriptions.statut, 'confirmee')
        )
      );

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

    let envoyesCount = 0;
    let errorsCount = 0;
    let sansAttestationCount = 0;

    for (const { inscription, apprenant, attestation } of inscriptionsAvecAttestations) {
      // Vérifier si l'attestation existe
      if (!attestation || !attestation.documentUrl) {
        sansAttestationCount++;
        console.log(`[Attestations Auto] Pas d'attestation générée pour ${apprenant.email}`);
        continue;
      }

      // Vérifier si l'attestation a déjà été envoyée
      const dejaEnvoyee = await attestationDejaEnvoyee(apprenant.id, sequence.id);
      if (dejaEnvoyee) {
        console.log(`[Attestations Auto] Attestation déjà envoyée pour ${apprenant.email}`);
        continue;
      }

      try {
        await sendAttestationEmail({
          to: apprenant.email,
          apprenantNom: apprenant.nom,
          apprenantPrenom: apprenant.prenom,
          formationNom: formation.nom,
          pdfUrl: attestation.documentUrl,
        });

        // Enregistrer dans l'historique
        await enregistrerEnvoiAttestation({
          sequenceId: sequence.id,
          apprenantId: apprenant.id,
          statut: "envoye",
          urlAttestation: attestation.documentUrl,
          modeEnvoi: "auto",
        });

        envoyesCount++;
        console.log(`[Attestations Auto] Email envoyé à ${apprenant.email}`);
      } catch (error: any) {
        // Enregistrer l'échec dans l'historique
        await enregistrerEnvoiAttestation({
          sequenceId: sequence.id,
          apprenantId: apprenant.id,
          statut: "erreur",
          messageErreur: error.message,
          urlAttestation: attestation.documentUrl,
          modeEnvoi: "auto",
        });

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

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

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

/**
 * Initialise le scheduler pour l'envoi automatique des attestations
 * Exécute le job tous les jours à 10h00
 */
export function initAttestationScheduler() {
  console.log("[Attestations Auto] Initialisation du scheduler d'envoi automatique");
  
  // Exécuter immédiatement au démarrage
  processAttestationsAutomatiques();
  
  // Puis exécuter tous les jours à 10h00
  const HEURE_EXECUTION = 10; // 10h00
  const MINUTE_EXECUTION = 0;
  
  setInterval(() => {
    const now = new Date();
    const heureActuelle = now.getHours();
    const minuteActuelle = now.getMinutes();
    
    // Exécuter seulement à l'heure prévue (avec une tolérance de 1 minute)
    if (heureActuelle === HEURE_EXECUTION && minuteActuelle === MINUTE_EXECUTION) {
      processAttestationsAutomatiques();
    }
  }, 60 * 1000); // Vérifier toutes les minutes
  
  console.log(`[Attestations Auto] Scheduler initialisé - Exécution quotidienne à ${HEURE_EXECUTION}:${String(MINUTE_EXECUTION).padStart(2, '0')}`);
}
