<?php
/**
 * Partage - Entry point for shared student submission forms.
 *
 * Routes:
 *   /partage/<slug>          - Render the share-link form (or password gate)
 *   /partage/<slug>/submit    - POST endpoint for form submissions via share link
 *   /partage/recapitulatif.php?id=N - Post-submission confirmation page
 */
require_once __DIR__ . '/../../bootstrap.php';
require_once APP_ROOT . '/src/EmailObfuscator.php';

// Parse the requested path from REQUEST_URI
$requestUri = $_SERVER['REQUEST_URI'] ?? '';
// Remove query string
$basePath   = parse_url($requestUri, PHP_URL_PATH);
// Extract the part after /partage/
$path = trim(str_replace('/partage/', '', $basePath), '/');

// Split into parts: /partage/<slug>/<action>
$parts = explode('/', $path);
$slug  = $parts[0] ?? '';
$action = $parts[1] ?? '';

// Special route: /partage/language-autre-fragment (HTMX fragment, no auth needed)
if ($slug === 'language-autre-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();
    require_once __DIR__ . '/language-autre-fragment.php';
    exit;
}

// Special route: /partage/format-website-fragment (HTMX fragment, legacy — kept for safety)
if ($slug === 'format-website-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();
    require_once __DIR__ . '/format-website-fragment.php';
    exit;
}

// Special route: /partage/validate-file-fragment (HTMX fragment — file MIME/size validation)
if ($slug === 'validate-file-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();
    require_once __DIR__ . '/../../src/Controllers/validate-file-fragment-shared.php';
    exit;
}



// Special route: /partage/fichiers-fragment (HTMX fragment — format-aware fichiers block)
if ($slug === 'fichiers-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();
    require_once __DIR__ . '/fichiers-fragment.php';
    exit;
}

// Special route: /partage/licence-fragment (HTMX fragment — licence section with conditional required)
if ($slug === 'licence-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();
    require_once __DIR__ . '/licence-fragment.php';
    exit;
}

// Special route: /partage/tag-search-fragment (HTMX fragment — interactive tag search)
if ($slug === 'tag-search-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();
    require_once __DIR__ . '/tag-search-fragment.php';
    exit;
}

// Special route: /partage/language-search-fragment (HTMX fragment — interactive language search)
if ($slug === 'language-search-fragment' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();
    require_once __DIR__ . '/language-search-fragment.php';
    exit;
}

// Special route: /partage/recapitulatif?id=N
if ($slug === 'recapitulatif' || $slug === 'recapitulatif.php') {
    App::boot();
    require_once __DIR__ . '/recapitulatif.php';
    exit;
}

// Validate slug format: YYYYMMDD-XXXXXXXX (17 chars)
if (!preg_match('#^\d{8}-[A-Z0-9+/]{8}$#', $slug)) {
    App::boot();
    $_SESSION['_flash_error'] = 'Ce lien de partage n\'est pas valide.';
    header('Location: /');
    exit;
}

// Boot for all requests: starts session, initialises DB, ensures CSRF token.
App::boot();

// ── POST: form submission ─────────────────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'submit') {
    error_log('[partage/index.php] SUBMIT ENTRY | slug=' . $slug . ' | content_type=' . ($_SERVER['CONTENT_TYPE'] ?? 'none') . ' | content_length=' . ($_SERVER['CONTENT_LENGTH'] ?? '0') . ' | post_keys=' . implode(',', array_keys($_POST)) . ' | files_count=' . count($_FILES) . ' | files_keys=' . implode(',', array_keys($_FILES)) . ' | queue_tfe=' . (isset($_FILES['queue_file']['name']['tfe']) ? count(array_filter($_FILES['queue_file']['name']['tfe'])) : 0));
    handleShareLinkSubmission($slug);
    exit;
}

// ── GET: render form ─────────────────────────────────────────────────────────

