<?php
/**
 * media_upload.php — Authenticated media upload endpoint
 * ─────────────────────────────────────────────────────────────────────────────
 * Called by post.php via multipart/form-data POST.
 * Returns JSON: { ok: true, url, filename, type, mime }
 *
 * Auth: same X-API-Key header / ?api_key= param as api.php.
 *
 * Place this file alongside api.php and post.php (webroot).
 * Files are stored in /media/ (absolute server path configured below).
 */

// ══════════════════════════════════════════════════════════════════════════════
// CONFIG
// ══════════════════════════════════════════════════════════════════════════════

// Absolute server path where uploads are saved.
// Must be writable by the web server (chmod 755 or 775).
define('UPLOAD_DIR',      $_SERVER['DOCUMENT_ROOT'] . '/media/');

// Public URL prefix for uploaded files (no trailing slash).
define('UPLOAD_URL',      '/media');

// Same key file used by api.php.
define('UPLOAD_KEY_FILE', __DIR__ . '/index_config/api_keys.txt');

// Max upload size in bytes (default 200 MB).
define('UPLOAD_MAX_BYTES', 200 * 1024 * 1024);

// Allowed MIME types → media type label.
define('UPLOAD_ALLOWED', serialize([
    'image/jpeg'      => 'image',
    'image/jpg'       => 'image',
    'image/png'       => 'image',
    'image/gif'       => 'image',
    'image/webp'      => 'image',
    'image/avif'      => 'image',
    'image/svg+xml'   => 'image',
    'video/mp4'       => 'video',
    'video/quicktime' => 'video',   // .mov
    'video/webm'      => 'video',
    'video/ogg'       => 'video',
    'video/x-msvideo' => 'video',   // .avi
    'video/x-matroska'=> 'video',   // .mkv
]));

// ══════════════════════════════════════════════════════════════════════════════

header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');

function upload_ok(array $data): never {
    echo json_encode(['ok' => true] + $data, JSON_UNESCAPED_SLASHES);
    exit;
}
function upload_err(string $msg, int $code = 400): never {
    http_response_code($code);
    echo json_encode(['ok' => false, 'error' => $msg]);
    exit;
}

// ── Auth ──────────────────────────────────────────────────────────────────────
if (!file_exists(UPLOAD_KEY_FILE)) upload_err('API key file not configured.', 503);

$supplied = trim(
    $_SERVER['HTTP_X_API_KEY'] ?? $_SERVER['HTTP_X_Api_Key'] ?? ($_GET['api_key'] ?? '')
);
if ($supplied === '') upload_err('Missing API key.', 401);

$valid_keys = array_filter(
    array_map('trim', file(UPLOAD_KEY_FILE)),
    fn($l) => $l !== '' && !str_starts_with($l, '#')
);
$authed = false;
foreach ($valid_keys as $k) { if (hash_equals($k, $supplied)) { $authed = true; break; } }
if (!$authed) upload_err('Invalid API key.', 403);

// ── Request validation ────────────────────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] !== 'POST') upload_err('POST required.', 405);
if (empty($_FILES['file'])) upload_err('No file received.');

$file  = $_FILES['file'];
$error = $file['error'] ?? UPLOAD_ERR_NO_FILE;

if ($error === UPLOAD_ERR_INI_SIZE || $error === UPLOAD_ERR_FORM_SIZE)
    upload_err('File exceeds size limit.');
if ($error !== UPLOAD_ERR_OK)
    upload_err('Upload error code: ' . $error);

if ($file['size'] > UPLOAD_MAX_BYTES)
    upload_err('File too large (max ' . round(UPLOAD_MAX_BYTES / 1048576) . ' MB).');

// ── MIME detection (finfo, not extension trust) ───────────────────────────────
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($file['tmp_name']);

$allowed = unserialize(UPLOAD_ALLOWED);
if (!isset($allowed[$mime])) {
    upload_err('File type not allowed: ' . $mime . '. Allowed: JPEG, PNG, GIF, WEBP, AVIF, SVG, MP4, MOV, WEBM, OGG, AVI, MKV.');
}
$media_type = $allowed[$mime];

// ── Generate unique filename preserving original extension ────────────────────
$orig_ext  = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
// Normalise common aliases
$ext_map   = ['jpg' => 'jpg', 'jpeg' => 'jpg', 'jpe' => 'jpg',
               'png' => 'png', 'gif' => 'gif', 'webp' => 'webp',
               'avif' => 'avif', 'svg' => 'svg',
               'mp4' => 'mp4', 'mov' => 'mov', 'webm' => 'webm',
               'ogg' => 'ogg', 'ogv' => 'ogg', 'avi' => 'avi', 'mkv' => 'mkv'];
$safe_ext  = $ext_map[$orig_ext] ?? $orig_ext;
$filename  = bin2hex(random_bytes(12)) . '.' . $safe_ext;
$dest      = UPLOAD_DIR . $filename;

// ── Create upload directory if it doesn't exist ───────────────────────────────
if (!is_dir(UPLOAD_DIR)) {
    if (!mkdir(UPLOAD_DIR, 0755, true)) {
        upload_err('Cannot create upload directory.', 500);
    }
    // Drop an index.html to prevent directory listing
    file_put_contents(UPLOAD_DIR . 'index.html', '');
}

// ── Move file ─────────────────────────────────────────────────────────────────
if (!move_uploaded_file($file['tmp_name'], $dest)) {
    upload_err('Failed to save file.', 500);
}

// ── Respond ───────────────────────────────────────────────────────────────────
upload_ok([
    'url'      => UPLOAD_URL . '/' . $filename,
    'filename' => $filename,
    'type'     => $media_type,   // 'image' | 'video'
    'mime'     => $mime,
    'size'     => $file['size'],
]);
