<?php
/**
 * Request Access Endpoint
 *
 * Handles file access requests for restricted TFEs.
 * - Validates CSRF token
 * - Rate limiting (per IP)
 * - Auto-approves @erg.school and @erg.be emails (sends 24h one-time link)
 * - Creates pending requests for external emails (admin approval)
 * - Sends notification emails via SMTP
 *
 * Security:
 *  - CSRF required (POST only)
 *  - Rate limit: 3 requests per 10 min per IP
 *  - Token sent in email body only (never in URL query as a direct action)
 *  - Token is short-lived (24h) and one-time use
 *  - Redemption link goes to GET /validate-access (confirmation page) then POST to redeem
 */
require_once __DIR__ . '/../bootstrap.php';
require_once APP_ROOT . '/src/Database.php';
require_once APP_ROOT . '/src/RateLimit.php';
require_once APP_ROOT . '/src/SmtpRelay.php';
// SmtpSendException is defined in SmtpRelay.php

header('Content-Type: application/json');

// Only accept POST requests
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['success' => false, 'message' => 'Méthode non autorisée']);
    exit;
}

// Boot session for CSRF
App::boot();

// Validate CSRF token
if (
    empty($_POST['csrf_token'])
    || empty($_SESSION['csrf_token'])
    || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])
) {
    http_response_code(403);
    echo json_encode(['success' => false, 'message' => 'Token de sécurité invalide']);
    exit;
}

// Validate input
$thesisId      = isset($_POST['thesis_id'])    ? (int)$_POST['thesis_id']            : 0;
$email         = isset($_POST['email'])         ? trim($_POST['email'])                : '';
$justification = isset($_POST['justification']) ? trim($_POST['justification'])        : '';

if ($thesisId <= 0 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Données invalides']);
    exit;
}

// Truncate justification to a safe length
if (strlen($justification) > 2000) {
    $justification = substr($justification, 0, 2000);
}

$db = Database::getInstance();

// Check if thesis exists and is published
$thesis = $db->getThesis($thesisId);
if (!$thesis || !$thesis['is_published']) {
    http_response_code(404);
    echo json_encode(['success' => false, 'message' => 'TFE non trouvé']);
    exit;
}

// Check if restricted files feature is enabled
if (!$db->isRestrictedFilesEnabled()) {
    http_response_code(403);
    echo json_encode(['success' => false, 'message' => 'Cette fonctionnalité est désactivée']);
    exit;
}

// Check if thesis actually has restricted access (access_type_id = 2)
$accessTypeId = $db->getThesisAccessTypeId($thesisId);
if ($accessTypeId !== 2) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Ce TFE ne nécessite pas d\'accès restreint']);
    exit;
}

// Rate limiting: max 3 requests per 10 minutes per IP
$rateLimitKey = 'access_request_' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
if (!(new RateLimit(30, 600))->checkKey($rateLimitKey)) {
    http_response_code(429);
    echo json_encode(['success' => false, 'message' => 'Trop de requêtes. Veuillez réessayer dans quelques minutes.']);
    exit;
}

// Check for existing request
$existingRequest = $db->getExistingAccessRequest($thesisId, $email);
if ($existingRequest) {
    if ($existingRequest['status'] === 'approved') {
        // Re-generate and re-send a fresh 24h token
        try {
            $newToken  = $db->generateAccessToken((int)$existingRequest['id'], 24);
            $host      = $_SERVER['HTTP_HOST'] ?? 'xamxam.erg.be';
            $accessUrl = "https://{$host}/validate-access?token={$newToken}&thesis={$thesisId}";

            $subject = "Accès (renvoi) - TFE : " . $thesis['title'];
            $body    = buildAutoApprovalEmail($thesis['title'], $thesis['authors'] ?? '', $accessUrl);
            $plain   = htmlToPlain($body);

            SmtpRelay::send($db, $email, $subject, $body, $plain);

            echo json_encode([
                'success' => true,
                'message' => 'Un nouvel email d\'accès vous a été envoyé.',
                'status'  => 'resent',
            ]);
        } catch (SmtpSendException $e) {
            error_log('Access request resend failed: ' . $e->getMessage());
            if ($e->isRecipientRejected()) {
                http_response_code(422);
                echo json_encode([
                    'success' => false,
                    'message' => "L'adresse e-mail « {$email} » est introuvable sur le serveur de messagerie de l'ERG. Vérifiez l'orthographe ou utilisez une autre adresse.",
                    'status'  => 'recipient_rejected',
                ]);
            } else {
                echo json_encode(['success' => true, 'message' => 'Votre accès est déjà approuvé. Si vous n\'avez pas reçu l\'email, contactez l\'administrateur.']);
            }
        } catch (Exception $e) {
            error_log('Access request resend failed: ' . $e->getMessage());
            echo json_encode(['success' => true, 'message' => 'Votre accès est déjà approuvé. Si vous n\'avez pas reçu l\'email, contactez l\'administrateur.']);
        }
        exit;
    }

    if ($existingRequest['status'] === 'pending') {
        http_response_code(400);
        echo json_encode([
            'success' => false,
            'message' => 'Une demande est déjà en cours de traitement pour cet email.',
            'status'  => 'already_pending',
        ]);
        exit;
    }
}

