const {onCall} = require("firebase-functions/v2/https");
const admin = require("firebase-admin");
const logger = require("firebase-functions/logger");
const nodemailer = require("nodemailer");
const {getSmtpConfig, EMAIL_CONFIG} = require("./utils/emailConfig");
/**
 * Traite la validation du matériel d'un événement
 * Appelée par le client lors du chargement/déchargement
 * Crée automatiquement les alertes nécessaires
 */
const handler = async (request) => {
  try {
    // L'authentification est automatique avec onCall
    const {auth, data} = request;

    if (!auth) {
      throw new Error("L'utilisateur doit être authentifié");
    }

    const {
      eventId,
      equipmentList, // [{equipmentId, status, quantity, etc.}]
      validationType, // 'LOADING', 'UNLOADING', 'CHECK_OUT', 'CHECK_IN'
    } = data;

    // Validation
    if (!eventId || !equipmentList || !validationType) {
      throw new Error("eventId, equipmentList et validationType sont requis");
    }

    const db = admin.firestore();
    const alerts = [];

    // 1. Récupérer les détails de l'événement
    const eventRef = db.collection("events").doc(eventId);
    const eventDoc = await eventRef.get();

    if (!eventDoc.exists) {
      throw new Error("Événement introuvable");
    }

    const event = eventDoc.data();
    const eventName = event.Name || event.name || "Événement inconnu";
    const eventDate = formatEventDate(event);

    // 2. Analyser les équipements et détecter les problèmes
    for (const equipment of equipmentList) {
      const {equipmentId, status, quantity, expectedQuantity} = equipment;

      // Équipement non emporté: pas d'alerte de perte/manquant au retour.
      if (status === "NOT_TAKEN") {
        continue;
      }

      // Cas 1: Équipement PERDU
      if (status === "LOST") {
        const alertData = await createAlertInFirestore({
          type: "LOST",
          severity: "CRITICAL",
          title: "Équipement perdu",
          message: `Équipement "${equipment.name || equipmentId}" perdu lors de l'événement "${eventName}" (${eventDate})`,
          equipmentId,
          eventId,
          eventName,
          eventDate,
          createdBy: auth.uid,
          metadata: {
            validationType,
            equipment,
          },
        });
        alerts.push(alertData);
      }

      // Cas 2: Équipement MANQUANT
      if (status === "MISSING") {
        const alertData = await createAlertInFirestore({
          type: "EQUIPMENT_MISSING",
          severity: "WARNING",
          title: "Équipement manquant",
          message: `Équipement "${equipment.name || equipmentId}" manquant pour l'événement "${eventName}" (${eventDate})`,
          equipmentId,
          eventId,
          eventName,
          eventDate,
          createdBy: auth.uid,
          metadata: {
            validationType,
            equipment,
          },
        });
        alerts.push(alertData);
      }

      // Cas 3: Quantité incorrecte
      const hasExpectedQuantity = typeof expectedQuantity === "number";
      const hasActualQuantity = typeof quantity === "number";
      if (hasExpectedQuantity && hasActualQuantity && quantity !== expectedQuantity) {
        const alertData = await createAlertInFirestore({
          type: "QUANTITY_MISMATCH",
          severity: "INFO",
          title: "Quantité incorrecte",
          message: `Quantité incorrecte pour "${equipment.name || equipmentId}": ${quantity} au lieu de ${expectedQuantity} attendus`,
          equipmentId,
          eventId,
          eventName,
          eventDate,
          createdBy: auth.uid,
          metadata: {
            validationType,
            equipment,
            expected: expectedQuantity,
            actual: quantity,
          },
        });
        alerts.push(alertData);
      }

      // Cas 4: Équipement endommagé
      if (status === "DAMAGED") {
        const alertData = await createAlertInFirestore({
          type: "DAMAGED",
          severity: "WARNING",
          title: "Équipement endommagé",
          message: `Équipement "${equipment.name || equipmentId}" endommagé durant l'événement "${eventName}" (${eventDate})`,
          equipmentId,
          eventId,
          eventName,
          eventDate,
          createdBy: auth.uid,
          metadata: {
            validationType,
            equipment,
          },
        });
        alerts.push(alertData);
      }
    }

    // 3. Mettre à jour les équipements de l'événement (uniquement lastValidation, assignedEquipment est déjà mis à jour par le client)
    await eventRef.update({
      lastValidation: {
        type: validationType,
        timestamp: admin.firestore.FieldValue.serverTimestamp(),
        by: auth.uid,
      },
    });

    // 4. Envoyer les notifications pour les alertes critiques
    const criticalAlerts = alerts.filter((a) => a.severity === "CRITICAL");
    if (criticalAlerts.length > 0) {
      for (const alert of criticalAlerts) {
        try {
          await sendAlertNotifications(alert, eventId);
        } catch (notificationError) {
          logger.error(`[processEquipmentValidation] Erreur notification alerte ${alert.id}:`, notificationError);
        }
      }
    }

    return {
      success: true,
      alertsCreated: alerts.length,
      criticalAlertsCount: criticalAlerts.length,
      alertIds: alerts.map((a) => a.id),
    };
  } catch (error) {
    logger.error("[processEquipmentValidation] Erreur:", error);
    throw error;
  }
});

