<?php
/**
 * GET /api/lab/descargar_orden.php?file=ruta_relativa_o_nombre
 * Sirve archivos de órdenes médicas con el Content-Type y nombre de archivo correctos.
 *
 * NO usa _helpers.php para evitar que ob_start() interfiera con readfile()
 * y que Content-Type:application/json se envíe antes del tipo real del archivo.
 */

// Sin buffering de salida — el archivo debe fluir directamente al navegador
if (ob_get_level()) ob_end_clean();

require_once __DIR__ . '/../../config/config.php';

// Seguridad: el usuario debe estar autenticado
if (!isUserLoggedIn()) {
    http_response_code(403);
    header('Content-Type: application/json');
    echo json_encode(['error' => 'No autorizado']);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
    http_response_code(405);
    exit;
}

$fileParam = trim($_GET['file'] ?? '');

// Rechazar rutas con traversal
if (!$fileParam || strpos($fileParam, '..') !== false) {
    http_response_code(400);
    header('Content-Type: application/json');
    echo json_encode(['error' => 'Parámetro inválido']);
    exit;
}

$projectRoot = realpath(__DIR__ . '/../../');
$uploadsBase = realpath($projectRoot . '/uploads');

// Resolver ruta física
if (preg_match('#^uploads/#', $fileParam)) {
    $path = realpath($projectRoot . '/' . $fileParam);
} elseif (preg_match('/^[a-zA-Z0-9_\-\.]+$/', $fileParam)) {
    $path = realpath($projectRoot . '/uploads/media/' . $fileParam);
} else {
    http_response_code(400);
    header('Content-Type: application/json');
    echo json_encode(['error' => 'Nombre de archivo inválido']);
    exit;
}

// Verificar que existe y está dentro de uploads/
if (!$path || !$uploadsBase || strpos($path, $uploadsBase) !== 0 || !is_file($path)) {
    http_response_code(404);
    header('Content-Type: application/json');
    echo json_encode(['error' => 'Archivo no encontrado']);
    exit;
}

// ── Detección MIME en 3 capas ─────────────────────────────────────────
$mime = '';

// Capa 1: finfo
if (function_exists('finfo_open')) {
    $fi   = finfo_open(FILEINFO_MIME_TYPE);
    $mime = $fi ? (string)finfo_file($fi, $path) : '';
    if ($fi) finfo_close($fi);
    // Quitar parámetros extras (ej: "image/jpeg; charset=binary")
    if ($mime && strpos($mime, ';') !== false) {
        $mime = trim(explode(';', $mime)[0]);
    }
}

// Capa 2: magic bytes manuales (más fiable que finfo para archivos renombrados como .bin)
if (!$mime || $mime === 'application/octet-stream') {
    $fh    = fopen($path, 'rb');
    $bytes = $fh ? fread($fh, 16) : '';
    if ($fh) fclose($fh);

    if (substr($bytes, 0, 3) === "\xFF\xD8\xFF") {
        $mime = 'image/jpeg';
    } elseif (substr($bytes, 0, 8) === "\x89PNG\r\n\x1a\n") {
        $mime = 'image/png';
    } elseif (substr($bytes, 0, 5) === '%PDF-') {
        $mime = 'application/pdf';
    } elseif (substr($bytes, 0, 6) === 'GIF89a' || substr($bytes, 0, 6) === 'GIF87a') {
        $mime = 'image/gif';
    } elseif (substr($bytes, 0, 4) === 'RIFF' && substr($bytes, 8, 4) === 'WEBP') {
        $mime = 'image/webp';
    } elseif (substr($bytes, 0, 4) === "\xD0\xCF\x11\xE0") {
        $mime = 'application/msword';   // DOC clásico
    } elseif (substr($bytes, 0, 2) === 'PK') {
        $mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; // DOCX/ZIP
    }
}

// Capa 3: fallback por extensión del nombre original
$ext = strtolower(pathinfo($fileParam, PATHINFO_EXTENSION));
if (!$mime || $mime === 'application/octet-stream') {
    $mimeByExt = [
        'pdf'  => 'application/pdf',
        'jpg'  => 'image/jpeg',
        'jpeg' => 'image/jpeg',
        'png'  => 'image/png',
        'gif'  => 'image/gif',
        'webp' => 'image/webp',
        'doc'  => 'application/msword',
        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    ];
    $mime = $mimeByExt[$ext] ?? 'application/octet-stream';
}

// ── Nombre de descarga: si era .bin, usar la extensión real ──────────
$extByMime = [
    'application/pdf'     => 'pdf',
    'image/jpeg'          => 'jpg',
    'image/png'           => 'png',
    'image/gif'           => 'gif',
    'image/webp'          => 'webp',
    'application/msword'  => 'doc',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
];
$basename     = basename($fileParam);
$downloadName = $basename;
if ($ext === 'bin' && isset($extByMime[$mime])) {
    $stem         = substr($basename, 0, strrpos($basename, '.'));
    $downloadName = $stem . '.' . $extByMime[$mime];
}

