<?php
/**
 * Validate Access Token Endpoint
 *
 * Security model:
 *  - GET  → show a confirmation page (token in hidden form field, never in logs as a meaningful action)
 *  - POST → redeem the one-time token, create a long-lived HttpOnly session cookie, redirect
 *
 * Mitigations implemented:
 *  - Token is one-time use: marked used_at on first redemption
 *  - Token short-lived: 24h by default
 *  - Redemption via POST: avoids token appearing in server-side access logs as a GET action
 *  - CSRF token required on POST
 *  - Cookie: HttpOnly; Secure; SameSite=Strict; 30-day session
 *  - Audit trail: IP, User-Agent, timestamp logged on redemption
 */
require_once __DIR__ . '/../bootstrap.php';
require_once APP_ROOT . '/src/Database.php';

// ── Helpers ───────────────────────────────────────────────────────────────────

function renderError(int $code, string $title, string $body, int $thesisId = 0): never
{
    http_response_code($code);
    $backLink = $thesisId > 0
        ? '<a href="/tfe?id=' . $thesisId . '">Retour au TFE</a>'
        : '<a href="/">Retour à l\'accueil</a>';
    echo '<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>' . htmlspecialchars($title) . ' - XAMXAM</title>
    <style>
        body{font-family:system-ui,sans-serif;display:flex;justify-content:center;
             align-items:center;min-height:100vh;margin:0;background:#f5f5f5}
        .box{background:#fff;padding:40px;border-radius:8px;
             box-shadow:0 2px 10px rgba(0,0,0,.1);max-width:500px;width:90%}
        h1{color:#c53030;font-size:1.5rem;margin:0 0 1rem}
        p{color:#555;line-height:1.6;margin:.5rem 0}
        a{color:#2c5282}
    </style>
</head>
<body>
    <div class="box">
        <h1>' . htmlspecialchars($title) . '</h1>
        ' . $body . '
        <p>' . $backLink . '</p>
    </div>
</body>
</html>';
    exit;
}

// ── Route: GET — show confirmation page ──────────────────────────────────────

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $token    = isset($_GET['token']) ? trim($_GET['token']) : '';
    $thesisId = isset($_GET['thesis']) ? (int)$_GET['thesis'] : 0;

    if (empty($token) || $thesisId <= 0) {
        renderError(400, 'Lien invalide',
            '<p>Ce lien d\'accès est invalide ou incomplet.</p>', $thesisId);
    }

    // Generate (or reuse) CSRF token in session
    App::boot();
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }

    // Minimal pre-check: does the token exist and look valid?
    // (Full redemption + one-time mark only happens on POST)
    $db = Database::getInstance();
    $check = $db->getPDO()->prepare(
        "SELECT fat.expires_at, fr.thesis_id
         FROM file_access_tokens fat
         JOIN file_access_requests fr ON fat.request_id = fr.id
         WHERE fat.token = ?
           AND fat.is_valid = 1
           AND fat.used_at IS NULL
           AND fat.expires_at > CURRENT_TIMESTAMP
           AND fr.status = 'approved'
           AND fr.thesis_id = ?
         LIMIT 1"
    );
    $check->execute([$token, $thesisId]);
    $valid = $check->fetch();

    if (!$valid) {
        renderError(403, 'Lien d\'accès invalide ou expiré',
            '<p>Ce lien a déjà été utilisé ou a expiré. Veuillez soumettre une nouvelle demande.</p>',
            $thesisId);
    }

    $csrfToken = $_SESSION['csrf_token'];
    $safeToken = htmlspecialchars($token, ENT_QUOTES);
?>
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Activer l'accès - XAMXAM</title>
    <style>
        body{font-family:system-ui,sans-serif;display:flex;justify-content:center;
             align-items:center;min-height:100vh;margin:0;background:#f5f5f5}
        .box{background:#fff;padding:40px;border-radius:8px;
             box-shadow:0 2px 10px rgba(0,0,0,.1);max-width:500px;width:90%}
        h1{font-size:1.5rem;margin:0 0 1rem;color:#1a202c}
        p{color:#555;line-height:1.6;margin:.5rem 0}
        .btn{display:inline-block;margin-top:1.5rem;padding:12px 28px;
             background:#2c5282;color:#fff;border:none;border-radius:5px;
             font-size:1rem;cursor:pointer;text-decoration:none}
        .btn:hover{background:#2a4365}
        .note{font-size:.85rem;color:#888;margin-top:1rem}
    </style>
</head>
<body>
    <div class="box">
        <h1>Activer l'accès aux fichiers</h1>
        <p>Cliquez sur le bouton ci-dessous pour activer l'accès aux fichiers de ce TFE sur cet appareil.</p>
        <p class="note">L'accès sera valide pendant 30 jours sur cet appareil et navigateur.</p>

        <form method="POST" action="/validate-access">
            <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken, ENT_QUOTES) ?>">
            <input type="hidden" name="token"      value="<?= $safeToken ?>">
            <input type="hidden" name="thesis_id"  value="<?= (int)$thesisId ?>">
            <button type="submit" class="btn">Activer l'accès</button>
        </form>
    </div>
</body>
</html>
<?php
    exit;
}

// ── Route: POST — redeem token, set cookie, redirect ─────────────────────────

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    App::boot();

    // CSRF check
    if (
        empty($_POST['csrf_token'])
        || empty($_SESSION['csrf_token'])
        || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])
    ) {
        renderError(403, 'Erreur de sécurité',
            '<p>Token de sécurité invalide. Veuillez réessayer.</p>');
    }

    $token    = isset($_POST['token'])    ? trim($_POST['token'])    : '';
    $thesisId = isset($_POST['thesis_id']) ? (int)$_POST['thesis_id'] : 0;

    if (empty($token) || $thesisId <= 0) {
        renderError(400, 'Données invalides',
            '<p>Les données du formulaire sont invalides.</p>');
    }

    $db = Database::getInstance();

    // Redeem the one-time token (marks it used, logs audit trail)
    $ip = $_SERVER['REMOTE_ADDR'] ?? '';
    $ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 512);

    $redemption = $db->redeemAccessToken($token, $ip, $ua);

    if (!$redemption || $redemption['thesis_id'] !== $thesisId) {
        renderError(403, 'Lien invalide ou déjà utilisé',
            '<p>Ce lien d\'accès est invalide, a déjà été utilisé, ou ne correspond pas au TFE demandé.</p>
             <p>Si vous avez besoin d\'un nouvel accès, veuillez soumettre une nouvelle demande.</p>',
            $thesisId);
    }

    // Create a long-lived browser session (separate from the one-time email token)
    $sessionToken = $db->createAccessSession($redemption['request_id'], 30);

    // Set HttpOnly, Secure, SameSite=Strict cookie (long-lived session)
    $cookieName   = 'tfe_access_' . $thesisId;
    $cookieSecure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';

    setcookie($cookieName, $sessionToken, [
        'expires'  => time() + 30 * 86400,
        'path'     => '/',
        'domain'   => '',
        'secure'   => $cookieSecure,
        'httponly' => true,
        'samesite' => 'Strict',
    ]);

    // Rotate CSRF token after successful action
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));

    // Redirect to TFE page (no token in URL)
    header('Location: /tfe?id=' . $thesisId);
    exit;
}

// ── Any other method ──────────────────────────────────────────────────────────
http_response_code(405);
header('Allow: GET, POST');
echo 'Méthode non autorisée';
exit;
