<?php
/**
 * img.php — SUBSPACE Image Proxy
 *
 * All images are served through this file, never directly from the filesystem.
 *
 * Two access paths:
 * 1. Authenticated: GET ?id={media_id} with Authorization: Bearer JWT
 * 2. Public signed: GET /subspace_2026/img/p/{slug}-{signature}.{ext}
 *    (rewritten by Apache to ?slug=...&sig=...&ext=...)
 */

require_once __DIR__ . '/../citadel_2026/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// --- Config ---
$db_host = 'localhost';
$db_name = getenv('SUBSPACE_DB_NAME') ?: 'subspace_2026';
$db_user = getenv('SUBSPACE_DB_USER') ?: 'data';
$db_pass = getenv('SUBSPACE_DB_PASS') ?: 'ncc1701D';
$jwt_secret = getenv('CITADEL_2025_JWT_SECRET') ?: 'bXlzZWN1cmVzdHJpbmcxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMw==';
$hmac_secret = trim(file_get_contents('/var/www/storage/subspace/.hmac-secret'));

try {
    $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
} catch (PDOException $e) {
    http_response_code(500);
    exit;
}

/**
 * Serve a file with optional Range request support (required for video playback).
 */
function serveFile(string $path, string $mimeType, string $cacheControl): void {
    $size = filesize($path);
    $isVideo = str_starts_with($mimeType, 'video/');

    header('Content-Type: ' . $mimeType);
    header('Cache-Control: ' . $cacheControl);
    header('X-Content-Type-Options: nosniff');

    if ($isVideo) {
        header('Accept-Ranges: bytes');

        if (isset($_SERVER['HTTP_RANGE'])) {
            // Parse Range header: "bytes=start-end"
            if (preg_match('/bytes=(\d*)-(\d*)/', $_SERVER['HTTP_RANGE'], $m)) {
                $start = $m[1] !== '' ? (int)$m[1] : 0;
                $end = $m[2] !== '' ? (int)$m[2] : $size - 1;

                if ($start > $end || $start >= $size) {
                    http_response_code(416);
                    header("Content-Range: bytes */$size");
                    exit;
                }
                $end = min($end, $size - 1);
                $length = $end - $start + 1;

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

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

        // No Range header — serve full file with Content-Length
        header('Content-Length: ' . $size);
    }

    readfile($path);
    exit;
}

// --- Path 2: Public signed URL ---
if (isset($_GET['slug'], $_GET['sig'])) {
    $slug = $_GET['slug'];
    $sig = $_GET['sig'];

    $stmt = $pdo->prepare('SELECT id, site_id, uuid, mime_type, storage_path, signature, visibility FROM media WHERE slug = ?');
    $stmt->execute([$slug]);
    $media = $stmt->fetch();

    if (!$media || $media['signature'] !== $sig) {
        http_response_code(403);
        exit;
    }
    if ($media['visibility'] !== 'public') {
        http_response_code(403);
        exit;
    }
    if (!file_exists($media['storage_path'])) {
        http_response_code(404);
        exit;
    }

    serveFile($media['storage_path'], $media['mime_type'], 'public, max-age=86400');
}

// --- Path 1: Authenticated access ---
if (isset($_GET['id'])) {
    $auth = $_SERVER['HTTP_AUTHORIZATION'] ?? apache_request_headers()['Authorization'] ?? '';
    if (!preg_match('/Bearer\s(\S+)/', $auth, $m)) {
        http_response_code(401);
        echo json_encode(['error' => 'Authentication required']);
        exit;
    }
    try {
        $payload = JWT::decode($m[1], new Key($jwt_secret, 'HS256'));
    } catch (\Exception $e) {
        http_response_code(401);
        echo json_encode(['error' => 'Invalid token']);
        exit;
    }

    $user_id = (string)($payload->user_id ?? $payload->sub ?? '0');
    $role = $payload->role ?? '';
    $is_admin = ($role === 'super_admin') ||
        (isset($payload->perm) && is_array($payload->perm) && in_array('inkwell:settings:manage', $payload->perm, true));

    $stmt = $pdo->prepare('SELECT id, uuid, mime_type, storage_path, uploaded_by, visibility FROM media WHERE id = ?');
    $stmt->execute([(int)$_GET['id']]);
    $media = $stmt->fetch();

    if (!$media) {
        http_response_code(404);
        echo json_encode(['error' => 'Media not found']);
        exit;
    }

    // Access control
    if ($media['visibility'] === 'private' && !$is_admin && $media['uploaded_by'] !== $user_id) {
        http_response_code(403);
        echo json_encode(['error' => 'Access denied']);
        exit;
    }

    if (!file_exists($media['storage_path'])) {
        http_response_code(404);
        exit;
    }

    serveFile($media['storage_path'], $media['mime_type'], 'private, max-age=3600');
}

http_response_code(400);
echo json_encode(['error' => 'id or signed URL parameters required']);
