/**
 * NotificationWatcher — invisible component mounted in AppLayout.
 *
 * Watches the live cost data (refreshed every 30 s) and generates
 * AppNotifications when a budget alert transitions:
 *   - below threshold  →  above threshold  (budget_exceeded)
 *   - below 80 %       →  ≥ 80 %           (budget_warning)
 *
 * Uses refs to track previous state so it fires only on the crossing,
 * not on every subsequent refresh.
 *
 * When an email is configured in localStorage (veylant_notif_email),
 * it also calls POST /v1/notifications/send for each new notification.
 */
import { useEffect, useRef } from "react";
import { useCosts } from "@/api/costs";
import { apiFetch } from "@/api/client";
import { loadNotifications, saveNotifications } from "@/lib/notifications";
import type { AppNotification } from "@/lib/notifications";

const ALERTS_KEY = "veylant_budget_alerts";
const NOTIF_EMAIL_KEY = "veylant_notif_email";

interface BudgetAlert {
  id: string;
  name: string;
  scope: string;
  threshold: number;
}

function loadAlerts(): BudgetAlert[] {
  try {
    return JSON.parse(localStorage.getItem(ALERTS_KEY) ?? "[]");
  } catch {
    return [];
  }
}

async function sendEmailNotification(notif: AppNotification, to: string): Promise<void> {
  await apiFetch("/v1/notifications/send", {
    method: "POST",
    body: JSON.stringify({
      to,
      alert_name: notif.title,
      scope: notif.scope,
      spend: notif.spend,
      threshold: notif.threshold,
      type: notif.type,
    }),
  });
}

export function NotificationWatcher() {
  const { data: costData } = useCosts({ group_by: "provider" }, 30_000);

  const prevExceeded = useRef<Set<string>>(new Set());
  const prevWarning = useRef<Set<string>>(new Set());

  useEffect(() => {
    if (!costData) return;

    const rows = costData.data ?? [];
    const costByProvider = Object.fromEntries(rows.map((c) => [c.key, c.total_cost_usd]));
    const totalCost = rows.reduce((s, c) => s + c.total_cost_usd, 0);

    function getSpend(scope: string): number {
      return scope === "global" ? totalCost : (costByProvider[scope] ?? 0);
    }

    const alerts = loadAlerts();
    const existing = loadNotifications();
    const newNotifs: AppNotification[] = [];

    for (const alert of alerts) {
      const spend = getSpend(alert.scope);
      const pct = alert.threshold > 0 ? (spend / alert.threshold) * 100 : 0;
      const isExceeded = spend >= alert.threshold;
      const isWarning = !isExceeded && pct >= 80;
      const scopeLabel = alert.scope === "global" ? "Dépenses totales" : alert.scope;

      // ── Exceeded ───────────────────────────────────────────────────────────
      if (isExceeded && !prevExceeded.current.has(alert.id)) {
        newNotifs.push({
          id: crypto.randomUUID(),
          type: "budget_exceeded",
          title: `Seuil dépassé : ${alert.name}`,
          message: `${scopeLabel} : $${spend.toFixed(6)} — seuil $${alert.threshold.toFixed(6)}`,
          alertId: alert.id,
          scope: alert.scope,
          spend,
          threshold: alert.threshold,
          createdAt: new Date().toISOString(),
          readAt: null,
        });
        prevExceeded.current.add(alert.id);
        prevWarning.current.delete(alert.id); // promote from warning
      } else if (!isExceeded) {
        prevExceeded.current.delete(alert.id);
      }

      // ── Warning (80 %) ─────────────────────────────────────────────────────
      if (isWarning && !prevWarning.current.has(alert.id)) {
        newNotifs.push({
          id: crypto.randomUUID(),
          type: "budget_warning",
          title: `Attention : ${alert.name} à ${pct.toFixed(0)} %`,
          message: `${scopeLabel} : $${spend.toFixed(6)} (${pct.toFixed(1)} % du seuil)`,
          alertId: alert.id,
          scope: alert.scope,
          spend,
          threshold: alert.threshold,
          createdAt: new Date().toISOString(),
          readAt: null,
        });
        prevWarning.current.add(alert.id);
      } else if (!isWarning) {
        prevWarning.current.delete(alert.id);
      }
    }

    if (newNotifs.length === 0) return;

    // Persist new notifications
    saveNotifications([...newNotifs, ...existing]);

    // Fire-and-forget email delivery if an address is configured
    const email = localStorage.getItem(NOTIF_EMAIL_KEY);
    if (email) {
      for (const n of newNotifs) {
        sendEmailNotification(n, email).catch(() => {
          // Non-blocking: email failure should never break the UI
        });
      }
    }
  }, [costData]);

  return null;
}
