const admin = require("firebase-admin");
const db = admin.firestore();
const logger = require("firebase-functions/logger");
const auth = require("../utils/auth");
const helpers = require("../utils/helpers");

// Créer une maintenance
exports.createMaintenance = async (req, res) => {
  try {
    const decodedToken = await auth.authenticateUser(req);
    const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_maintenances");

    if (!hasAccess) {
      res.status(403).json({error: "Forbidden: Requires manage_maintenances permission"});
      return;
    }

    const maintenanceData = req.body.data;

    const dataToSave = helpers.deserializeTimestamps(maintenanceData, [
      "scheduledDate", "completedDate", "createdAt", "updatedAt",
    ]);

    const docRef = await db.collection("maintenances").add(dataToSave);
    const maintenanceId = docRef.id;

    if (maintenanceData.equipmentIds && Array.isArray(maintenanceData.equipmentIds)) {
      for (const equipmentId of maintenanceData.equipmentIds) {
        try {
          const equipmentDoc = await db.collection("equipments").doc(equipmentId).get();
          if (equipmentDoc.exists) {
            const equipmentData = equipmentDoc.data();
            const maintenanceIds = equipmentData.maintenanceIds || [];
            if (!maintenanceIds.includes(maintenanceId)) {
              maintenanceIds.push(maintenanceId);
              await db.collection("equipments").doc(equipmentId).update({
                maintenanceIds: maintenanceIds,
              });
            }
          }

          if (maintenanceData.scheduledDate) {
            const scheduledDate = maintenanceData.scheduledDate.toDate ?
              maintenanceData.scheduledDate.toDate() :
              new Date(maintenanceData.scheduledDate);
            const sevenDaysFromNow = new Date();
            sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 7);

            if (scheduledDate <= sevenDaysFromNow) {
              const existingAlerts = await db.collection("alerts")
                  .where("equipmentId", "==", equipmentId)
                  .where("type", "==", "maintenanceDue")
                  .where("isRead", "==", false)
                  .get();

              let alertExists = false;
              for (const alertDoc of existingAlerts.docs) {
                const alertData = alertDoc.data();
                if (alertData.message && alertData.message.includes(maintenanceData.name || "")) {
                  alertExists = true;
                  break;
                }
              }

              if (!alertExists) {
                const equipmentName = equipmentDoc.exists ?
                  (equipmentDoc.data().name || equipmentId) :
                  equipmentId;

                const daysUntil = Math.ceil((scheduledDate - new Date()) / (1000 * 60 * 60 * 24));

                await db.collection("alerts").add({
                  type: "maintenanceDue",
                  message: `Maintenance "${maintenanceData.name || "Sans nom"}" prévue dans ${daysUntil} jour(s) pour ${equipmentName}`,
                  equipmentId: equipmentId,
                  createdAt: admin.firestore.Timestamp.now(),
                  isRead: false,
                });
              }
            }
          }
        } catch (err) {
          logger.error(`Error updating equipment ${equipmentId} for maintenance:`, err);
        }
      }
    }

    res.status(201).json({id: maintenanceId, message: "Maintenance created successfully"});
  } catch (error) {
    logger.error("Error creating maintenance:", error);
    res.status(500).json({error: error.message});
  }
};

// Mettre à jour une maintenance
exports.updateMaintenance = async (req, res) => {
  try {
    const decodedToken = await auth.authenticateUser(req);
    const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_maintenances");

    if (!hasAccess) {
      res.status(403).json({error: "Forbidden: Requires manage_maintenances permission"});
      return;
    }

    const {maintenanceId, data} = req.body.data;

    if (!maintenanceId) {
      res.status(400).json({error: "Maintenance ID is required"});
      return;
    }

    delete data.id;
    data.updatedAt = admin.firestore.Timestamp.now();

    const dataToSave = helpers.deserializeTimestamps(data, [
      "scheduledDate", "completedDate",
    ]);

    await db.collection("maintenances").doc(maintenanceId).update(dataToSave);

    res.status(200).json({message: "Maintenance updated successfully"});
  } catch (error) {
    logger.error("Error updating maintenance:", error);
    res.status(500).json({error: error.message});
  }
};

// Récupérer toutes les maintenances
exports.getMaintenances = async (req, res) => {
  try {
    const decodedToken = await auth.authenticateUser(req);
    const {equipmentId} = req.body.data || {};

    const canView = await auth.hasPermission(decodedToken.uid, "view_equipment");

    if (!canView) {
      res.status(403).json({error: "Forbidden: Requires equipment permissions"});
      return;
    }

    let query = db.collection("maintenances");

    if (equipmentId) {
      query = query.where("equipmentIds", "array-contains", equipmentId);
    }

    const snapshot = await query.get();
    const maintenances = snapshot.docs.map((doc) => {
      const data = doc.data();
      return {
        id: doc.id,
        ...helpers.serializeTimestamps(data, ["scheduledDate", "completedDate", "createdAt", "updatedAt"]),
      };
    });

    res.status(200).json({maintenances});
  } catch (error) {
    logger.error("Error fetching maintenances:", error);
    res.status(500).json({error: error.message});
  }
};