/**
 * Crée une alerte dans Firestore
 */
async function createAlertInFirestore(alertData) {
  const db = admin.firestore();
  const alertRef = db.collection("alerts").doc();

  const fullAlertData = {
    id: alertRef.id,
    ...alertData,
    createdAt: admin.firestore.FieldValue.serverTimestamp(),
    isRead: false,
    status: "ACTIVE",
    emailSent: false,
    assignedTo: [],
  };

  await alertRef.set(fullAlertData);

  return {...fullAlertData, id: alertRef.id};
}

/**
 * Détermine les utilisateurs à notifier et envoie les notifications
 */
async function sendAlertNotifications(alert, eventId) {
  const db = admin.firestore();
  const targetUserIds = new Set();
  const usersWithPermission = new Set();

  try {
    // 1. Récupérer TOUS les utilisateurs et leurs permissions
    const allUsersSnapshot = await db.collection("users").get();

    // Créer un map pour stocker les références de rôles à récupérer
    const roleRefs = new Map();

    for (const doc of allUsersSnapshot.docs) {
      const user = doc.data();

      if (!user.role) {
        continue;
      }

      // Extraire le chemin du rôle
      let rolePath = "";
      let roleId = "";

      if (typeof user.role === "string") {
        rolePath = user.role;
        roleId = user.role.split("/").pop();
      } else if (user.role.path) {
        rolePath = user.role.path;
        roleId = user.role.path.split("/").pop();
      } else if (user.role._path && user.role._path.segments) {
        rolePath = user.role._path.segments.join("/");
        roleId = user.role._path.segments[user.role._path.segments.length - 1];
      }

      if (roleId && !roleRefs.has(roleId)) {
        roleRefs.set(roleId, {users: [], rolePath});
      }

      if (roleId) {
        roleRefs.get(roleId).users.push(doc.id);
      }
    }

    // 2. Récupérer les permissions de chaque rôle unique
    for (const [roleId, {users, rolePath}] of roleRefs.entries()) {
      try {
        const roleDoc = await db.collection("roles").doc(roleId).get();

        if (roleDoc.exists) {
          const roleData = roleDoc.data();
          const permissions = roleData.permissions || [];

          // Vérifier si le rôle a la permission view_all_events
          if (permissions.includes("view_all_events")) {
            users.forEach((userId) => {
              usersWithPermission.add(userId);
              targetUserIds.add(userId);
            });
          }
        }
      } catch (error) {
        logger.error(`[sendAlertNotifications] Erreur récupération rôle ${roleId}:`, error);
      }
    }

    // 3. Ajouter la workforce de l'événement
    if (eventId) {
      const eventDoc = await db.collection("events").doc(eventId).get();

      if (eventDoc.exists) {
        const event = eventDoc.data();
        const workforce = event.workforce || [];

        workforce.forEach((member) => {
          // Extraire l'userId selon différentes structures possibles
          let userId = null;

          if (typeof member === "string") {
            userId = member;
          } else if (member.userId) {
            userId = member.userId;
          } else if (member.id) {
            userId = member.id;
          } else if (member.user) {
            if (typeof member.user === "string") {
              userId = member.user;
            } else if (member.user.id) {
              userId = member.user.id;
            }
          }

          if (userId) {
            targetUserIds.add(userId);
          }
        });
      }
    }

    const userIds = Array.from(targetUserIds);

    // 4. Mettre à jour l'alerte avec la liste des utilisateurs
    await db.collection("alerts").doc(alert.id).update({
      assignedTo: userIds,
    });

    // 5. Envoyer les emails si alerte critique
    if (alert.severity === "CRITICAL") {
      await sendAlertEmails(alert, userIds);
    }

    return userIds;
  } catch (error) {
    logger.error("[sendAlertNotifications] Erreur:", error);
    throw error;
  }
}

