import { getDb } from "./db";
import { attestations, configAttestation, inscriptions, apprenants, sequences, formations, datesFormation } from "../drizzle/schema";
import { eq, and } from "drizzle-orm";
import { storagePut } from "./storage";
import PDFDocument from "pdfkit";
import { format } from "date-fns";
import { fr } from "date-fns/locale";
import crypto from "crypto";

/**
 * Génère une attestation de formation en PDF
 */
export async function genererAttestationPDF(inscriptionId: number): Promise<{ s3Key: string; pdfUrl: string }> {
  const db = await getDb();
  if (!db) {
    throw new Error("Base de données non disponible");
  }

  // Récupérer les données de l'inscription
  const [inscriptionData] = await db
    .select({
      inscription: inscriptions,
      apprenant: apprenants,
      sequence: sequences,
      formation: formations,
    })
    .from(inscriptions)
    .innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id))
    .innerJoin(sequences, eq(inscriptions.sequenceId, sequences.id))
    .innerJoin(formations, eq(sequences.formationId, formations.id))
    .where(eq(inscriptions.id, inscriptionId))
    .limit(1);

  if (!inscriptionData) {
    throw new Error("Inscription introuvable");
  }

  const { inscription, apprenant, sequence, formation } = inscriptionData;

  // Récupérer les dates de la séquence
  const dates = await db
    .select()
    .from(datesFormation)
    .where(eq(datesFormation.sequenceId, sequence.id));

  // Récupérer la configuration de l'attestation
  const [config] = await db
    .select()
    .from(configAttestation)
    .limit(1);

  // Créer le PDF
  const doc = new PDFDocument({
    size: "A4",
    margins: { top: 50, bottom: 50, left: 50, right: 50 },
  });

  const chunks: Buffer[] = [];
  doc.on("data", (chunk: Buffer) => chunks.push(chunk));

  return new Promise((resolve, reject) => {
    doc.on("end", async () => {
      try {
        const pdfBuffer = Buffer.concat(chunks);
        
        // Générer une clé S3 unique
        const randomSuffix = crypto.randomBytes(8).toString("hex");
        const s3Key = `attestations/${apprenant.id}-${sequence.id}-${randomSuffix}.pdf`;
        
        // Upload vers S3
        const { url } = await storagePut(s3Key, pdfBuffer, "application/pdf");
        
        resolve({ s3Key, pdfUrl: url });
      } catch (error) {
        reject(error);
      }
    });

    doc.on("error", reject);

    // Construction du PDF
    (async () => {
      try {
        // Logo en haut à droite si disponible
        if (config?.logoUrl) {
          try {
            const logoResponse = await fetch(config.logoUrl);
            const logoBuffer = Buffer.from(await logoResponse.arrayBuffer());
            doc.image(logoBuffer, doc.page.width - 150, 50, { width: 100 });
          } catch (error) {
            console.error("Erreur lors du chargement du logo:", error);
          }
        }

      // Titre
      doc.fontSize(24).font("Helvetica-Bold").text("ATTESTATION DE FORMATION", { align: "center" });
      doc.moveDown(2);

      // Texte personnalisable ou texte par défaut
      const texteAttestation = config?.texteAttestation || 
        "Nous attestons que {{nomComplet}} a suivi avec assiduité la formation \"{{nomFormation}}\" organisée du {{dateDebut}} au {{dateFin}}.";

      // Remplacer les variables
      const nomComplet = `${apprenant.prenom} ${apprenant.nom}`;
      const dateDebut = dates.length > 0 ? format(new Date(dates[0].dateDebut), "dd MMMM yyyy", { locale: fr }) : "";
      const dateFin = dates.length > 0 ? format(new Date(dates[dates.length - 1].dateFin), "dd MMMM yyyy", { locale: fr }) : "";

      const texteRempli = texteAttestation
        .replace(/\{\{nomComplet\}\}/g, nomComplet)
        .replace(/\{\{nomFormation\}\}/g, formation.nom)
        .replace(/\{\{dateDebut\}\}/g, dateDebut)
        .replace(/\{\{dateFin\}\}/g, dateFin);

      doc.fontSize(12).font("Helvetica").text(texteRempli, { align: "justify" });
      doc.moveDown(2);

      // Détails de la formation
      doc.fontSize(10).font("Helvetica-Bold").text("Détails de la formation :", { underline: true });
      doc.moveDown(0.5);
      doc.font("Helvetica");
      doc.text(`Formation : ${formation.nom}`);
      doc.text(`Séquence : ${sequence.nom}`);
      doc.text(`Lieu : ${sequence.lieu}`);
      doc.moveDown(0.5);
      doc.text("Dates :");
      dates.forEach((date) => {
        const dateStr = format(new Date(date.dateDebut), "dd/MM/yyyy", { locale: fr });
        const heureDebut = format(new Date(date.dateDebut), "HH:mm");
        const heureFin = format(new Date(date.dateFin), "HH:mm");
        doc.text(`  • ${dateStr} de ${heureDebut} à ${heureFin}`);
      });

      doc.moveDown(3);

      // Signature
      doc.fontSize(10);
      doc.text(`Fait le ${format(new Date(), "dd MMMM yyyy", { locale: fr })}`, { align: "right" });
      doc.moveDown(3);

        // Signature si disponible
        if (config?.signatureUrl) {
          try {
            const signatureResponse = await fetch(config.signatureUrl);
            const signatureBuffer = Buffer.from(await signatureResponse.arrayBuffer());
            const signatureX = doc.page.width - 200;
            const signatureY = doc.y;
            doc.image(signatureBuffer, signatureX, signatureY, { width: 150, height: 50 });
            doc.moveDown(3);
          } catch (error) {
            console.error("Erreur lors du chargement de la signature:", error);
          }
        }

        if (config?.nomSignataire) {
          doc.text(config.nomSignataire, { align: "right" });
        }
        if (config?.fonctionSignataire) {
          doc.text(config.fonctionSignataire, { align: "right" });
        }

        doc.end();
      } catch (error) {
        doc.end();
        reject(error);
      }
    })();
  });
}