require_once APP_ROOT . '/src/ShareLink.php';
$shareLinkModel = new ShareLink(Database::getInstance());

$validationResult = $shareLinkModel->validateLink($slug);

if (!$validationResult['valid']) {
    $reason = $validationResult['reason'];

    if ($reason === 'not_found') {
        $_SESSION['_flash_error'] = 'Ce lien de partage n\'existe pas ou a été supprimé.';
        header('Location: /');
        exit;
    }

    if ($reason === 'disabled') {
        renderShareLinkError('Lien désactivé', 'Ce lien de partage a été désactivé par un administrateur.');
        exit;
    }

    if ($reason === 'expired') {
        renderShareLinkError('Lien expiré', 'Ce lien de partage a expiré.');
        exit;
    }

    if ($reason === 'needs_password') {
        // If already verified in session, skip the gate and render the form directly
        if (!empty($_SESSION['share_verified_' . $slug])) {
            error_log('[ShareLink] Session already verified for slug=' . $slug . ', rendering form');
            $link = $validationResult['link'];
            renderShareLinkForm($slug, $link);
            exit;
        }

        // Show password gate
        $link = $validationResult['link'];
        error_log('[ShareLink] Password gate triggered for slug=' . $slug . ', method=' . $_SERVER['REQUEST_METHOD']);
        requirePasswordGate($link, $slug);
        exit;
    }

    $_SESSION['_flash_error'] = 'Erreur inattendue.';
    header('Location: /');
    exit;
}

// Link is valid - render the form
$link = $validationResult['link'];
renderShareLinkForm($slug, $link);

// ── Functions ─────────────────────────────────────────────────────────────────

/**
 * Render a styled error page for invalid/expired/disabled share links.
 */
function renderShareLinkError(string $title, string $message): void
{
    $pageTitle = htmlspecialchars($title);
    ?>
    <!DOCTYPE html>
    <html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title><?= $pageTitle ?></title>
        <link rel="apple-touch-icon" sizes="152x152" href="/assets/favicon/apple-touch-icon-152x152.png">
        <link rel="apple-touch-icon" sizes="167x167" href="/assets/favicon/apple-touch-icon-167x167.png">
        <link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon-180x180.png">
        <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png">
        <link rel="shortcut icon" href="/assets/favicon/favicon.ico">
        <meta name="theme-color" content="#ffffff">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/common.css') ?>">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/form.css') ?>">
    </head>
    <body class="student-body">
        <div class="share-error">
            <h1><?= $pageTitle ?></h1>
            <p><?= htmlspecialchars($message) ?></p>
            <a href="/">← Retour à l'accueil</a>
        </div>
    </body>
    </html>
    <?php
}

