db_import

<?php
/**
 * db_import.php
 * Import des SMS/MMS depuis un fichier NDJSON (dans un ZIP) vers la BDD
 */

// =============================================================================
// Mapping JSON => PDO
// clé   = nom du champ dans le JSON
// valeur = nom de la colonne en BDD
// =============================================================================
$id_name_sms = [
    "date_sent"      => "date_send",
    "address"        => "tel",
    "date"           => "date_received",
    "__display_name" => "user_name",
    "type"           => "direction",
    "body"           => "msg_text_content"
];

$id_name_mms = [
    "date"           => "date_received",
    "__display_name" => "user_name",
    "msg_box"        => "direction",
];

// Champs obligatoires — si l'un manque, la ligne est skippée
$requis_sms = ['address', 'date', 'type'];
$requis_mms = ['date'];

/**
 * get_zip_path
 * Vérifie que le fichier ZIP existe et retourne son chemin absolu
 * @param string $zip_name
 * @return string|false
 */
function get_zip_path(string $zip_name): string|false
{
    $zip_path = dirname(__DIR__) . '/bkup_messages/' . basename($zip_name);
    if (empty($zip_name) || !file_exists($zip_path)) return false;
    return $zip_path;
}

/**
 * import_bdd
 * Ouvre le ZIP, lit le NDJSON ligne par ligne,
 * vérifie les données et retourne un rapport
 * @param PDO    $pdo
 * @param string $zip_name
 * @return array $rapport
 */
function import_bdd(PDO $pdo, string $zip_name): array
{
    global $id_name_sms, $id_name_mms, $requis_sms, $requis_mms;

    // =========================================================================
    // ÉTAPE 1 — Vérification et ouverture du ZIP
    // Si ça plante ici, on stoppe tout et on retourne une erreur
    // =========================================================================

    $zip_path = get_zip_path($zip_name);
    if ($zip_path === false) {
        return ['erreur' => "L'archive '{$zip_name}' est introuvable."];
    }

    $zip = new ZipArchive();
    if ($zip->open($zip_path) !== true) {
        return ['erreur' => "Impossible d'ouvrir l'archive."];
    }

    $contenu = $zip->getFromName('messages.ndjson');
    $zip->close();
    if ($contenu === false) {
        return ['erreur' => "Impossible de lire messages.ndjson."];
    }

    // =========================================================================
    // ÉTAPE 2 — Initialisation du rapport
    // C'est ce tableau qui sera retourné à la fin avec toutes les infos
    // =========================================================================

    $rapport = [
        'nb_sms'            => 0,   // nombre de SMS détectés
        'nb_mms'            => 0,   // nombre de MMS détectés
        'nb_importes'       => 0,   // nombre de lignes importées avec succès
        'nb_skipped'        => 0,   // nombre de lignes ignorées
        'erreurs_json'      => [],  // lignes non décodables en JSON
        'err_pre_check_bdd' => [],  // lignes avec champs manquants ou vides
        'erreurs_bdd'       => [],  // lignes qui ont planté à l'insertion
    ];

    // =========================================================================
    // ÉTAPE 3 — Boucle ligne par ligne sur le NDJSON
    // =========================================================================

    foreach (explode("\n", trim($contenu)) as $k => $line) {

        // On ignore les lignes vides
        if ($line === '') continue;

        // ---------------------------------------------------------------------
        // Décodage JSON
        // Si la ligne n'est pas du JSON valide, on note l'erreur et on passe
        // à la ligne suivante — pas la peine d'aller plus loin sur cette ligne
        // ---------------------------------------------------------------------
        $json = json_decode($line, true);
        if (json_last_error() !== JSON_ERROR_NONE || !is_array($json)) {
            $rapport['erreurs_json'][$k] = json_last_error_msg();
            $rapport['nb_skipped']++;
            continue; // ligne suivante
        }

        // ---------------------------------------------------------------------
        // Détection SMS ou MMS
        // SMS : pas de __sender_address ni __recipient_addresses
        // MMS : présence de __sender_address ou __recipient_addresses
        // ---------------------------------------------------------------------
        $is_sms  = !isset($json['__sender_address']) && !isset($json['__recipient_addresses']);
        $mapping = $is_sms ? $id_name_sms : $id_name_mms;
        $requis  = $is_sms ? $requis_sms  : $requis_mms;

        if ($is_sms) {
            $rapport['nb_sms']++;
        } else {
            $rapport['nb_mms']++;
        }

        // ---------------------------------------------------------------------
        // Vérification des champs via le mapping
        // Pour chaque champ attendu, on vérifie s'il existe et s'il est valide
        // ---------------------------------------------------------------------
        $fields  = []; // données valides prêtes pour la BDD
        $erreurs = []; // erreurs détectées sur cette ligne

        foreach ($mapping as $k_json => $k_out) {

            // Cas 1 : le champ n'existe pas dans le JSON
            if (!isset($json[$k_json])) {
                $erreurs[$k_json] = "Champ '{$k_json}' non défini à la ligne {$k}";

            // Cas 2 : le champ existe mais il est vide
            } elseif (empty($json[$k_json])) {
                $erreurs[$k_json] = "Champ '{$k_json}' vide à la ligne {$k}";

            // Cas 3 : tout est ok, on récupère la valeur
            } else {
                $fields[$k_out] = $json[$k_json];
            }
        }

        // ---------------------------------------------------------------------
        // Vérification des champs obligatoires
        // Si un champ requis est absent de $fields, on ajoute une erreur
        // ---------------------------------------------------------------------
        foreach ($requis as $champ) {
            if (empty($fields[$champ])) {
                $erreurs[$champ] = "Champ requis '{$champ}' manquant à la ligne {$k}";
            }
        }

        // ---------------------------------------------------------------------
        // Si des erreurs ont été détectées sur cette ligne,
        // on les enregistre dans le rapport et on passe à la ligne suivante
        // ---------------------------------------------------------------------
        if (!empty($erreurs)) {
            $rapport['err_pre_check_bdd'][$k] = $erreurs;
            $rapport['nb_skipped']++;
            continue; // ligne suivante
        }

        // ---------------------------------------------------------------------
        // Ici, $fields contient des données valides et complètes
        // L'insertion en BDD se fera ici — à venir
        // ---------------------------------------------------------------------
        $rapport['nb_importes']++;
    }

    // =========================================================================
    // ÉTAPE 4 — Retour du rapport complet
    // =========================================================================
    return $rapport;
}