<?php
setlocale(LC_CTYPE, "pl_PL.UTF-8", "en_US.UTF-8", "C.UTF-8");
require_once 'functions.php';

function subtitleError($message, $status = 400) {
    http_response_code($status);
    header('Content-Type: text/plain; charset=UTF-8');
    header('Cache-Control: no-store');
    echo $message;
    exit;
}

function serveSubtitleFile($file, $offset = 0) {
    if (!is_file($file)) subtitleError('Napisy nie są dostępne.', 404);
    @touch($file);
    header('Content-Type: text/vtt; charset=UTF-8');
    header('Content-Disposition: inline');
    header('Content-Length: ' . filesize($file));
    header('Cache-Control: private, max-age=86400');
    header('X-Subtitle-Offset: ' . number_format((float)$offset, 3, '.', ''));
    header('X-Content-Type-Options: nosniff');
    readfile($file);
    exit;
}

$shareHash = $_GET['h'] ?? '';
$isPublicShare = false;

if ($shareHash !== '') {
    if (!preg_match('/^(?:[a-f0-9]{12}|[a-f0-9]{32})$/', $shareHash)) subtitleError('Błędny lub wygasły link.', 403);
    $db = getDb();
    if (!isset($db['shares'][$shareHash])) subtitleError('Błędny lub wygasły link.', 403);

    $share = $db['shares'][$shareHash];
    if (time() > (int)($share['expires'] ?? 0)) subtitleError('Ten link tymczasowy wygasł.', 403);

    $folderKey = $share['folder'] ?? '';
    $subPath = $share['path'] ?? '';
    $fileName = $share['file'] ?? '';
    $resolved = resolveAllowedFile($folderKey, $subPath, $fileName);
    if ($resolved === false) subtitleError('Plik nie istnieje lub znajduje się poza dozwolonym folderem.', 404);
    $isPublicShare = true;
} else {
    checkAuth();
    $folderKey = $_GET['folder'] ?? '';
    $subPath = $_GET['path'] ?? '';
    $fileName = $_GET['file'] ?? '';
    $resolved = resolveAllowedFile($folderKey, $subPath, $fileName);
    if ($resolved === false) subtitleError('Odmowa dostępu lub plik nie istnieje.', 403);
}

session_write_close();
set_time_limit(300);

$sid = isset($_GET['sid']) ? intval($_GET['sid']) : -1;
if ($sid < 0) subtitleError('Nieprawidłowa ścieżka napisów.');

$chunkStart = isset($_GET['start']) ? max(0, floor((float)$_GET['start'])) : 0;
$chunkLength = isset($_GET['length']) ? (int)$_GET['length'] : 120;
$chunkLength = max(30, min(300, $chunkLength));
$chunkOverlap = 10;
$extractStart = max(0, $chunkStart - $chunkOverlap);
$extractDuration = $chunkLength + ($chunkOverlap * 2);

$filePath = $resolved['full'];
$fileSignature = (@filemtime($filePath) ?: 0) . '|' . (@filesize($filePath) ?: 0);
$thumbDir = __DIR__ . '/data/thumbnails';
if (!is_dir($thumbDir)) @mkdir($thumbDir, 0777, true);

$metaHash = md5('video-meta-v3|' . $filePath . '|' . $fileSignature);
$metaFile = $thumbDir . '/meta_' . $metaHash . '.json';
$probeData = readJsonFile($metaFile, []);
if (empty($probeData)) {
    $probeCmd = "/usr/bin/ffprobe -v error -print_format json -show_entries format=duration,start_time:stream=index,codec_type,codec_name,start_time:stream_tags=language,title:stream_disposition=default,forced " . escapeshellarg($filePath);
    $probeData = json_decode((string)@shell_exec($probeCmd), true);
    if (!is_array($probeData)) $probeData = [];
    if (!empty($probeData)) writeJsonFile($metaFile, $probeData);
}