function requirePasswordGate(array $link, string $slug): void
{
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['share_password'])) {
        error_log('[partage/password-gate] ENTRY | slug=' . $slug . ' | post_keys=' . implode(',', array_keys($_POST)));
        require_once APP_ROOT . '/src/ShareLink.php';
        $shareLinkModel = new ShareLink(Database::getInstance());

        error_log('[ShareLink] Password verification attempt for slug=' . $slug . ', submitted_password_len=' . strlen($_POST['share_password']));

        $hashFromDb = $link['password_hash'] ?? null;
        error_log('[ShareLink] Link password_hash from DB: ' . ($hashFromDb !== null ? 'present (len=' . strlen($hashFromDb) . ')' : 'null'));

        if ($shareLinkModel->verifyPassword($link, $_POST['share_password'])) {
            // Store verified status in session
            $_SESSION['share_verified_' . $slug] = true;
            error_log('[ShareLink] Password verified OK for slug=' . $slug . ', redirecting to form');
            // Redirect to clear POST data
            header('Location: /partage/' . $slug);
            exit;
        } else {
            error_log('[ShareLink] Password verification FAILED for slug=' . $slug);
            $_SESSION['_flash_error'] = 'Mot de passe incorrect.';
            header('Location: /partage/' . $slug);
            exit;
        }
    }

    $pageTitle = 'Accès protégé';

    // Consume flash errors from wrong-password redirects
    $flashError = $_SESSION['_flash_error'] ?? null;
    unset($_SESSION['_flash_error']);

    ?>
    <!DOCTYPE html>
    <html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title><?= htmlspecialchars($pageTitle) ?></title>
        <link rel="apple-touch-icon" sizes="152x152" href="/assets/favicon/apple-touch-icon-152x152.png">
        <link rel="apple-touch-icon" sizes="167x167" href="/assets/favicon/apple-touch-icon-167x167.png">
        <link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon-180x180.png">
        <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png">
        <link rel="shortcut icon" href="/assets/favicon/favicon.ico">
        <meta name="theme-color" content="#ffffff">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/common.css') ?>">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/form.css') ?>">
    </head>
    <body class="student-body">
        <div class="password-gate">
            <h1>🔒 Accès protégé</h1>
            <?php if ($flashError): ?>
            <p class="password-error"><?= htmlspecialchars($flashError) ?></p>
            <?php endif; ?>
            <form method="post">
                <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token'] ?? '') ?>">
                <label for="share_password">Ce lien est protégé par un mot de passe :</label>
                <input type="password" id="share_password" name="share_password" required autofocus>
                <br>
                <button type="submit" class="btn btn--primary">Accéder au formulaire</button>
            </form>
        </div>
    </body>
    </html>
    <?php
}

