import { eq, desc, and, gte, lte, sql, like } from "drizzle-orm";
import { getDb } from "./db";
import { logsNotifications, sequences, apprenants, formateurs, formations } from "../drizzle/schema";

export type NotificationType = 
  | "remerciement"
  | "notification_formateur_inscription"
  | "notification_formateur_annulation"
  | "alerte_capacite"
  | "notification_liste_attente";

export interface LogNotificationInput {
  type: NotificationType;
  sequenceId?: number;
  apprenantId?: number;
  formateurId?: number;
  emailDestinataire: string;
  sujet: string;
  statut: "success" | "failed";
  messageErreur?: string;
  metadata?: Record<string, unknown>;
}

/**
 * Enregistre un log de notification
 */
export async function logNotification(input: LogNotificationInput) {
  const db = await getDb();
  if (!db) {
    console.warn("[NotificationLogs] Database not available");
    return;
  }

  try {
    await db.insert(logsNotifications).values({
      type: input.type,
      sequenceId: input.sequenceId || null,
      apprenantId: input.apprenantId || null,
      formateurId: input.formateurId || null,
      emailDestinataire: input.emailDestinataire,
      sujet: input.sujet,
      statut: input.statut,
      messageErreur: input.messageErreur || null,
      metadata: input.metadata ? JSON.stringify(input.metadata) : null,
    });
    console.log(`[NotificationLogs] Log créé: ${input.type} -> ${input.emailDestinataire} (${input.statut})`);
  } catch (error) {
    console.error("[NotificationLogs] Erreur lors de la création du log:", error);
  }
}

/**
 * Récupère l'historique des notifications avec filtres
 */
export async function getNotificationLogs(filters?: {
  type?: NotificationType;
  dateDebut?: Date;
  dateFin?: Date;
  statut?: "success" | "failed";
  email?: string;
  sequenceId?: number;
  limit?: number;
  offset?: number;
}) {
  const db = await getDb();
  if (!db) return { logs: [], total: 0 };

  const conditions = [];

  if (filters?.type) {
    conditions.push(eq(logsNotifications.type, filters.type));
  }
  if (filters?.dateDebut) {
    conditions.push(gte(logsNotifications.dateEnvoi, filters.dateDebut));
  }
  if (filters?.dateFin) {
    conditions.push(lte(logsNotifications.dateEnvoi, filters.dateFin));
  }
  if (filters?.statut) {
    conditions.push(eq(logsNotifications.statut, filters.statut));
  }
  if (filters?.email) {
    conditions.push(like(logsNotifications.emailDestinataire, `%${filters.email}%`));
  }
  if (filters?.sequenceId) {
    conditions.push(eq(logsNotifications.sequenceId, filters.sequenceId));
  }

  const whereClause = conditions.length > 0 ? and(...conditions) : undefined;

  // Récupérer les logs avec les informations associées
  const logs = await db
    .select({
      id: logsNotifications.id,
      type: logsNotifications.type,
      sequenceId: logsNotifications.sequenceId,
      apprenantId: logsNotifications.apprenantId,
      formateurId: logsNotifications.formateurId,
      emailDestinataire: logsNotifications.emailDestinataire,
      sujet: logsNotifications.sujet,
      dateEnvoi: logsNotifications.dateEnvoi,
      statut: logsNotifications.statut,
      messageErreur: logsNotifications.messageErreur,
      metadata: logsNotifications.metadata,
      sequenceNom: sequences.nom,
      formationNom: formations.nom,
      apprenantNom: apprenants.nom,
      apprenantPrenom: apprenants.prenom,
      formateurNom: formateurs.nom,
    })
    .from(logsNotifications)
    .leftJoin(sequences, eq(logsNotifications.sequenceId, sequences.id))
    .leftJoin(formations, eq(sequences.formationId, formations.id))
    .leftJoin(apprenants, eq(logsNotifications.apprenantId, apprenants.id))
    .leftJoin(formateurs, eq(logsNotifications.formateurId, formateurs.id))
    .where(whereClause)
    .orderBy(desc(logsNotifications.dateEnvoi))
    .limit(filters?.limit || 50)
    .offset(filters?.offset || 0);

  // Compter le total
  const [countResult] = await db
    .select({ count: sql<number>`COUNT(*)` })
    .from(logsNotifications)
    .where(whereClause);

  // S'assurer que les logs sont bien définis et que tous les champs sont valides
  const safeLogs = (logs || []).map(log => ({
    ...log,
    sequenceNom: log.sequenceNom || null,
    formationNom: log.formationNom || null,
    apprenantNom: log.apprenantNom || null,
    apprenantPrenom: log.apprenantPrenom || null,
    formateurNom: log.formateurNom || null,
    messageErreur: log.messageErreur || null,
    metadata: log.metadata || null,
  }));

  return {
    logs: safeLogs,
    total: countResult?.count || 0,
  };
}

