import { eq, and, sql } from "drizzle-orm";
import { presences, inscriptions, datesFormation, sequences, apprenants } from "../drizzle/schema";
import { getDb } from "./db";

/**
 * Valider la présence d'un apprenant (par QR code ou manuellement)
 */
export async function validerPresence(params: {
  inscriptionId: number;
  dateFormationId: number;
  periode: "matin" | "apres_midi";
  modeValidation: "qrcode" | "manuel";
  validateurId?: number;
  commentaire?: string;
  signatureUrl?: string;
  signatureS3Key?: string;
}) {
  const db = await getDb();
  if (!db) throw new Error("Database not available");

  // Vérifier si la présence existe déjà pour cette période
  const presenceExistante = await db
    .select()
    .from(presences)
    .where(
      and(
        eq(presences.inscriptionId, params.inscriptionId),
        eq(presences.dateFormationId, params.dateFormationId),
        sql`${presences.periode} = ${params.periode}`
      )
    );

  if (presenceExistante.length > 0) {
    throw new Error(`Présence déjà validée pour ${params.periode === 'matin' ? 'le matin' : 'l\'après-midi'}`);
  }

  // Créer la présence
  await db.insert(presences).values({
    inscriptionId: params.inscriptionId,
    dateFormationId: params.dateFormationId,
    periode: params.periode,
    heurePresence: new Date(),
    modeValidation: params.modeValidation,
    validateurId: params.validateurId,
    commentaire: params.commentaire,
    signatureUrl: params.signatureUrl,
    signatureS3Key: params.signatureS3Key,
    dateSigned: params.signatureUrl ? new Date() : undefined,
  });

  return { success: true };
}

/**
 * Récupérer toutes les présences pour une séquence
 */
export async function getPresencesBySequence(sequenceId: number) {
  const db = await getDb();
  if (!db) throw new Error("Database not available");

  const result = await db
    .select({
      presenceId: presences.id,
      inscriptionId: presences.inscriptionId,
      dateFormationId: presences.dateFormationId,
      periode: presences.periode,
      heurePresence: presences.heurePresence,
      modeValidation: presences.modeValidation,
      validateurId: presences.validateurId,
      commentaire: presences.commentaire,
      signatureUrl: sql<string | null>`${presences}.signatureUrl`,
      signatureS3Key: sql<string | null>`${presences}.signatureS3Key`,
      dateSigned: sql<Date | null>`${presences}.dateSigned`,
      apprenantId: apprenants.id,
      apprenantNom: apprenants.nom,
      apprenantPrenom: apprenants.prenom,
      apprenantEmail: apprenants.email,
      dateDebut: datesFormation.dateDebut,
      dateFin: datesFormation.dateFin,
    })
    .from(presences)
    .innerJoin(inscriptions, eq(presences.inscriptionId, inscriptions.id))
    .innerJoin(apprenants, eq(inscriptions.apprenantId, apprenants.id))
    .innerJoin(datesFormation, eq(presences.dateFormationId, datesFormation.id))
    .where(eq(datesFormation.sequenceId, sequenceId));

  return result;
}

/**
 * Récupérer les présences pour une inscription spécifique
 */
export async function getPresencesByInscription(inscriptionId: number) {
  const db = await getDb();
  if (!db) throw new Error("Database not available");

  const result = await db
    .select({
      presenceId: presences.id,
      dateFormationId: presences.dateFormationId,
      periode: presences.periode,
      heurePresence: presences.heurePresence,
      modeValidation: presences.modeValidation,
      validateurId: presences.validateurId,
      commentaire: presences.commentaire,
      signatureUrl: sql<string | null>`${presences}.signatureUrl`,
      signatureS3Key: sql<string | null>`${presences}.signatureS3Key`,
      dateSigned: sql<Date | null>`${presences}.dateSigned`,
      dateDebut: datesFormation.dateDebut,
      dateFin: datesFormation.dateFin,
    })
    .from(presences)
    .innerJoin(datesFormation, eq(presences.dateFormationId, datesFormation.id))
    .where(eq(presences.inscriptionId, inscriptionId));

  return result;
}

/**
 * Vérifier si toutes les présences sont validées pour une inscription
 */
export async function checkAllPresencesValidated(inscriptionId: number): Promise<boolean> {
  const db = await getDb();
  if (!db) throw new Error("Database not available");

  // Récupérer l'inscription avec la séquence
  const inscription = await db
    .select({
      sequenceId: inscriptions.sequenceId,
    })
    .from(inscriptions)
    .where(eq(inscriptions.id, inscriptionId))
    .limit(1);

  if (inscription.length === 0) {
    throw new Error("Inscription not found");
  }

  // Compter le nombre de dates de formation pour cette séquence
  const datesCount = await db
    .select({ count: datesFormation.id })
    .from(datesFormation)
    .where(eq(datesFormation.sequenceId, inscription[0].sequenceId));

  // Compter le nombre de présences validées pour cette inscription
  const presencesCount = await db
    .select({ count: presences.id })
    .from(presences)
    .where(eq(presences.inscriptionId, inscriptionId));

  return presencesCount.length === datesCount.length;
}

/**
 * Supprimer une présence
 */
export async function supprimerPresence(presenceId: number) {
  const db = await getDb();
  if (!db) throw new Error("Database not available");

  await db.delete(presences).where(eq(presences.id, presenceId));

  return { success: true };
}
