<?php
/**
 * Fichier  : api/backup.php
 * Auteur   : KREMER Régis
 * Version  : 2.6.102
 * Date     : 2026-07-21
 * Description : API administrateur — export et restauration des données JSON MageStock.
 *
 * 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, commandes, imports et prix d'achat.
 *   v2.6.6 (2026-07-08) — Renommage de l'export en magestock-backup.
 *   v2.6.84 (2026-07-20) — Restauration protégée par confirmation et validation préalable.
 *   v2.6.99 (2026-07-20) — Export/restauration étendus à toutes les entités persistantes utiles ; rate limits exclus.
 *   v2.6.102 (2026-07-21) — Configuration LDAP exportée désactivée ; secrets, certificats et audit LDAP exclus.
 */
require_once dirname(__DIR__).'/config.php';
require_once dirname(__DIR__).'/includes/ldap-helper.php';
startSession(); requireAdmin(); requirePerm('backup.manage');

/**
 * Entités persistantes incluses dans une sauvegarde applicative.
 * rate_limits est volontairement exclu : il s'agit d'un état de sécurité éphémère.
 */
function backupEntityNames(): array {
    return [
        'alerts', 'brands', 'categories', 'inventories', 'kits', 'locations',
        'movements', 'orders', 'permissions', 'plan_objects', 'plans',
        'product_versions', 'products', 'purchase_prices', 'push_subscriptions',
        'reservations', 'stock', 'suppliers', 'variant_families', 'warehouses',
        // Écrit en dernier lors d'une restauration pour ne pas modifier les comptes
        // avant que toutes les autres entités aient été validées et enregistrées.
        'users',
    ];
}

$method=$_SERVER['REQUEST_METHOD'];
switch($method){
case 'GET':
    $backup=[
        '_meta'=>[
            'app'=>APP_NAME,
            'version'=>APP_VER,
            'exportDate'=>date('c'),
            'formatVersion'=>2,
            'excluded'=>['rate_limits','ldap_bind_secret','ldap_master_key','ldap_ca_certificate','ldap_audit'],
        ],
        'settings'=>getSettings(),
    ];
    $ldapBackup = magestockLdapReadConfig();
    $ldapBackup['enabled'] = false;
    $ldapBackup['mode'] = 'local';
    $ldapBackup['lastSuccessfulTestAt'] = '';
    $ldapBackup['lastSuccessfulTestFingerprint'] = '';
    $ldapBackup['lastSuccessfulTestUser'] = '';
    $backup['ldap_settings'] = [$ldapBackup];
    foreach(backupEntityNames() as $entity) $backup[$entity]=loadData($entity);
    header('Content-Type:application/json;charset=UTF-8');
    header('Content-Disposition:attachment;filename="magestock-backup-'.date('Y-m-d').'.json"');
    echo json_encode($backup,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);exit;

case 'POST':
    csrfCheck();
    $payload=json_decode(file_get_contents('php://input'),true);
    if(!is_array($payload)) jsonError('Format JSON invalide.');
    if(!hash_equals('RESTAURER', (string)($payload['confirmation'] ?? ''))) {
        jsonError('Confirmation de restauration invalide.', 409);
    }
    $body=$payload['backup'] ?? null;
    if(!is_array($body)) jsonError('Sauvegarde MageStock invalide.');
    $meta=$body['_meta'] ?? [];
    if(isset($meta['app']) && stripos((string)$meta['app'], 'MageStock') === false) {
        jsonError('Cette sauvegarde ne provient pas de MageStock.', 422);
    }

    $known=backupEntityNames();
    $present=false;
    foreach($known as $entity){
        if(!array_key_exists($entity,$body)) continue;
        $present=true;
        if(!is_array($body[$entity])) jsonError("Entité '{$entity}' invalide dans la sauvegarde.", 422);
    }
    if(!$present && !isset($body['settings']) && !isset($body['ldap_settings'])) jsonError('La sauvegarde ne contient aucune entité restaurable.', 422);
    if(isset($body['settings']) && !is_array($body['settings'])) jsonError('Paramètres invalides dans la sauvegarde.', 422);
    if(isset($body['ldap_settings']) && (!is_array($body['ldap_settings']) || !is_array($body['ldap_settings'][0] ?? null))) jsonError('Configuration LDAP invalide dans la sauvegarde.', 422);

    // Toutes les validations sont terminées avant la première écriture.
    $restored=[];
    if(isset($body['settings'])) {
        $current = getSettings();
        $incoming = $body['settings'];
        // Compatibilité avec les anciens exports qui pouvaient omettre les clés VAPID.
        foreach(['vapidPrivateKey','vapidPublicKey'] as $secretKey) {
            if(empty($incoming[$secretKey]) && !empty($current[$secretKey])) $incoming[$secretKey] = $current[$secretKey];
        }
        saveSettings($incoming);
        $restored['settings']=1;
    }
    if(isset($body['ldap_settings'][0]) && is_array($body['ldap_settings'][0])) {
        $ldapIncoming = $body['ldap_settings'][0];
        $ldapIncoming['enabled'] = false;
        $ldapIncoming['mode'] = 'local';
        $ldapIncoming['lastSuccessfulTestAt'] = '';
        $ldapIncoming['lastSuccessfulTestFingerprint'] = '';
        $ldapIncoming['lastSuccessfulTestUser'] = '';
        magestockLdapSaveConfig($ldapIncoming, currentUser(), '');
        $restored['ldap_settings']=1;
    }

    foreach($known as $entity) {
        if($entity==='users' || !array_key_exists($entity,$body)) continue;
        saveData($entity,$body[$entity]);
        $restored[$entity]=count($body[$entity]);
    }
    if(array_key_exists('users',$body)) {
        saveData('users',$body['users']);
        $restored['users']=count($body['users']);
    }
    // Une restauration ne doit pas réinjecter un ancien verrouillage anti-bruteforce.
    saveData('rate_limits',[]);
    jsonResponse(['ok'=>true,'message'=>'Sauvegarde MageStock restaurée.','restored'=>$restored]);

default: jsonError('Méthode non supportée.',405);
}
?>
