<?php
/**
 * serve_file.php - Secure file serving for SaniBook media
 * 
 * Streams files from the secure upload directory (outside webroot).
 * Usage: serve_file.php?id=<media_id>&download=1 (optional download flag)
 * 
 * Access Control:
 *  - Admins: can access any file
 *  - Submission owner: can access their own files
 *  - Public: can only access files from verified submissions
 * 
 * Rules:
 *  - PDF: viewable inline + downloadable (with &download=1)
 *  - Video/Audio: inline only, no download
 *  - Image: inline only
 */

session_start();
include 'config.php';

// Validate input
$media_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$force_download = isset($_GET['download']) && $_GET['download'] == '1';

if ($media_id <= 0) {
    http_response_code(400);
    echo 'Invalid media ID.';
    exit;
}

// Fetch media record WITH submission verification status
$stmt = $conn->prepare("
    SELECT m.id, m.file_path, m.mime_type, m.media_type, m.original_filename, m.title, m.submission_id,
           s.is_verified, s.user_id AS submission_owner_id, s.status AS submission_status
    FROM media_uploads m
    LEFT JOIN submissions s ON m.submission_id = s.id
    WHERE m.id = ?
");
$stmt->bind_param("i", $media_id);
$stmt->execute();
$media = $stmt->get_result()->fetch_assoc();

if (!$media || empty($media['file_path'])) {
    http_response_code(404);
    echo 'File not found.';
    exit;
}

// --- ACCESS CONTROL ---
$is_admin = (($_SESSION['user_role'] ?? '') === 'admin' && ($_SESSION['admin_logged_in'] ?? false) === true);
$is_owner = (isset($_SESSION['user_id']) && intval($_SESSION['user_id']) === intval($media['submission_owner_id'] ?? 0));
$is_verified = (intval($media['is_verified'] ?? 0) === 1);

if (!$is_admin && !$is_owner && !$is_verified) {
    http_response_code(403);
    echo 'Access denied. This file belongs to an unverified submission.';
    exit;
}

// Resolve file path
$file_path = $media['file_path'];

// If path doesn't start with / or a drive letter, prepend SECURE_UPLOAD_PATH
if (!preg_match('#^(/|[A-Za-z]:\\\\)#', $file_path)) {
    $file_path = SECURE_UPLOAD_PATH . $file_path;
}

// Prevent path traversal
$real_path = realpath($file_path);
if ($real_path === false) {
    http_response_code(404);
    echo 'File not found on disk.';
    exit;
}

// Determine MIME type
$mime = $media['mime_type'] ?: mime_content_type($real_path);
$media_type = $media['media_type'];
$filename = $media['original_filename'] ?: ($media['title'] ?: basename($real_path));

// Enforce download rules — only PDFs can be downloaded
if ($force_download && $media_type !== 'pdf') {
    $force_download = false;
}

// Sanitize filename for Content-Disposition header
$safe_filename = preg_replace('/[^\w\s\-\.\(\)]/', '_', $filename);

// Set headers
header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($real_path));
header('Accept-Ranges: bytes');
header('X-Content-Type-Options: nosniff');

if ($force_download) {
    header('Content-Disposition: attachment; filename="' . $safe_filename . '"');
} else {
    header('Content-Disposition: inline; filename="' . $safe_filename . '"');
}

// Prevent caching of sensitive files
header('Cache-Control: private, max-age=3600');
header('Pragma: public');

// Support range requests for video/audio streaming
if (isset($_SERVER['HTTP_RANGE']) && in_array($media_type, ['video', 'audio'])) {
    $size = filesize($real_path);
    $start = 0;
    $end = $size - 1;

    if (preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $matches)) {
        $start = intval($matches[1]);
        if (!empty($matches[2])) {
            $end = min(intval($matches[2]), $size - 1);
        }
    }

    // Validate range
    if ($start > $end || $start >= $size) {
        http_response_code(416);
        header("Content-Range: bytes */$size");
        exit;
    }

    $length = $end - $start + 1;
    http_response_code(206);
    header("Content-Range: bytes $start-$end/$size");
    header("Content-Length: $length");

    $fp = fopen($real_path, 'rb');
    fseek($fp, $start);
    $remaining = $length;
    $chunk_size = 8192;
    while ($remaining > 0 && !feof($fp)) {
        $read = min($chunk_size, $remaining);
        echo fread($fp, $read);
        $remaining -= $read;
        flush();
    }
    fclose($fp);
    exit;
}

// Stream the file
readfile($real_path);
exit;
?>