function renderShareLinkForm(string $slug, array $link): void
{
    require_once APP_ROOT . '/src/Controllers/ThesisCreateController.php';

    try {
        $ctrl = ThesisCreateController::make();
        extract($ctrl->loadFormData());
    } catch (Exception $e) {
        error_log('Failed to load form data: ' . $e->getMessage());
        die('Erreur lors du chargement du formulaire.');
    }

    // Filter out PACS from AP programs for student forms (spec: admin-only AP)
    $apPrograms = array_values(array_filter($apPrograms, fn($ap) => ($ap['code'] ?? '') !== 'PACS'));

    $formData = $_SESSION['form_data_share_' . $slug] ?? [];
    unset($_SESSION['form_data_share_' . $slug]);

    // Determine allowed objet values for this link
    $siteSettings     = Database::getInstance()->getAllSettings();
    $objetRestriction = $link['objet_restriction'] ?? null;
    if ($objetRestriction !== null && $objetRestriction !== '') {
        $allowedObjet = explode(',', $objetRestriction);
    } else {
        $allowedObjet = ['tfe'];
        if (($siteSettings['objet_these_enabled'] ?? '1') === '1') $allowedObjet[] = 'thèse';
        if (($siteSettings['objet_frart_enabled']  ?? '1') === '1') $allowedObjet[] = 'frart';
    }

    // Generate a CSRF token specific to this share link (stored in session)
    $shareCsrfKey = 'share_csrf_' . $slug;
    if (empty($_SESSION[$shareCsrfKey])) {
        $_SESSION[$shareCsrfKey] = bin2hex(random_bytes(32));
    }
    $shareCsrfToken = $_SESSION[$shareCsrfKey];

    $pageTitle  = 'Soumettre un TFE';
    $isVerified = !empty($_SESSION['share_verified_' . $slug]);

    // Build old()-compatible callable from $formData (share forms use the array variant).
    $shareOldFn = fn(string $key, string $default = '') => old($formData, $key, $default);
    // No autofocus in the share form - identity function.
    $shareWithAutofocusFn = fn(string $field, array $attrs = []) => $attrs;

    // Load all form help blocks in one query.
    $helpBlocks = Database::getInstance()->getAllFormHelpBlocks();
    $helpFn = fn(string $key) => empty($helpBlocks[$key]['enabled']) ? '' : ($helpBlocks[$key]['content'] ?? '');

    // ── Shared form variables ──────────────────────────────────────────────
    $mode         = 'partage';
    $formAction   = '/partage/' . urlencode($slug) . '/submit';
    $hiddenFields = '<input type="hidden" name="share_link_token" value="' . htmlspecialchars($shareCsrfToken) . '">';

    $oldFn           = $shareOldFn;
    $withAutofocusFn = $shareWithAutofocusFn;

    // Synopsis extra: inject fieldset_synopsis help block
    ob_start();
    $helpContent = $helpFn('fieldset_synopsis');
    include APP_ROOT . '/templates/partials/form/form-help-block.php';
    $synopsisExtra = ob_get_clean();

    // Jury data from repopulation
    $juryPromoteur    = null;
    $juryPromoteurs   = [];
    $juryPromoteurUlb = null;
    $juryPromoteursUlb = [];
    // promoteurices may be submitted as arrays (multiple entries)
    $promoteursRaw = old($formData, 'jury_promoteur');
    if (is_array($promoteursRaw)) {
        foreach ($promoteursRaw as $name) {
            $name = trim($name ?? '');
            if ($name !== '') $juryPromoteurs[] = ['name' => $name];
        }
    } elseif (is_string($promoteursRaw) && trim($promoteursRaw) !== '') {
        $juryPromoteur = $promoteursRaw;
    }
    $promoteursUlbRaw = old($formData, 'jury_promoteur_ulb_name');
    if (is_array($promoteursUlbRaw)) {
        foreach ($promoteursUlbRaw as $name) {
            $name = trim($name ?? '');
            if ($name !== '') $juryPromoteursUlb[] = ['name' => $name];
        }
    } elseif (is_string($promoteursUlbRaw) && trim($promoteursUlbRaw) !== '') {
        $juryPromoteurUlb = $promoteursUlbRaw;
    }
    $lecteursInternes = [];
    $lecteursExternes = [];
    for ($i = 0; $i < 10; $i++) {
        $n = old($formData, "jury_lecteur_interne:$i");
        if ($n !== '') $lecteursInternes[] = ['name' => $n];
    }
    for ($i = 0; $i < 10; $i++) {
        $n = old($formData, "jury_lecteur_externe:$i");
        if ($n !== '') $lecteursExternes[] = ['name' => $n];
    }
    $showPromoteurUlb = true;
    $promoteurUlbConditional = true;

    // Licence / access
    $libreEnabled        = ($siteSettings['access_type_libre_enabled'] ?? '0') === '1';
    $interneEnabled      = ($siteSettings['access_type_interne_enabled'] ?? '1') === '1';
    $interditEnabled     = ($siteSettings['access_type_interdit_enabled'] ?? '1') === '1';
    $generalitiesHtml    = $helpFn('fieldset_generalites');
    $defaultAccessTypeId = 2;

    // Optional sections
    $showFlash             = true;
    $showIntroHelp         = true;
    $showEmailConfirmation = true;

    // Files: add mode
    $filesMode = 'add';

    // Website URL from repopulation
    $existingWebsiteUrl   = $formData['website_url'] ?? '';
    $existingWebsiteLabel = $formData['website_label'] ?? '';
    $checkedFormatsForSiteWeb = $formData['formats'] ?? [];

    // Context / backoffice not shown in partage
    $currentRaw               = [];
    $contactInterne = null;
    $contactPublic  = false;
    $currentContextNote       = null;
    ?>
    <!DOCTYPE html>
    <html lang="fr">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title><?= htmlspecialchars($pageTitle) ?></title>
        <link rel="apple-touch-icon" sizes="152x152" href="/assets/favicon/apple-touch-icon-152x152.png">
        <link rel="apple-touch-icon" sizes="167x167" href="/assets/favicon/apple-touch-icon-167x167.png">
        <link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon-180x180.png">
        <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png">
        <link rel="shortcut icon" href="/assets/favicon/favicon.ico">
        <meta name="theme-color" content="#ffffff">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/common.css') ?>">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/form.css') ?>">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/filepond.min.css') ?>">
        <link rel="stylesheet" href="<?= App::assetV('/assets/css/filepond-plugin-image-preview.min.css') ?>">
        <script src="<?= App::assetV('/assets/js/filepond.min.js') ?>" defer></script>
        <script src="<?= App::assetV('/assets/js/filepond-plugin-file-validate-type.min.js') ?>" defer></script>
        <script src="<?= App::assetV('/assets/js/filepond-plugin-file-validate-size.min.js') ?>" defer></script>
        <script src="<?= App::assetV('/assets/js/filepond-plugin-image-preview.min.js') ?>" defer></script>
        <script src="<?= App::assetV('/assets/js/filepond-plugin-image-exif-orientation.min.js') ?>" defer></script>
        <script src="<?= App::assetV('/assets/js/file-upload-filepond.js') ?>" defer></script>
        <script src="<?= App::assetV('/assets/js/beforeunload-guard.js') ?>" defer></script>
        <script src="<?= App::assetV('/assets/js/htmx.min.js') ?>" defer></script>
    </head>
    <body class="student-body">
        <main id="main-content">
            <div class="thesis-add-header">
                <h1><?= htmlspecialchars($pageTitle) ?></h1>
                <?php if ($isVerified): ?>
                <span class="share-badge">🔓 Accès partagé</span>
                <?php endif; ?>
                <p class="thesis-add-subtitle">Formulaire pour <a href="/">XAMXAM</a></p>
            </div>

            <div class="share-help-contact">
                <p>Des questions ou un problème avec le formulaire ?
                <a href="<?= EmailObfuscator::mailto('xamxam@erg.be') ?>"><?= EmailObfuscator::email('xamxam@erg.be') ?></a></p>
            </div>

            <?php
            // Show previously-selected files that were lost during validation redirect
            $primedFiles = $_SESSION['share_primed_files_' . $slug] ?? null;
            unset($_SESSION['share_primed_files_' . $slug]);
            if ($primedFiles && count($primedFiles) > 0): ?>
            <div class="flash-warning" role="alert">
                <p>⚠️ Les fichiers suivants avaient été sélectionnés avant l'erreur de validation.
                Veuillez les sélectionner à nouveau :</p>
                <ul>
                    <?php foreach ($primedFiles as $pf): ?>
                    <li><?= htmlspecialchars($pf) ?></li>
                    <?php endforeach; ?>
                </ul>
            </div>
            <?php endif; ?>

            <?php include APP_ROOT . '/templates/partials/form/form.php'; ?>
        </main>
    </body>
    </html>
    <?php
}