/**
 * Enregistre une attestation dans la base de données
 */
export async function enregistrerAttestation(
  inscriptionId: number,
  apprenantId: number,
  sequenceId: number,
  s3Key: string,
  pdfUrl: string
): Promise<number> {
  const db = await getDb();
  if (!db) {
    throw new Error("Base de données non disponible");
  }

  const [result] = await db.insert(attestations).values({
    inscriptionId,
    apprenantId,
    sequenceId,
    s3Key,
    pdfUrl,
    emailEnvoye: false,
  });

  return result.insertId;
}

/**
 * Récupère l'attestation d'un apprenant pour une séquence
 */
export async function getAttestation(apprenantId: number, sequenceId: number) {
  const db = await getDb();
  if (!db) return null;

  const [attestation] = await db
    .select()
    .from(attestations)
    .where(
      and(
        eq(attestations.apprenantId, apprenantId),
        eq(attestations.sequenceId, sequenceId)
      )
    )
    .limit(1);

  return attestation || null;
}

/**
 * Récupère toutes les attestations d'un apprenant
 */
export async function getAttestationsApprenant(apprenantId: number) {
  const db = await getDb();
  if (!db) return [];

  return db
    .select({
      attestation: attestations,
      sequence: sequences,
      formation: formations,
    })
    .from(attestations)
    .innerJoin(sequences, eq(attestations.sequenceId, sequences.id))
    .innerJoin(formations, eq(sequences.formationId, formations.id))
    .where(eq(attestations.apprenantId, apprenantId));
}

/**
 * Marque une attestation comme envoyée par email
 */
export async function marquerAttestationEnvoyee(attestationId: number) {
  const db = await getDb();
  if (!db) return;

  await db
    .update(attestations)
    .set({
      emailEnvoye: true,
      dateEnvoiEmail: new Date(),
    })
    .where(eq(attestations.id, attestationId));
}

/**
 * Récupère ou crée la configuration des attestations
 */
export async function getOrCreateConfigAttestation() {
  const db = await getDb();
  if (!db) return null;

  let [config] = await db.select().from(configAttestation).limit(1);

  if (!config) {
    // Créer une configuration par défaut
    await db.insert(configAttestation).values({
      texteAttestation: "Nous attestons que {{nomComplet}} a suivi avec assiduité la formation \"{{nomFormation}}\" organisée du {{dateDebut}} au {{dateFin}}.",
    });

    [config] = await db.select().from(configAttestation).limit(1);
  }

  return config;
}

/**
 * Met à jour la configuration des attestations
 */
export async function updateConfigAttestation(data: {
  logoS3Key?: string;
  logoUrl?: string;
  signatureS3Key?: string;
  signatureUrl?: string;
  nomSignataire?: string;
  fonctionSignataire?: string;
  texteAttestation?: string;
}) {
  const db = await getDb();
  if (!db) return;

  const [existing] = await db.select().from(configAttestation).limit(1);

  if (existing) {
    await db.update(configAttestation).set(data).where(eq(configAttestation.id, existing.id));
  } else {
    await db.insert(configAttestation).values(data);
  }
}

/**
 * Génère une prévisualisation du modèle d'attestation avec des données fictives
 */