/**
 * Récupère les statistiques des notifications
 */
export async function getNotificationStats(filters?: {
  dateDebut?: Date;
  dateFin?: Date;
}) {
  const db = await getDb();
  if (!db) return null;

  const conditions = [];
  if (filters?.dateDebut) {
    conditions.push(gte(logsNotifications.dateEnvoi, filters.dateDebut));
  }
  if (filters?.dateFin) {
    conditions.push(lte(logsNotifications.dateEnvoi, filters.dateFin));
  }

  const whereClause = conditions.length > 0 ? and(...conditions) : undefined;

  // Statistiques globales
  const [globalStats] = await db
    .select({
      total: sql<number>`COUNT(*)`,
      success: sql<number>`SUM(CASE WHEN statut = 'success' THEN 1 ELSE 0 END)`,
      failed: sql<number>`SUM(CASE WHEN statut = 'failed' THEN 1 ELSE 0 END)`,
    })
    .from(logsNotifications)
    .where(whereClause);

  // Statistiques par type
  const statsByType = await db
    .select({
      type: logsNotifications.type,
      total: sql<number>`COUNT(*)`,
      success: sql<number>`SUM(CASE WHEN statut = 'success' THEN 1 ELSE 0 END)`,
      failed: sql<number>`SUM(CASE WHEN statut = 'failed' THEN 1 ELSE 0 END)`,
    })
    .from(logsNotifications)
    .where(whereClause)
    .groupBy(logsNotifications.type);

  // Évolution par jour (7 derniers jours)
  const evolutionParJour = await db
    .select({
      date: sql<string>`DATE(dateEnvoi)`,
      total: sql<number>`COUNT(*)`,
      success: sql<number>`SUM(CASE WHEN statut = 'success' THEN 1 ELSE 0 END)`,
      failed: sql<number>`SUM(CASE WHEN statut = 'failed' THEN 1 ELSE 0 END)`,
    })
    .from(logsNotifications)
    .where(whereClause)
    .groupBy(sql`DATE(dateEnvoi)`)
    .orderBy(sql`DATE(dateEnvoi)`)
    .limit(30);

  // Vérifier que globalStats existe et a des valeurs valides
  const total = globalStats?.total || 0;
  const success = globalStats?.success || 0;
  const failed = globalStats?.failed || 0;
  const tauxSucces = total > 0 ? Math.round((success / total) * 100) : 0;

  return {
    global: {
      total,
      success,
      failed,
      tauxSucces,
    },
    parType: statsByType || [],
    evolutionParJour: evolutionParJour || [],
  };
}

/**
 * Labels pour les types de notifications
 */
export const notificationTypeLabels: Record<NotificationType, string> = {
  remerciement: "Remerciement post-formation",
  notification_formateur_inscription: "Notification formateur (inscription)",
  notification_formateur_annulation: "Notification formateur (annulation)",
  alerte_capacite: "Alerte capacité atteinte",
  notification_liste_attente: "Notification liste d'attente",
};