/**
 * Handle share link form submission.
 */
function handleShareLinkSubmission(string $slug): void
{
    // Session already started by App::boot() on the GET path; start here
    // only if somehow not yet active (e.g. direct POST without prior GET).
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }

    require_once APP_ROOT . '/src/ShareLink.php';
    require_once APP_ROOT . '/src/RateLimit.php';

    $shareLinkModel = new ShareLink(Database::getInstance());

    $link = $shareLinkModel->findBySlug($slug);

    if ($link === null || !$link['is_active'] || ($link['expires_at'] !== null && strtotime($link['expires_at']) < time())) {
        $_SESSION['_flash_error'] = 'Ce lien n\'est plus valide.';
        header('Location: /partage/' . urlencode($slug));
        exit;
    }

    // ── Rate limiting ────────────────────────────────────────────────────────
    // 5 submissions per IP per 10 minutes, keyed per share link.
    $rateLimitCacheDir = STORAGE_ROOT . '/cache/rate_limit';
    $shareRateLimitId  = 'share_' . $slug . '_' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
    $rateLimit         = new RateLimit(50, 600, $rateLimitCacheDir);

    if (!$rateLimit->checkKey($shareRateLimitId)) {
        $_SESSION['_flash_error'] = 'Trop de tentatives. Veuillez réessayer plus tard.';
        header('Location: /partage/' . urlencode($slug));
        exit;
    }
    // ── End rate limiting ────────────────────────────────────────────────────

    // Check password verification if link has a password
    if ($link['password_hash'] !== null && empty($_SESSION['share_verified_' . $slug])) {
        if (isset($_POST['share_password_submit'])) {
            if ($shareLinkModel->verifyPassword($link, $_POST['share_password_submit'])) {
                $_SESSION['share_verified_' . $slug] = true;
            } else {
                $_SESSION['_flash_error'] = 'Mot de passe incorrect.';
                header('Location: /partage/' . urlencode($slug));
                exit;
            }
        } else {
            $_SESSION['_flash_error'] = 'Vous devez entrer le mot de passe avant de soumettre le formulaire.';
            header('Location: /partage/' . urlencode($slug));
            exit;
        }
    }

    // Validate share-link CSRF token
    $shareCsrfKey = 'share_csrf_' . $slug;
    if (!isset($_POST['share_link_token'], $_SESSION[$shareCsrfKey])
        || !hash_equals($_SESSION[$shareCsrfKey], $_POST['share_link_token'])) {
        error_log('Share link CSRF validation failed for ' . $slug);
        $_SESSION['_flash_error'] = 'Token de sécurité invalide.';
        header('Location: /partage/' . urlencode($slug));
        exit;
    }

    require_once APP_ROOT . '/src/Controllers/ThesisCreateController.php';
    require_once APP_ROOT . '/src/SmtpRelay.php';
    require_once APP_ROOT . '/src/StudentEmail.php';
    require_once APP_ROOT . '/src/AppLogger.php';
    require_once APP_ROOT . '/src/DuplicateThesisException.php';
    require_once APP_ROOT . '/src/ErrorHandler.php';

    $logger = new AppLogger();
    $authorName = $_POST['auteurice'] ?? 'unknown';

    try {
        $ctrl     = ThesisCreateController::make();
        $thesisId = $ctrl->submit($_POST, $_FILES);

        // Collect file processing warnings (invalid types, too large, etc.)
        $fileWarnings = $ctrl->getFileWarnings();
        if ($fileWarnings) {
            $_SESSION['_flash_warning'] = implode("\n", $fileWarnings);
        }

        $identifier = $ctrl->getIdentifier($thesisId);
        $logger->logSubmission('partage', $thesisId, $identifier, $authorName, [
            'share_slug' => $slug,
        ]);

        // Mark the link as used
        $shareLinkModel = new ShareLink(Database::getInstance());
        $shareLinkModel->incrementUsage($link['id']);

        // Clean up share-specific session data
        unset($_SESSION[$shareCsrfKey]);
        unset($_SESSION['share_verified_' . $slug]);

        // Send confirmation e-mail - on delivery failure, redirect to retry page
        $emailError = null;
        try {
            $emailSent = StudentEmail::sendConfirmation(Database::getInstance(), $thesisId, $_POST);
            $_SESSION['share_email_sent'] = $emailSent;
        } catch (SmtpSendException $e) {
            ErrorHandler::log('partage_smtp', $e, ['slug' => $slug, 'thesis_id' => $thesisId]);
            if ($e->isRecipientRejected()) {
                $_SESSION['share_email_retry_thesis'] = $thesisId;
                $_SESSION['share_email_retry_error']  = $e->smtpResponse;
                header('Location: /partage/retry-email?id=' . urlencode((string)$thesisId));
                exit();
            }
            // Non-recipient errors (relay down, etc.) - skip email silently
            $_SESSION['share_email_sent'] = false;
        }

        // Redirect to thanks page
        header('Location: /partage/recapitulatif?id=' . urlencode((string)$thesisId));
        exit();

    } catch (DuplicateThesisException $e) {
        $logger->logDuplicate('partage', $authorName, $e->existingThesisId, $e->existingIdentifier, [
            'share_slug' => $slug,
        ]);
        ErrorHandler::log('partage_duplicate', $e, ['slug' => $slug, 'author' => $authorName]);

        // Repopulate the form and surface a clear warning to the student.
        // Store as plain text — htmlspecialchars() is applied at render time.
        $_SESSION['_flash_warning'] = 'Votre soumission ressemble à un TFE déjà enregistré.'
            . "\n" . $e->existingIdentifier . ' — ' . $e->existingTitle . ' (' . $e->existingYear . ')';
        $_SESSION['_flash_contact'] = true;
        $_SESSION['form_data_share_' . $slug] = $_POST;
        storePrimedFiles($slug);
        $_SESSION[$shareCsrfKey] = bin2hex(random_bytes(32)); // Regenerate token

        header('Location: /partage/' . urlencode($slug));
        exit();

    } catch (Exception $e) {
        $logger->logError('partage', $e->getMessage(), [
            'share_slug' => $slug,
            'author'     => $authorName,
            'post_keys'  => array_keys($_POST),
        ]);
        ErrorHandler::log('partage_submit', $e, ['slug' => $slug, 'author' => $authorName]);

        $_SESSION['_flash_error'] = ErrorHandler::userMessage($e);
        $_SESSION['_flash_contact'] = true;
        $_SESSION['form_data_share_' . $slug] = $_POST;
        storePrimedFiles($slug);
        $_SESSION[$shareCsrfKey] = bin2hex(random_bytes(32)); // Regenerate token

        // Redirect back to the form
        header('Location: /partage/' . urlencode($slug));
        exit();
    }
}