export async function genererPreviewAttestation(): Promise<{ pdfUrl: string }> {
  const db = await getDb();
  if (!db) {
    throw new Error("Base de données non disponible");
  }

  // Récupérer la configuration de l'attestation
  const config = await getOrCreateConfigAttestation();
  if (!config) {
    throw new Error("Configuration d'attestation introuvable");
  }

  // Données fictives pour la prévisualisation
  const donneesFictives = {
    apprenant: {
      nom: "Dupont",
      prenom: "Jean",
      email: "jean.dupont@example.com",
    },
    formation: {
      nom: "Formation Manager Itinova",
      nbJours: 5,
    },
    sequence: {
      nom: "Groupe A",
      lieu: "Paris",
    },
    dates: [
      { date: new Date("2026-02-10") },
      { date: new Date("2026-02-11") },
      { date: new Date("2026-02-12") },
      { date: new Date("2026-02-13") },
      { date: new Date("2026-02-14") },
    ],
  };

  // Créer le PDF
  const doc = new PDFDocument({ size: "A4", margin: 50 });
  const chunks: Buffer[] = [];

  doc.on("data", (chunk) => chunks.push(chunk));

  // En-tête avec logo si disponible
  if (config.logoUrl) {
    try {
      const response = await fetch(config.logoUrl);
      const arrayBuffer = await response.arrayBuffer();
      const buffer = Buffer.from(arrayBuffer);
      doc.image(buffer, 50, 45, { width: 100 });
    } catch (error) {
      console.error("Erreur lors du chargement du logo:", error);
    }
  }

  // Titre
  doc
    .fontSize(24)
    .font("Helvetica-Bold")
    .text("ATTESTATION DE FORMATION", 0, 150, { align: "center" });

  doc.moveDown(2);

  // Texte de l'attestation avec remplacement des variables
  let texte = config.texteAttestation || "Nous attestons que {{nomComplet}} a suivi avec assiduité la formation \"{{nomFormation}}\" organisée du {{dateDebut}} au {{dateFin}}.";
  
  const dateDebut = format(donneesFictives.dates[0].date, "d MMMM yyyy", { locale: fr });
  const dateFin = format(donneesFictives.dates[donneesFictives.dates.length - 1].date, "d MMMM yyyy", { locale: fr });
  
  texte = texte
    .replace(/\{\{nomComplet\}\}/g, `${donneesFictives.apprenant.prenom} ${donneesFictives.apprenant.nom}`)
    .replace(/\{\{nomFormation\}\}/g, donneesFictives.formation.nom)
    .replace(/\{\{dateDebut\}\}/g, dateDebut)
    .replace(/\{\{dateFin\}\}/g, dateFin)
    .replace(/\{\{lieu\}\}/g, donneesFictives.sequence.lieu)
    .replace(/\{\{nbJours\}\}/g, donneesFictives.formation.nbJours.toString());

  doc
    .fontSize(12)
    .font("Helvetica")
    .text(texte, { align: "justify", lineGap: 5 });

  doc.moveDown(2);

  // Dates de formation
  doc.fontSize(10).font("Helvetica-Bold").text("Dates de formation :");
  doc.font("Helvetica");
  donneesFictives.dates.forEach((d) => {
    doc.text(`• ${format(d.date, "EEEE d MMMM yyyy", { locale: fr })}`, { indent: 20 });
  });

  doc.moveDown(2);

  // Signature
  doc.fontSize(10).font("Helvetica").text(`Fait à ${donneesFictives.sequence.lieu}, le ${format(new Date(), "d MMMM yyyy", { locale: fr })}`);

  doc.moveDown(1);

  if (config.signatureUrl) {
    try {
      const response = await fetch(config.signatureUrl);
      const arrayBuffer = await response.arrayBuffer();
      const buffer = Buffer.from(arrayBuffer);
      doc.image(buffer, doc.x, doc.y, { width: 150 });
      doc.moveDown(3);
    } catch (error) {
      console.error("Erreur lors du chargement de la signature:", error);
    }
  }

  if (config.nomSignataire) {
    doc.font("Helvetica-Bold").text(config.nomSignataire);
  }
  if (config.fonctionSignataire) {
    doc.font("Helvetica").text(config.fonctionSignataire);
  }

  // Finaliser le PDF
  doc.end();

  await new Promise((resolve) => doc.on("end", resolve));

  const pdfBuffer = Buffer.concat(chunks);

  // Uploader sur S3
  const randomSuffix = crypto.randomBytes(8).toString("hex");
  const s3Key = `attestations/preview/preview-${randomSuffix}.pdf`;
  const { url: pdfUrl } = await storagePut(s3Key, pdfBuffer, "application/pdf");

  return { pdfUrl };
}