$supportedSubtitleCodecs = ['subrip', 'srt', 'ass', 'ssa', 'webvtt', 'mov_text', 'text', 'ttml'];
$selectedStream = null;
$videoStartTime = 0.0;
$videoStartTimeFound = false;
$subtitleIdx = 0;
if (isset($probeData['streams']) && is_array($probeData['streams'])) {
    foreach ($probeData['streams'] as $stream) {
        if (($stream['codec_type'] ?? '') === 'video' && isset($stream['start_time']) && is_numeric($stream['start_time'])) {
            $videoStartTime = (float)$stream['start_time'];
            $videoStartTimeFound = true;
            break;
        }
    }

    if (!$videoStartTimeFound && isset($probeData['format']['start_time']) && is_numeric($probeData['format']['start_time'])) {
        $videoStartTime = (float)$probeData['format']['start_time'];
    }

    foreach ($probeData['streams'] as $stream) {
        if (($stream['codec_type'] ?? '') !== 'subtitle' || !isset($stream['index'])) continue;

        if ($subtitleIdx !== $sid) {
            $subtitleIdx++;
            continue;
        }

        $codec = strtolower((string)($stream['codec_name'] ?? ''));
        if (!in_array($codec, $supportedSubtitleCodecs, true)) break;
        $selectedStream = $stream;
        break;
    }
}

if ($selectedStream === null) subtitleError('Wybrana ścieżka nie jest obsługiwanym napisem tekstowym.', 422);

$subtitleDir = __DIR__ . '/data/subtitles';
if (!is_dir($subtitleDir) && !@mkdir($subtitleDir, 0777, true) && !is_dir($subtitleDir)) {
    subtitleError('Nie można utworzyć cache napisów.', 500);
}

$cacheHash = md5('embedded-subtitle-chunk-v3|' . $filePath . '|' . $fileSignature . '|' . $sid . '|' . ($selectedStream['index'] ?? '') . '|' . ($selectedStream['codec_name'] ?? '') . '|' . $videoStartTime . '|' . $chunkStart . '|' . $chunkLength);
$cacheFile = $subtitleDir . '/' . $cacheHash . '.vtt';
$lockFile = $subtitleDir . '/' . $cacheHash . '.lock';
$logFile = $subtitleDir . '/' . $cacheHash . '.log';

if (is_file($cacheFile) && filesize($cacheFile) > 0) serveSubtitleFile($cacheFile, -$videoStartTime);

foreach (glob($subtitleDir . '/*.part.*') ?: [] as $staleFile) {
    if (time() - (@filemtime($staleFile) ?: time()) > 3600) @unlink($staleFile);
}
foreach (glob($subtitleDir . '/*.log') ?: [] as $staleFile) {
    if (time() - (@filemtime($staleFile) ?: time()) > 86400) @unlink($staleFile);
}

$lockHandle = @fopen($lockFile, 'c+');
if ($lockHandle === false || !flock($lockHandle, LOCK_EX)) {
    if (is_resource($lockHandle)) fclose($lockHandle);
    subtitleError('Nie można zablokować generowania napisów.', 500);
}

if (is_file($cacheFile) && filesize($cacheFile) > 0) {
    flock($lockHandle, LOCK_UN);
    fclose($lockHandle);
    serveSubtitleFile($cacheFile, -$videoStartTime);
}

$tmpFile = $subtitleDir . '/' . $cacheHash . '.part.' . getmypid() . '.vtt';
@unlink($tmpFile);

$extractEnd = $videoStartTime + $extractStart + $extractDuration;
$cmd = "/usr/bin/timeout --kill-after=10 120 /usr/bin/ffmpeg -y -nostdin -hide_banner -loglevel error -copyts -ss " . escapeshellarg((string)$extractStart)
    . " -i " . escapeshellarg($filePath)
    . " -map 0:s:" . $sid
    . " -to " . escapeshellarg((string)$extractEnd)
    . " -vn -an -c:s webvtt -f webvtt " . escapeshellarg($tmpFile);

$output = [];
$returnCode = 1;
@exec($cmd . " 2>" . escapeshellarg($logFile), $output, $returnCode);

$isValid = false;
if ($returnCode === 0 && is_file($tmpFile) && filesize($tmpFile) > 0) {
    $header = (string)@file_get_contents($tmpFile, false, null, 0, 16);
    $isValid = strpos(ltrim($header, "\xEF\xBB\xBF"), 'WEBVTT') === 0;
}

if ($isValid && @rename($tmpFile, $cacheFile)) {
    @unlink($logFile);
    flock($lockHandle, LOCK_UN);
    fclose($lockHandle);
    serveSubtitleFile($cacheFile, -$videoStartTime);
}

@unlink($tmpFile);
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
subtitleError('Nie udało się wyodrębnić wbudowanej ścieżki napisów.', 422);