/**
 * Helper to retrieve old form data (with support for array keys via : delimiter)
 */
/**
 * Retrieve old form data for repopulation.
 * Returns raw value (no escaping) — callers must htmlspecialchars() when rendering.
 * For arrays, returns the array as-is so callers can iterate.
 */
function old(array $data, string $key, $default = '') {
    // Support nested keys like "jury_lecteurs:0"
    $parts = explode(':', $key);
    $value = $data;
    foreach ($parts as $part) {
        if (is_array($value) && array_key_exists($part, $value)) {
            $value = $value[$part];
        } else {
            return $default;
        }
    }
    return $value;
}

/**
 * Store names of uploaded files in session so they can be shown
 * to the user on form re-render after a validation error.
 *
 * $_FILES is not preserved across redirects, but the user should know
 * which files they need to re-select.
 */
function storePrimedFiles(string $slug): void
{
    $names = [];
    if (!empty($_FILES['couverture']['name'])) {
        $names[] = 'Couverture : ' . $_FILES['couverture']['name'];
    }
    if (!empty($_FILES['note_intention']['name'])) {
        $names[] = 'Note d\'intention : ' . $_FILES['note_intention']['name'];
    }
    if (!empty($_FILES['files']['name']) && is_array($_FILES['files']['name'])) {
        foreach ($_FILES['files']['name'] as $name) {
            if ($name !== '' && $name !== null) {
                $names[] = 'TFE : ' . $name;
            }
        }
    }
    if (!empty($_FILES['annexes']['name'])) {
        if (is_array($_FILES['annexes']['name'])) {
            foreach ($_FILES['annexes']['name'] as $name) {
                if ($name !== '' && $name !== null) {
                    $names[] = 'Annexe : ' . $name;
                }
            }
        } else {
            $names[] = 'Annexe : ' . $_FILES['annexes']['name'];
        }
    }
    if (!empty($_FILES['peertube_video']['name'])) {
        $names[] = 'Vidéo PeerTube : ' . $_FILES['peertube_video']['name'];
    }
    if (!empty($_FILES['peertube_audio']['name'])) {
        $names[] = 'Audio PeerTube : ' . $_FILES['peertube_audio']['name'];
    }
    if (!empty($names)) {
        $_SESSION['share_primed_files_' . $slug] = $names;
    }
}
