<?php

// Fonction pour calculer le fingerprint d'un fichier audio
function calculate_fingerprint($file) {
    $return_code = 0;

    $file_bash = str_replace(['$'], ['\$'], $file);

    exec("fpcalc -json \"$file_bash\" 2>&1", $output, $return_code);
    // Vérifier s'il y a eu une erreur lors de l'exécution de la commande
    if ($return_code !== 0) {
        // Enregistrer l'erreur dans un fichier journal par exemple
        error_log("Erreur lors du calcul du fingerprint pour le fichier \"$file_bash\" : " . implode("\n", $output));
        return null; // Retourner null pour indiquer une erreur
    }

    // Traitement de la réponse
    $result = json_decode(implode('', $output), true);

    // Vérifier si le résultat est valide
    if (isset($result['fingerprint'])) {
        return $result['fingerprint']; // Retourner le fingerprint
    } else {
        // Enregistrer un message d'erreur dans le journal
        error_log("Réponse invalide lors du calcul du fingerprint pour le fichier $file : " . implode("\n", $output));
        return null; // Retourner null en cas de réponse invalide
    }
}


function getTagValue($metadataInFile, $tagKey) {
    // Vérifier si la clé existe dans le tableau et retourner sa valeur si c'est le cas
    if (isset($metadataInFile['streams'][0]['tags'][$tagKey])) {
        return $metadataInFile['streams'][0]['tags'][$tagKey];
    } else {
        // Retourner null si la clé n'existe pas
        return null;
    }
}


// Fonction pour extraire les métadonnées d'un fichier audio
function extract_metadata($file) {

    # Extraire les métadonnées avec ffprobe
    $ffprobe_output = shell_exec("ffprobe -hide_banner -loglevel fatal -show_error -show_format -show_streams -print_format json \"$file\"");
    
    // Décoder la sortie JSON
    $metadataInFile = json_decode($ffprobe_output, true);
    
    // Vérifier si les métadonnées contiennent les tags
    if (isset($metadataInFile['streams'][0]['tags'])) {


        // Extraire les metadonnées
        $metadata['ARTIST'] = getTagValue($metadataInFile, 'ARTIST');
        $metadata['TITLE'] = getTagValue($metadataInFile, 'TITLE');
        $metadata['ALBUM'] = getTagValue($metadataInFile, 'ALBUM');
        $metadata['ACOUSTID'] = getTagValue($metadataInFile, 'ACOUSTID_ID');
        $metadata['duration'] = isset($metadataInFile['format']['duration']) ? (float)$metadataInFile['format']['duration'] : null;

    }


    if (isset($metadata)) {
        return $metadata;
    } else {
        return null;
    }

    
}

// Vérifier si le nombre de paramètres est correct
if ($argc != 3) {
    die("Usage: php scan_files.php <directory> <database>\n");
}

$directory = $argv[1];
$db_file = $argv[2];

// Vérifier si le dossier existe
if (!is_dir($directory)) {
    die("Le dossier spécifié n'existe pas.\n");
}

// Vérifier si la base de données existe, sinon la créer
if (!file_exists($db_file)) {
    echo "La base de données n'existe pas. Création en cours...\n";
    $db = new PDO("sqlite:$db_file");
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Créer les tables
    $db->exec("CREATE TABLE IF NOT EXISTS files (
        id INTEGER PRIMARY KEY,
        file_path TEXT UNIQUE,
        first_referenced DATETIME,
        last_updated DATETIME
    )");
    $db->exec("CREATE TABLE IF NOT EXISTS fingerprints (
        id INTEGER PRIMARY KEY,
        file_id INTEGER UNIQUE,
        fingerprint TEXT,
        FOREIGN KEY (file_id) REFERENCES files(id)
    )");
    $db->exec("CREATE TABLE IF NOT EXISTS metadata (
        file_id INTEGER PRIMARY KEY,
        artist TEXT,
        title TEXT,
        album TEXT,
        duration REAL,
        acoustid TEXT,
        FOREIGN KEY (file_id) REFERENCES files(id)
    )");

    // Création de la table system_info si elle n'existe pas déjà
    $db->exec("CREATE TABLE IF NOT EXISTS system_info (
        id INTEGER PRIMARY KEY,
        version INTEGER NOT NULL
    )");
        
    // Insertion des données de version
    $version = "1";
    $insert_version_sql = "INSERT INTO system_info (version) VALUES (:version)";
    $stmt = $db->prepare($insert_version_sql);
    $stmt->bindParam(':version', $version, PDO::PARAM_STR);
    $stmt->execute();

    echo "Base de données créée avec succès.\n";
} else {
    // Connexion à la base de données SQLite
    $db = new PDO("sqlite:$db_file");
}

