<?php
/**
 * Fichier  : includes/push-helper.php
 * Auteur   : KREMER Régis
 * Version  : 2.6.6
 * Date     : 2026-02-21
 * Description : Helper envoi de notifications Web Push (VAPID)
 *
 * Changelog :
 *   v2.1.0 (2026-02-21) — Version initiale auditée et sécurisée
 *   v2.1.1 (2026-02-21) — Corrections sécurité (CSRF, MIME, session, migrateSuppliers)
 *   v2.2.0 (2026-02-21) — Permissions magasins, bons de commande, rapport d'écart,
 *                      import CSV, historique prix, bon de livraison multi-lignes
 */
// ================================================================
// includes/push-helper.php — Helper pour envoyer des notifications push
// À inclure dans les API qui déclenchent des notifications
// ================================================================

/**
 * Envoie une notification push à tous les admins sauf l'initiateur
 * 
 * @param string $type Type de notification (stock_out, stock_in, alert, inventory)
 * @param string $title Titre de la notification
 * @param string $body Corps du message
 * @param array $data Données additionnelles (url, etc.)
 * @param int|null $excludeUserId ID de l'utilisateur à exclure (l'initiateur)
 * @return int Nombre de notifications envoyées
 */
function sendPushToAdmins(string $type, string $title, string $body, array $data = [], ?int $excludeUserId = null): int {
    $subs = loadData('push_subscriptions');
    $users = loadData('users');
    
    if (empty($subs)) {
        return 0;
    }
    
    // Trouver les IDs des admins actifs
    $adminIds = [];
    foreach ($users as $u) {
        if (($u['role'] ?? '') === 'admin' && ($u['active'] ?? true) !== false) {
            $adminIds[] = (int)$u['id'];
        }
    }
    
    if (empty($adminIds)) {
        return 0;
    }
    
    // Préparer le payload
    $payload = [
        'title' => $title,
        'body' => $body,
        'type' => $type,
        'icon' => assetUrl('img/icon-192.png'),
        'badge' => assetUrl('img/badge-72.png'),
        'tag' => 'magestock-' . $type . '-' . time(),
        'data' => array_merge(['url' => appUrl()], $data),
        'timestamp' => time() * 1000
    ];
    
    $sent = 0;
    
    foreach ($subs as $sub) {
        $subUserId = (int)($sub['userId'] ?? 0);
        
        // Exclure l'initiateur
        if ($excludeUserId !== null && $subUserId === $excludeUserId) {
            continue;
        }
        
        // Envoyer uniquement aux admins
        if (!in_array($subUserId, $adminIds)) {
            continue;
        }
        
        if (sendSinglePush($sub, $payload)) {
            $sent++;
        }
    }
    
    return $sent;
}

/**
 * Envoie une notification push à une subscription spécifique
 */
function sendSinglePush(array $subscription, array $payload): bool {
    $endpoint = $subscription['endpoint'] ?? '';
    $keys = $subscription['keys'] ?? [];
    
    if (empty($endpoint)) {
        return false;
    }
    
    // Préparer le payload JSON
    $payloadJson = json_encode($payload);
    
    // Headers de base
    $headers = [
        'Content-Type: application/json',
        'Content-Length: ' . strlen($payloadJson),
        'TTL: 86400',
        'Urgency: normal'
    ];
    
    // Envoyer via cURL
    $ch = curl_init($endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $payloadJson,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => true
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    
    // Log pour debug
    if ($httpCode !== 201 && $httpCode !== 200) {
        error_log("[PUSH] Erreur envoi à $endpoint: HTTP $httpCode - $error - $response");
    }
    
    // 410 = Gone → subscription expirée, la supprimer
    if ($httpCode === 410) {
        $subs = loadData('push_subscriptions');
        $subs = array_filter($subs, fn($s) => ($s['endpoint'] ?? '') !== $endpoint);
        saveData('push_subscriptions', array_values($subs));
    }
    
    return $httpCode >= 200 && $httpCode < 300;
}

/**
 * Helpers pour les différents types de notifications
 */

function notifyStockOut(string $productName, string $warehouseName, int $quantity, ?int $excludeUserId = null): int {
    return sendPushToAdmins(
        'stock_out',
        '📤 Sortie de stock',
        "$quantity × $productName sorti(s) de $warehouseName",
        ['url' => appUrl('index.php?page=movements')],
        $excludeUserId
    );
}

function notifyStockIn(string $productName, string $warehouseName, int $quantity, ?int $excludeUserId = null): int {
    return sendPushToAdmins(
        'stock_in',
        '📥 Entrée de stock',
        "$quantity × $productName ajouté(s) à $warehouseName",
        ['url' => appUrl('index.php?page=movements')],
        $excludeUserId
    );
}

function notifyStockAlert(string $productName, string $warehouseName, string $alertType, int $currentQty, int $threshold): int {
    $typeLabel = $alertType === 'min' ? 'Stock bas' : 'Stock élevé';
    $emoji = $alertType === 'min' ? '⚠️' : '📈';
    
    return sendPushToAdmins(
        'alert',
        "$emoji $typeLabel",
        "$productName dans $warehouseName: $currentQty unités (seuil: $threshold)",
        ['url' => appUrl('index.php?page=alerts')],
        null // Alertes envoyées à tous les admins
    );
}

function notifyInventoryComplete(string $warehouseName, int $productCount, int $discrepancies, ?int $excludeUserId = null): int {
    $emoji = $discrepancies > 0 ? '⚠️' : '✅';
    $status = $discrepancies > 0 ? "$discrepancies écart(s) trouvé(s)" : "Aucun écart";
    
    return sendPushToAdmins(
        'inventory',
        "$emoji Inventaire terminé",
        "$warehouseName: $productCount produits vérifiés. $status",
        ['url' => appUrl('index.php?page=inventory')],
        $excludeUserId
    );
}

/**
 * Vérifie les alertes pour un produit/magasin et envoie des notifications si déclenchées
 */
function checkAndNotifyAlerts(int $productId, int $warehouseId): void {
    $alerts = loadData('alerts');
    $stock = loadData('stock');
    $products = loadData('products');
    $warehouses = loadData('warehouses');
    
    // Trouver le stock actuel
    $currentQty = 0;
    foreach ($stock as $s) {
        if ((int)($s['productId'] ?? 0) === $productId && (int)($s['warehouseId'] ?? 0) === $warehouseId) {
            $currentQty = (int)($s['quantity'] ?? 0);
            break;
        }
    }
    
    // Vérifier les alertes
    foreach ($alerts as $alert) {
        if ((int)($alert['productId'] ?? 0) !== $productId) continue;
        if ((int)($alert['warehouseId'] ?? 0) !== $warehouseId) continue;
        
        $threshold = (int)($alert['threshold'] ?? 0);
        $type = $alert['type'] ?? 'min';
        $wasTriggered = $alert['triggered'] ?? false;
        
        $isTriggered = ($type === 'min') ? ($currentQty <= $threshold) : ($currentQty >= $threshold);
        
        // Envoyer notification seulement si l'alerte vient de se déclencher (pas déjà active)
        if ($isTriggered && !$wasTriggered) {
            $product = findById($products, $productId);
            $warehouse = findById($warehouses, $warehouseId);
            
            $prodName = $product ? $product['name'] : 'Produit';
            $whName = $warehouse ? $warehouse['name'] : 'Magasin';
            
            notifyStockAlert($prodName, $whName, $type, $currentQty, $threshold);
        }
    }
}