// ── Disposición: inline para imágenes/PDF, attachment para el resto ──
$inlineMimes  = ['application/pdf', 'image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$disposition  = in_array($mime, $inlineMimes, true) ? 'inline' : 'attachment';

// ── Enviar archivo ───────────────────────────────────────────────────
header('Content-Type: ' . $mime);
header('Content-Disposition: ' . $disposition . '; filename="' . addslashes($downloadName) . '"');
header('Content-Length: ' . filesize($path));
header('Cache-Control: private, max-age=3600');
header('X-Content-Type-Options: nosniff');

readfile($path);
exit;


$fileParam = $_GET['file'] ?? '';

// Rechazar inmediatamente rutas con ..
if (!$fileParam || strpos($fileParam, '..') !== false) {
    http_response_code(400);
    echo json_encode(['error' => 'Archivo inválido']);
    exit;
}

$projectRoot = realpath(__DIR__ . '/../../');
$uploadsBase = realpath($projectRoot . '/uploads');

// Resolver la ruta completa:
// - Si ya empieza con uploads/ → resolver desde raíz del proyecto
// - Si es solo un nombre de archivo → buscar en uploads/media/
if (preg_match('#^uploads/#', $fileParam)) {
    $path = realpath($projectRoot . '/' . $fileParam);
} else {
    // Solo nombre: solo aceptar alfanumérico + guiones/puntos, sin slashes
    if (!preg_match('/^[a-zA-Z0-9_\-\.]+$/', $fileParam)) {
        http_response_code(400);
        echo json_encode(['error' => 'Archivo inválido']);
        exit;
    }
    $path = realpath($projectRoot . '/uploads/media/' . $fileParam);
}

$base = $uploadsBase;

// Verificar que el archivo esté dentro del directorio permitido
if (!$path || !$base || strpos($path, $base) !== 0 || !is_file($path)) {
    http_response_code(404);
    echo json_encode(['error' => 'Archivo no encontrado']);
    exit;
}

// Detectar MIME real — 3 capas para máxima fiabilidad con archivos .bin

// Capa 1: finfo (usa magic bytes internamente)
$mime = '';
if (function_exists('finfo_open')) {
    $fi   = finfo_open(FILEINFO_MIME_TYPE);
    $mime = $fi ? (string)finfo_file($fi, $path) : '';
    if ($fi) finfo_close($fi);
}

// Capa 2: Lectura manual de magic bytes (funciona aunque finfo falle o devuelva octet-stream)
if (!$mime || $mime === 'application/octet-stream') {
    $handle = fopen($path, 'rb');
    $bytes  = $handle ? fread($handle, 12) : '';
    if ($handle) fclose($handle);

    if (substr($bytes, 0, 3) === "\xFF\xD8\xFF") {
        $mime = 'image/jpeg';
    } elseif (substr($bytes, 0, 8) === "\x89PNG\r\n\x1a\n") {
        $mime = 'image/png';
    } elseif (substr($bytes, 0, 5) === '%PDF-') {
        $mime = 'application/pdf';
    } elseif (substr($bytes, 0, 6) === 'GIF89a' || substr($bytes, 0, 6) === 'GIF87a') {
        $mime = 'image/gif';
    } elseif (substr($bytes, 0, 4) === 'RIFF' && substr($bytes, 8, 4) === 'WEBP') {
        $mime = 'image/webp';
    } elseif (substr($bytes, 0, 2) === 'PK') {
        $mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
    }
}

// Capa 3: Fallback por extensión declarada
$ext = strtolower(pathinfo($fileParam, PATHINFO_EXTENSION));
$mimeMap = [
    'pdf'  => 'application/pdf',
    'doc'  => 'application/msword',
    'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'jpg'  => 'image/jpeg',
    'jpeg' => 'image/jpeg',
    'png'  => 'image/png',
    'gif'  => 'image/gif',
    'webp' => 'image/webp',
];

if (!$mime || $mime === 'application/octet-stream') {
    $mime = $mimeMap[$ext] ?? 'application/octet-stream';
}

// Tipos que el navegador puede mostrar inline
$inlineTypes = ['application/pdf', 'image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$disposition = in_array($mime, $inlineTypes) ? 'inline' : 'attachment';

// Si el archivo fue guardado con extensión .bin, usar la correcta según MIME
$mimeToExt = [
    'application/pdf'  => 'pdf',
    'application/msword' => 'doc',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
    'image/jpeg' => 'jpg',
    'image/png'  => 'png',
    'image/gif'  => 'gif',
    'image/webp' => 'webp',
];
$downloadExt  = ($ext === 'bin' && isset($mimeToExt[$mime])) ? $mimeToExt[$mime] : $ext;
$downloadName = basename($fileParam);
if ($ext === 'bin' && isset($mimeToExt[$mime])) {
    $downloadName = substr($downloadName, 0, strrpos($downloadName, '.') + 1) . $downloadExt;
}

header('Content-Type: ' . $mime);
header('Content-Disposition: ' . $disposition . '; filename="' . rawurlencode($downloadName) . '"');
header('Content-Length: ' . filesize($path));
header('Cache-Control: private, max-age=3600');
header('X-Content-Type-Options: nosniff');

readfile($path);
exit;