// Determine if auto-approved (ERG domain)
$emailLower = strtolower($email);
$isErgEmail = (
    str_ends_with($emailLower, '@erg.school') ||
    str_ends_with($emailLower, '@erg.be')
);

$host = $_SERVER['HTTP_HOST'] ?? 'xamxam.erg.be';

try {
    if ($isErgEmail) {
        // Auto-approve: create request + short-lived 24h token
        $requestId = $db->createFileAccessRequest($thesisId, $email, null);
        $token     = $db->approveAccessRequest($requestId, null, 24);

        $accessUrl = "https://{$host}/validate-access?token={$token}&thesis={$thesisId}";
        $subject   = "Accès accordé - TFE : " . $thesis['title'];
        $body      = buildAutoApprovalEmail($thesis['title'], $thesis['authors'] ?? '', $accessUrl);
        $plain     = htmlToPlain($body);

        try {
            SmtpRelay::send($db, $email, $subject, $body, $plain);
        } catch (SmtpSendException $e) {
            if ($e->isRecipientRejected()) {
                // SMTP server does not know this address — roll back the approval
                // so the user can retry with a valid address.
                $db->getPDO()->exec(
                    "DELETE FROM file_access_tokens WHERE request_id = {$requestId}"
                );
                $db->getPDO()->exec(
                    "UPDATE file_access_requests
                     SET status = 'rejected', admin_notes = 'Adresse e-mail inconnue du serveur de messagerie (550)'
                     WHERE id = {$requestId}"
                );
                http_response_code(422);
                echo json_encode([
                    'success' => false,
                    'message' => "L'adresse e-mail « {$email} » est introuvable sur le serveur de messagerie de l'ERG. Vérifiez l'orthographe ou utilisez une autre adresse.",
                    'status'  => 'recipient_rejected',
                ]);
                exit;
            }
            // Transient send failure — access is approved, email may arrive later
            error_log("[request-access] Email delivery failed for approved request #{$requestId}: " . $e->getMessage());
        }

        http_response_code(200);
        echo json_encode([
            'success' => true,
            'message' => 'Un email avec le lien d\'accès vous a été envoyé. Le lien est valable 24 heures.',
            'status'  => 'auto_approved',
        ]);

    } else {
        // External email: justification required, create pending request
        if (empty($justification)) {
            http_response_code(400);
            echo json_encode([
                'success' => false,
                'message' => 'Une justification est requise pour les emails externes à l\'ERG.',
                'status'  => 'justification_required',
            ]);
            exit;
        }

        $requestId = $db->createFileAccessRequest($thesisId, $email, $justification);

        // Notify admins
        $thesisYear = $thesis['year'] ?? '';
        $subject    = "Nouvelle demande d'accès - TFE : " . $thesis['title'];
        $body       = buildAdminNotificationEmail(
            $thesis['title'],
            $thesis['authors'] ?? '',
            $thesisYear,
            $email,
            $justification,
            $host
        );
        $plain = htmlToPlain($body);

        $notifyEmail = SmtpRelay::getNotifyEmail($db);
        if ($notifyEmail !== '') {
            SmtpRelay::send($db, $notifyEmail, $subject, $body, $plain);
        }

        http_response_code(200);
        echo json_encode([
            'success' => true,
            'message' => 'Votre demande a été envoyée et sera examinée par un administrateur.',
            'status'  => 'pending',
        ]);
    }

} catch (SmtpSendException $e) {
    error_log('Access request SMTP failure: ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'Erreur lors de l\'envoi de l\'email. Veuillez réessayer.']);
} catch (Exception $e) {
    error_log('Access request failed: ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'Erreur lors du traitement de la demande']);
}

// ─────────────────────────────────────────────────────────────────────────────
// Email template helpers
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Build the auto-approval email sent to ERG-domain users.
 * The link leads to a confirmation page (GET) that then requires a POST to redeem.
 */
function buildAutoApprovalEmail(string $title, string $authors, string $accessUrl): string
{
    $safeTitle   = htmlspecialchars($title,   ENT_QUOTES);
    $safeAuthors = htmlspecialchars($authors, ENT_QUOTES);
    $safeUrl     = htmlspecialchars($accessUrl, ENT_QUOTES);

    return <<<HTML
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="font-family:system-ui,Arial,sans-serif;line-height:1.6;color:#333">
  <div style="max-width:600px;margin:0 auto;padding:20px">
    <h2 style="color:#2c5282">Accès accordé au TFE</h2>

    <p>Bonjour,</p>
    <p>Votre demande d'accès au TFE suivant a été automatiquement approuvée :</p>

    <div style="background:#f7fafc;padding:15px;border-left:4px solid #2c5282;margin:20px 0">
      <strong>Titre :</strong> {$safeTitle}<br>
      <strong>Auteur(s) :</strong> {$safeAuthors}
    </div>

    <p>Cliquez sur le bouton ci-dessous pour activer l'accès aux fichiers de ce TFE :</p>

    <div style="text-align:center;margin:30px 0">
      <a href="{$safeUrl}"
         style="display:inline-block;padding:12px 30px;background-color:#2c5282;
                color:#fff;text-decoration:none;border-radius:5px;font-weight:bold">
        Activer l'accès au TFE
      </a>
    </div>

    <p><strong>Ce lien est valable 24 heures et à usage unique.</strong>
       L'accès sur votre appareil sera ensuite conservé 30 jours.</p>

    <p style="margin-top:30px;color:#666;font-size:.9em">
      Cordialement,<br>L'équipe XAMXAM – ERG
    </p>
  </div>
</body>
</html>
HTML;
}

/**
 * Build the admin notification email for external (non-ERG) access requests.
 */
function buildAdminNotificationEmail(
    string $title,
    string $authors,
    string $year,
    string $email,
    string $justification,
    string $host
): string {
    $safeTitle         = htmlspecialchars($title,         ENT_QUOTES);
    $safeAuthors       = htmlspecialchars($authors,       ENT_QUOTES);
    $safeYear          = htmlspecialchars($year,          ENT_QUOTES);
    $safeEmail         = htmlspecialchars($email,         ENT_QUOTES);
    $safeJustification = nl2br(htmlspecialchars($justification, ENT_QUOTES));
    $adminUrl          = htmlspecialchars("https://{$host}/admin/file-access.php", ENT_QUOTES);

    return <<<HTML
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="font-family:system-ui,Arial,sans-serif;line-height:1.6;color:#333">
  <div style="max-width:600px;margin:0 auto;padding:20px">
    <h2 style="color:#c53030">Nouvelle demande d'accès</h2>

    <p>Une nouvelle demande d'accès a été soumise :</p>

    <div style="background:#fff5f5;padding:15px;border-left:4px solid #c53030;margin:20px 0">
      <strong>TFE :</strong> {$safeTitle}<br>
      <strong>Auteur(s) :</strong> {$safeAuthors}<br>
      <strong>Année :</strong> {$safeYear}
    </div>

    <div style="background:#f7fafc;padding:15px;margin:20px 0">
      <strong>Email du demandeur :</strong> {$safeEmail}<br><br>
      <strong>Justification :</strong><br>
      {$safeJustification}
    </div>

    <div style="margin:30px 0;text-align:center">
      <a href="{$adminUrl}"
         style="display:inline-block;padding:12px 30px;background-color:#2c5282;
                color:#fff;text-decoration:none;border-radius:5px;font-weight:bold">
        Gérer les demandes d'accès
      </a>
    </div>

    <p style="color:#666;font-size:.9em">
      Connectez-vous au panneau d'administration pour approuver ou rejeter cette demande.
    </p>
  </div>
</body>
</html>
HTML;
}

/**
 * Convert HTML to plain text for the email text/plain part.
 */
function htmlToPlain(string $html): string
{
    $text = strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $html));
    $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    $text = preg_replace('/\n{3,}/', "\n\n", $text);
    return trim($text);
}
