import { prisma } from "./prisma";
import { distanceMeters } from "./geo";
import { sendText } from "./evolution";

const COOLDOWN_MS = 5 * 60 * 1000; // anti-spam : 5 min entre deux alertes

// Message par défaut (variables substituées). Modifiable par le Super Admin.
export const DEFAULT_GEOFENCE_MESSAGE =
  "⚠️ Alerte localisation : « {device} » s'est éloigné de {distance} m du point de référence " +
  "(seuil {radius} m).";

// Construit le message final à partir d'un modèle et des données de la position.
export function formatAlert(
  template: string | null | undefined,
  data: { device: string; distance: number; radius: number; lat: number; lng: number }
): string {
  const link = `https://www.openstreetmap.org/?mlat=${data.lat}&mlon=${data.lng}#map=17/${data.lat}/${data.lng}`;
  return (template && template.trim() ? template : DEFAULT_GEOFENCE_MESSAGE)
    .replace(/\{device\}/g, data.device)
    .replace(/\{distance\}/g, String(Math.round(data.distance)))
    .replace(/\{radius\}/g, String(data.radius))
    .replace(/\{lat\}/g, String(data.lat))
    .replace(/\{lng\}/g, String(data.lng))
    .replace(/\{link\}/g, link);
}

// Évalue la zone d'un appareil pour une nouvelle position. N'alerte (WhatsApp) qu'au
// **franchissement** sortant de la zone (inside → outside), avec un délai anti-spam.
// Conçu pour ne jamais faire échouer l'ingestion : toute erreur est avalée.
export async function evaluateGeofence(deviceId: string, lat: number, lng: number): Promise<void> {
  try {
    const geo = await prisma.geofence.findUnique({
      where: { deviceId },
      include: { device: true },
    });
    if (!geo || !geo.enabled) return;

    const dist = distanceMeters(geo.refLat, geo.refLng, lat, lng);
    const inside = dist <= geo.radiusM;

    // Première évaluation : on établit la base sans alerter.
    if (geo.lastInside === null || geo.lastInside === undefined) {
      await prisma.geofence.update({ where: { deviceId }, data: { lastInside: inside } });
      return;
    }

    // Sortie de zone détectée (était dedans, maintenant dehors).
    if (geo.lastInside === true && !inside) {
      const now = Date.now();
      const cool = geo.lastNotifiedAt ? now - geo.lastNotifiedAt.getTime() < COOLDOWN_MS : false;
      if (!cool) {
        const msg = formatAlert(geo.message, {
          device: geo.device.name,
          distance: dist,
          radius: geo.radiusM,
          lat,
          lng,
        });
        try {
          await sendText(geo.notifyNumber, msg);
        } catch (e) {
          console.warn("[geofence] envoi WhatsApp échoué:", (e as Error).message);
        }
        await prisma.geofence.update({
          where: { deviceId },
          data: { lastInside: false, lastNotifiedAt: new Date() },
        });
        return;
      }
    }

    // Mise à jour de l'état (rentrée en zone, ou déplacement interne).
    if (geo.lastInside !== inside) {
      await prisma.geofence.update({ where: { deviceId }, data: { lastInside: inside } });
    }
  } catch (e) {
    console.warn("[geofence] évaluation échouée:", (e as Error).message);
  }
}
