<?php
declare(strict_types=1);

/**
 * /messages/file.php
 * Видача вкладення приватних повідомлень:
 * - перевіряє, що поточний користувач є учасником розмови
 * - віддає файл inline або як download (?dl=1)
 * - SEO: завжди NOINDEX (приватні вкладення)
 *
 * БЕЗПЕКА (посилено):
 * - жорстка перевірка realpath
 * - дозволений корінь тільки /upload/messages/
 * - inline лише для безпечних MIME
 */

require_once __DIR__ . '/../includes/start.php';

$pdo = db();
$me  = current_user();
require_login();

if (!function_exists('pmf_norm_path')) {
    function pmf_norm_path(string $path): string
    {
        $path = str_replace('\\', '/', $path);
        $path = preg_replace('~/+~', '/', $path);
        return rtrim((string)$path, '/');
    }
}

if (!function_exists('pmf_starts_with')) {
    function pmf_starts_with(string $haystack, string $needle): bool
    {
        if ($needle === '') return true;
        return strncmp($haystack, $needle, strlen($needle)) === 0;
    }
}

if (!function_exists('pmf_abs_file')) {
    function pmf_abs_file(string $relPath): ?string
    {
        $relPath = trim($relPath);
        if ($relPath === '' || str_contains($relPath, "\0")) {
            return null;
        }

        $relPath = ltrim(str_replace('\\', '/', $relPath), '/');
        if (!preg_match('~^upload/messages/~i', $relPath)) {
            return null;
        }

        $projectRoot = realpath(__DIR__ . '/..');
        if (!$projectRoot) {
            return null;
        }
        $projectRoot = pmf_norm_path((string)$projectRoot);

        $messagesRoot = realpath($projectRoot . '/upload/messages');
        if (!$messagesRoot) {
            return null;
        }
        $messagesRoot = pmf_norm_path((string)$messagesRoot);

        $full = $projectRoot . '/' . $relPath;
        $real = realpath($full);
        if (!$real || !is_file($real)) {
            return null;
        }

        $realNorm = pmf_norm_path((string)$real);
        if ($realNorm !== $messagesRoot && !pmf_starts_with($realNorm, $messagesRoot . '/')) {
            return null;
        }

        return $real;
    }
}

if (!function_exists('pmf_inline_mime_allowed')) {
    function pmf_inline_mime_allowed(string $mime): bool
    {
        $mime = strtolower(trim($mime));
        if ($mime === '') return false;

        return in_array($mime, [
            'image/jpeg',
            'image/png',
            'image/gif',
            'image/webp',
            'audio/mpeg',
            'audio/mp3',
            'audio/ogg',
            'audio/wav',
            'audio/x-wav',
            'audio/webm',
            'video/mp4',
            'video/webm',
            'video/ogg',
        ], true);
    }
}

/* SEO / robots */
if (!headers_sent()) {
    header('X-Robots-Tag: noindex, nofollow', true);
    header('Referrer-Policy: same-origin', true);
    header('X-Content-Type-Options: nosniff', true);
    header('X-Frame-Options: SAMEORIGIN', true);
    header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0', true);
    header('Pragma: no-cache', true);
    header('Expires: 0', true);
}

$id = (int)($_GET['id'] ?? 0);
$dl = (int)($_GET['dl'] ?? 0);

if ($id <= 0) {
    http_response_code(400);
    echo 'Bad request';
    exit;
}

$st = $pdo->prepare("
  SELECT
    a.*,
    m.thread_id,
    t.user1_id,
    t.user2_id
  FROM message_attachments a
  JOIN message_messages m ON m.id = a.message_id
  JOIN message_threads  t ON t.id = m.thread_id
  WHERE a.id = ?
  LIMIT 1
");
$st->execute([$id]);
$row = $st->fetch(PDO::FETCH_ASSOC);

if (!$row) {
    http_response_code(404);
    echo 'Not found';
    exit;
}

$meId = (int)($me['id'] ?? 0);
if ((int)$row['user1_id'] !== $meId && (int)$row['user2_id'] !== $meId) {
    http_response_code(403);
    echo 'Forbidden';
    exit;
}

$abs = pmf_abs_file((string)($row['rel_path'] ?? ''));
if ($abs === null) {
    http_response_code(404);
    echo 'File missing';
    exit;
}

$mime = strtolower(trim((string)($row['mime'] ?? '')));
if ($mime === '' && function_exists('finfo_open')) {
    $f = finfo_open(FILEINFO_MIME_TYPE);
    if ($f) {
        $mime = strtolower(trim((string)(finfo_file($f, $abs) ?: 'application/octet-stream')));
        finfo_close($f);
    }
}
if ($mime === '') {
    $mime = 'application/octet-stream';
}

$orig = (string)($row['original_name'] ?? 'file');
$size = (int)($row['size_bytes'] ?? 0);
if ($size <= 0) {
    $size = (int)filesize($abs);
}

$disp = ($dl === 1 || !pmf_inline_mime_allowed($mime)) ? 'attachment' : 'inline';

$origSafe = preg_replace('/[\x00-\x1F\x7F"]/u', '', $orig);
$origSafe = str_replace(["\\", '/', "\r", "\n", "\t"], '_', (string)$origSafe);
$origSafe = trim((string)$origSafe);
if ($origSafe === '') {
    $origSafe = 'file';
}

$encoded = rawurlencode($origSafe);

header('Content-Type: ' . $mime);
header('Content-Length: ' . $size);
header('Content-Disposition: ' . $disp . '; filename="' . $origSafe . '"; filename*=UTF-8\'\'' . $encoded);

$fp = fopen($abs, 'rb');
if ($fp === false) {
    http_response_code(500);
    echo 'Cannot open file';
    exit;
}

fpassthru($fp);
fclose($fp);
exit;