// Préparation de la requête d'insertion des fichiers
$insert_file_stmt = $db->prepare("INSERT INTO files (file_path, first_referenced, last_updated) VALUES (:file_path, DATETIME('now'), DATETIME('now'))");

// Préparer la requête SQL d'insertion ou de mise à jour des empreintes digitales
$insert_fingerprint_sql = "INSERT INTO fingerprints (file_id, fingerprint)
                           VALUES (:file_id, :fingerprint)
                           ON CONFLICT(file_id) DO UPDATE
                           SET fingerprint = :fingerprint";

$insert_fingerprint_stmt = $db->prepare($insert_fingerprint_sql);

// Préparer la requête SQL d'insertion ou de mise à jour des métadonnées
$insert_metadata_sql = "INSERT INTO metadata (file_id, artist, title, album, acoustid, duration)
                        VALUES (:file_id, :artist, :title, :album, :acoustid, :duration)
                        ON CONFLICT(file_id) DO UPDATE
                        SET artist = :artist,
                            title = :title,
                            album = :album,
                            acoustid = :acoustid,
                            duration = :duration";

$insert_metadata_stmt = $db->prepare($insert_metadata_sql);

$count = 0; // Initialisation du compteur

// Parcourir les fichiers audio
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
foreach ($iterator as $file) {

    $file_bash = escapeshellarg($file);

    if ($file->isFile() && in_array($file->getExtension(), ['mp3', 'opus', 'ogg', 'm4a'])) {

        if ($count % 10 == 0) {
            echo "\rProgress: $count files processed\n";
        }

        $file_path = $file->getPathname();

        // Vérifier si le fichier existe déjà dans la base de données
        $result = $db->query("SELECT id FROM files WHERE file_path = " . $db->quote($file_path));
        $file_id = $result->fetchColumn();

        if (!$file_id) {
            // Insérer le fichier dans la base de données
            $insert_file_stmt->execute([':file_path' => $file_path]);
            $file_id = $db->lastInsertId();
            
            // Calculer le fingerprint du fichier
            // $fingerprint = calculate_fingerprint($file_path);
        
            // Insérer le fingerprint dans la base de données
            // $insert_fingerprint_stmt->execute([':file_id' => $file_id, ':fingerprint' => $fingerprint]);

        } else {
            // Mettre à jour la date de dernière mise à jour du fichier
            $db->exec("UPDATE files SET last_updated = DATETIME('now') WHERE id = $file_id");
        }


        // Extraire les métadonnées du fichier audio
        $metadata = extract_metadata($file_path);

        // Insérer les métadonnées dans la base de données
        $insert_metadata_stmt->execute([
            ':file_id' => $file_id,
            ':artist' => isset($metadata['ARTIST']) ? $metadata['ARTIST'] : null,
            ':title' => isset($metadata['TITLE']) ? $metadata['TITLE'] : null,
            ':album' => isset($metadata['ALBUM']) ? $metadata['ALBUM'] : null,
            ':acoustid' => isset($metadata['ACOUSTID']) ? $metadata['ACOUSTID'] : null,
            ':duration' => isset($metadata['duration']) ? (int)$metadata['duration'] : null
        ]);

        $count++;
    }
}

// Fermer la connexion à la base de données
$db = null;

echo "Terminé.\n";

?>