/**
 * Envoie les emails d'alerte
 */
async function sendAlertEmails(alert, userIds) {
  try {
    const {renderTemplate, getEmailSubject, prepareTemplateData} = require("./utils/emailTemplates");
    const db = admin.firestore();

    // Vérifier que EMAIL_CONFIG est disponible
    if (!EMAIL_CONFIG || !EMAIL_CONFIG.from) {
      logger.error("[sendAlertEmails] EMAIL_CONFIG non configuré");
      return 0;
    }

    const transporter = nodemailer.createTransport(getSmtpConfig());
    let successCount = 0;

    // Envoyer les emails par lots de 5
    const batches = [];
    for (let i = 0; i < userIds.length; i += 5) {
      batches.push(userIds.slice(i, i + 5));
    }

    for (const batch of batches) {
      const promises = batch.map(async (userId) => {
        try {
          // Récupérer l'utilisateur
          const userDoc = await db.collection("users").doc(userId).get();

          if (!userDoc.exists) {
            return false;
          }

          const user = userDoc.data();

          // Vérifier les préférences email
          const prefs = user.notificationPreferences || {};
          if (!prefs.emailEnabled) {
            return false;
          }

          if (!user.email) {
            return false;
          }

          // Préparer et envoyer l'email
          let html;
          try {
            const templateData = await prepareTemplateData(alert, user);
            html = await renderTemplate("alert-individual", templateData);
          } catch (templateError) {
            logger.error(`[sendAlertEmails] Erreur template pour ${userId}:`, templateError);
            html = `
            <html>
              <body>
                <h2>${alert.title || "Nouvelle alerte"}</h2>
                <p>${alert.message}</p>
                <a href="${EMAIL_CONFIG.appUrl}/alerts">Voir l'alerte</a>
              </body>
            </html>
          `;
          }

          await transporter.sendMail({
            from: `"${EMAIL_CONFIG.from.name}" <${EMAIL_CONFIG.from.address}>`,
            to: user.email,
            replyTo: EMAIL_CONFIG.replyTo,
            subject: getEmailSubject(alert),
            html: html,
            text: alert.message,
          });

          return true;
        } catch (error) {
          logger.error(`[sendAlertEmails] Erreur email ${userId}:`, error);
          return false;
        }
      });
      const results = await Promise.all(promises);
      successCount += results.filter((r) => r).length;
    }

    // Mettre à jour l'alerte
    await db.collection("alerts").doc(alert.id).update({
      emailSent: true,
      emailSentAt: admin.firestore.FieldValue.serverTimestamp(),
      emailsSentCount: successCount,
    });

    return successCount;
  } catch (error) {
    logger.error("[sendAlertEmails] Erreur globale:", error);
    return 0;
  }
}

/**
 * Formate la date d'un événement
 */
function formatEventDate(event) {
  const rawDate =
    event?.StartDateTime ||
    event?.startDateTime ||
    event?.startDate ||
    event?.eventDate;

  const parsedDate = parseFirestoreDate(rawDate);
  const safeDate = parsedDate || new Date();

  return safeDate.toLocaleDateString("fr-FR", {
    day: "numeric",
    month: "numeric",
    year: "numeric",
  });
}

function parseFirestoreDate(value) {
  if (!value) {
    return null;
  }

  if (typeof value.toDate === "function") {
    return value.toDate();
  }

  if (value instanceof Date) {
    return value;
  }

  if (typeof value === "string" || typeof value === "number") {
    const date = new Date(value);
    return Number.isNaN(date.getTime()) ? null : date;
  }

  if (typeof value === "object" && typeof value.seconds === "number") {
    return new Date(value.seconds * 1000);
  }

  if (typeof value === "object" && typeof value._seconds === "number") {
    return new Date(value._seconds * 1000);
  }

  return null;
}

exports.processEquipmentValidation = onCall({
  cors: true,
  region: "europe-west9",
}, handler);

exports.handler = handler;

