<?php
if (!defined('PIECES_TYPES')) {
    define('PIECES_TYPES', ['photo' => "Photo d'identité", 'releve_bac' => 'Relevé / attestation du BAC', 'extrait_naissance' => 'Extrait de naissance']);
}
if (!defined('PIECES_MAX')) {
    define('PIECES_MAX', 5 * 1024 * 1024);
}
if (!function_exists('valider_piece_meta')) {
    function valider_piece_meta(string $nom, int $taille): ?string {
        if (mb_strlen($nom) > 255) return 'Nom de fichier trop long.'; // nom_original est un VARCHAR(255)
        $ext = strtolower(pathinfo($nom, PATHINFO_EXTENSION));
        if (!in_array($ext, ['pdf','jpg','jpeg','png'], true)) return 'Format accepté : PDF, JPG ou PNG.';
        if ($taille > PIECES_MAX) return 'Fichier trop volumineux (5 Mo maximum).';
        return null;
    }
}
if (!function_exists('nom_stockage')) {
    function nom_stockage(string $nomOriginal): string {
        // Nommage aléatoire non négociable : le nom fourni par le candidat ne touche jamais le disque.
        return bin2hex(random_bytes(16)) . '.' . strtolower(pathinfo($nomOriginal, PATHINFO_EXTENSION));
    }
}
if (!function_exists('enregistrer_piece')) {
    /**
     * Valide puis enregistre une pièce jointe : fichier sur disque (nom aléatoire) + ligne en table pieces.
     *
     * Contrat : retourne null si l'enregistrement a réussi OU si aucune pièce n'a été fournie
     * (UPLOAD_ERR_NO_FILE — les pièces sont optionnelles au dépôt) ; sinon un message d'erreur
     * en français destiné au candidat. $file est une entrée $_FILES complète
     * (name, type, tmp_name, error, size) : la clé 'error' est examinée avant toute autre validation.
     * $deplacer n'existe que pour les tests (move_uploaded_file exige un vrai POST HTTP).
     *
     * Ne jamais re-servir les fichiers de public/uploads/ directement (le .htaccess les bloque) :
     * uniquement via le futur point d'accès authentifié piece.php.
     */
    function enregistrer_piece(PDO $pdo, int $candidatureId, string $type, array $file, string $uploadsDir, ?callable $deplacer = null): ?string {
        $deplacer ??= 'move_uploaded_file';
        $codeErreur = (int)($file['error'] ?? UPLOAD_ERR_OK);
        if ($codeErreur === UPLOAD_ERR_NO_FILE) return null; // pièce optionnelle : rien à enregistrer
        if ($codeErreur === UPLOAD_ERR_INI_SIZE || $codeErreur === UPLOAD_ERR_FORM_SIZE) return 'Fichier trop volumineux (5 Mo maximum).';
        if ($codeErreur !== UPLOAD_ERR_OK) return 'Le téléversement a échoué. Veuillez réessayer.';
        if (!array_key_exists($type, PIECES_TYPES)) return 'Type de pièce inconnu.';
        $err = valider_piece_meta($file['name'], $file['size']);
        if ($err !== null) return $err;
        $mime = mime_content_type($file['tmp_name']);
        if (!in_array($mime, ['application/pdf','image/jpeg','image/png'], true)) return 'Type de fichier non reconnu.';
        $stock = nom_stockage($file['name']);
        if (!is_dir("$uploadsDir/pieces")) mkdir("$uploadsDir/pieces", 0755, true);
        if (!$deplacer($file['tmp_name'], "$uploadsDir/pieces/$stock")) return "Échec de l'enregistrement du fichier.";
        try {
            // nom_original est une saisie du candidat : toujours l'échapper à l'affichage.
            $pdo->prepare('INSERT INTO pieces (candidature_id, type, nom_original, nom_stockage) VALUES (?,?,?,?)')
                ->execute([$candidatureId, $type, $file['name'], $stock]);
        } catch (PDOException $ex) {
            @unlink("$uploadsDir/pieces/$stock"); // pas de fichier orphelin (données personnelles) sans ligne en base
            error_log('enregistrer_piece: INSERT pieces en échec: ' . $ex->getMessage());
            return "Échec de l'enregistrement du fichier.";
        }
        return null;
    }
}