// Supprimer une maintenance
exports.deleteMaintenance = async (req, res) => {
  try {
    const decodedToken = await auth.authenticateUser(req);

    const canManage = await auth.hasPermission(decodedToken.uid, "manage_equipment");
    if (!canManage) {
      res.status(403).json({error: "Forbidden: Requires manage_equipment permission"});
      return;
    }

    const maintenanceId = req.body.data?.maintenanceId;
    if (!maintenanceId) {
      res.status(400).json({error: "maintenanceId is required"});
      return;
    }

    const maintenanceDoc = await db.collection("maintenances").doc(maintenanceId).get();
    if (maintenanceDoc.exists) {
      const maintenance = maintenanceDoc.data();

      if (maintenance.equipmentIds) {
        for (const equipmentId of maintenance.equipmentIds) {
          const equipmentDoc = await db.collection("equipments").doc(equipmentId).get();
          if (equipmentDoc.exists) {
            const equipmentData = equipmentDoc.data();
            const maintenanceIds = (equipmentData.maintenanceIds || []).filter((id) => id !== maintenanceId);
            await db.collection("equipments").doc(equipmentId).update({maintenanceIds});
          }
        }
      }
    }

    await db.collection("maintenances").doc(maintenanceId).delete();

    res.status(200).json({success: true});
  } catch (error) {
    logger.error("Error deleting maintenance:", error);
    res.status(500).json({error: error.message});
  }
};

/**
 * Vérifier les maintenances à venir et créer des alertes
 */
exports.checkUpcomingMaintenances = async (req, res) => {
  try {
    const decodedToken = await auth.authenticateUser(req);
    const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_equipment");

    if (!hasAccess) {
      res.status(403).json({error: "Forbidden: Requires manage_equipment permission"});
      return;
    }

    const sevenDaysFromNow = new Date();
    sevenDaysFromNow.setDate(sevenDaysFromNow.getDate() + 7);

    const now = admin.firestore.Timestamp.now();
    const sevenDaysTimestamp = admin.firestore.Timestamp.fromDate(sevenDaysFromNow);

    // Récupérer les maintenances planifiées dans les 7 prochains jours
    const maintenancesSnapshot = await db.collection("maintenances")
        .where("scheduledDate", "<=", sevenDaysTimestamp)
        .where("scheduledDate", ">=", now)
        .get();

    const alertsCreated = [];

    for (const doc of maintenancesSnapshot.docs) {
      const maintenance = doc.data();

      // Vérifier si une alerte existe déjà pour cette maintenance
      const existingAlertSnapshot = await db.collection("alerts")
          .where("type", "==", "MAINTENANCE_DUE")
          .where("relatedMaintenanceId", "==", doc.id)
          .get();

      if (existingAlertSnapshot.empty) {
        // Créer une nouvelle alerte
        const alertData = {
          type: "MAINTENANCE_DUE",
          title: `Maintenance à venir`,
          message: `Une maintenance est prévue pour ${maintenance.equipmentIds?.length || 0} équipement(s)`,
          severity: "MEDIUM",
          isRead: false,
          relatedMaintenanceId: doc.id,
          createdAt: admin.firestore.Timestamp.now(),
        };

        const alertRef = await db.collection("alerts").add(alertData);
        alertsCreated.push({id: alertRef.id, ...alertData});
      }
    }

    res.status(200).json({
      success: true,
      alertsCreated: alertsCreated.length,
      alerts: alertsCreated,
    });
  } catch (error) {
    logger.error("Error checking upcoming maintenances:", error);
    res.status(500).json({error: error.message});
  }
};

/**
 * Compléter une maintenance
 */
exports.completeMaintenance = async (req, res) => {
  try {
    const decodedToken = await auth.authenticateUser(req);
    const hasAccess = await auth.hasPermission(decodedToken.uid, "manage_equipment");

    if (!hasAccess) {
      res.status(403).json({error: "Forbidden: Requires manage_equipment permission"});
      return;
    }

    const {maintenanceId, performedBy, cost} = req.body.data;

    if (!maintenanceId) {
      res.status(400).json({error: "maintenanceId is required"});
      return;
    }

    const now = admin.firestore.Timestamp.now();
    const updateData = {
      completedDate: now,
      updatedAt: now,
    };

    if (performedBy) {
      updateData.performedBy = performedBy;
    }

    if (cost !== undefined && cost !== null) {
      updateData.cost = cost;
    }

    // Mettre à jour la maintenance
    await db.collection("maintenances").doc(maintenanceId).update(updateData);

    // Récupérer la maintenance pour mettre à jour les équipements
    const maintenanceDoc = await db.collection("maintenances").doc(maintenanceId).get();
    const maintenanceData = maintenanceDoc.data();

    // Mettre à jour la date de dernière maintenance des équipements
    if (maintenanceData && maintenanceData.equipmentIds) {
      const updatePromises = maintenanceData.equipmentIds.map((equipmentId) =>
        db.collection("equipments").doc(equipmentId).update({
          lastMaintenanceDate: now,
          updatedAt: now,
        }),
      );

      await Promise.all(updatePromises);
    }

    res.status(200).json({success: true});
  } catch (error) {
    logger.error("Error completing maintenance:", error);
    res.status(500).json({error: error.message});
  }
};
