<?php

declare(strict_types=1);

class AdminVideoController
{
    public static function routes(): void
    {
        Router::get('/admin/videos', [self::class, 'index']);
        Router::get('/admin/videos/create', [self::class, 'create']);
        Router::post('/admin/videos/store', [self::class, 'store']);
        Router::get('/admin/videos/{id}/edit', [self::class, 'edit']);
        Router::post('/admin/videos/{id}/update', [self::class, 'update']);
        Router::post('/admin/videos/{id}/delete', [self::class, 'destroy']);
        Router::post('/admin/videos/bulk-delete', [self::class, 'bulkDelete']);
        Router::post('/admin/videos/bulk-delete-start', [self::class, 'bulkDeleteStart']);
        Router::post('/admin/videos/bulk-delete-chunk', [self::class, 'bulkDeleteChunk']);
        Router::get('/admin/videos/bulk-delete-status', [self::class, 'bulkDeleteStatus']);
        Router::post('/admin/videos/bulk-delete-cancel', [self::class, 'bulkDeleteCancel']);
        Router::post('/admin/videos/{id}/translations', [self::class, 'saveTranslations']);
    }

    public static function index(): void
    {
        Auth::requireAdmin();
        $search = $_GET['q'] ?? '';
        $status = $_GET['status'] ?? '';
        $categoryId = !empty($_GET['category']) ? (int) $_GET['category'] : 0;
        $performerId = !empty($_GET['performer']) ? (int) $_GET['performer'] : 0;
        $hasThumbnail = $_GET['thumbnail'] ?? '';
        $sort = $_GET['sort'] ?? 'newest';

         
        $typeRows = Database::fetchAll('SELECT video_type, COUNT(*) as cnt FROM videos GROUP BY video_type ORDER BY ' . Video::typeFieldOrder());
        $availableTypes = array_column($typeRows, 'video_type');
        $showTypeFilter = count($availableTypes) > 1;
        $typeFilter = '';
        if ($showTypeFilter) {
            $typeFilter = $_GET['type'] ?? '';
            if ($typeFilter !== '' && !in_array($typeFilter, Video::VALID_TYPES, true)) {
                $typeFilter = '';
            }
        }

        $filters = ['admin' => true];
        if ($search !== '') $filters['search'] = $search;
        if ($status !== '') $filters['status'] = $status;
        if ($categoryId > 0) $filters['category_id'] = $categoryId;
        if ($performerId > 0) $filters['performer_id'] = $performerId;
        if ($hasThumbnail !== '') $filters['has_thumbnail'] = $hasThumbnail;
        if ($sort !== 'newest') $filters['sort'] = $sort;
        if ($typeFilter !== '') $filters['video_type'] = $typeFilter;

        $total = Video::count($filters);
        $pagination = Pagination::fromRequest($total, 100);
        $videos = Video::all($filters, $pagination->perPage, $pagination->offset);

         
        $videoTranslations = [];
        $videoIds = array_column($videos, 'id');
        if (!empty($videoIds)) {
            $placeholders = implode(',', array_fill(0, count($videoIds), '?'));
            $tRows = Database::fetchAll(
                "SELECT video_id, lang_code, title FROM video_translations WHERE video_id IN ({$placeholders}) ORDER BY video_id, lang_code",
                $videoIds
            );
            foreach ($tRows as $tr) {
                $videoTranslations[(int)$tr['video_id']][$tr['lang_code']] = $tr['title'];
            }
        }

        Router::render('admin/videos', [
            'pageTitle' => 'Videos',
            'activeMenu' => 'videos',
            'contentTemplate' => '_videos',
            'headerAction' => ['url' => '/admin/videos/create', 'label' => 'New Video'],
            'videos' => $videos,
            'pagination' => $pagination,
            'search' => $search,
            'filterCategories' => Database::fetchAll('SELECT id, name FROM categories ORDER BY name ASC'),
            'filterPerformers' => Database::fetchAll('SELECT id, name FROM performers ORDER BY name ASC'),
            'currentStatus' => $status,
            'currentCategory' => $categoryId,
            'currentPerformer' => $performerId,
            'currentThumbnail' => $hasThumbnail,
            'currentSort' => $sort,
            'showTypeFilter' => $showTypeFilter,
            'availableTypes' => $availableTypes,
            'currentType' => $typeFilter,
            'videoTranslations' => $videoTranslations,
        ]);
    }

    public static function create(): void
    {
        Auth::requireAdmin();
        Router::render('admin/video_form', [
            'pageTitle' => 'New Video',
            'activeMenu' => 'videos',
            'contentTemplate' => '_video_form',
            'video' => null,
            'categories' => Category::all(),
            'tags' => Tag::all(),
            'performers' => Performer::all('', 1000, 0),
            'channels' => Channel::all('', 1000, 0),
            'selectedCategories' => [],
            'selectedTags' => [],
            'selectedPerformers' => [],
            'selectedChannels' => [],
            'error' => null,
        ]);
    }

    public static function store(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            $_SESSION['flash'] = ['type' => 'error', 'message' => 'Your session has expired. Please refresh the page and try again.'];
            Router::redirect('/admin/videos/create');
        }

        $data = [
            'title' => trim($_POST['title'] ?? ''),
            'slug' => Slug::unique('videos', $_POST['title'] ?? ''),
            'description' => trim($_POST['description'] ?? ''),
            'embed_code' => trim($_POST['embed_code'] ?? ''),
            'duration' => (int) ($_POST['duration'] ?? 0),
            'video_type' => in_array($_POST['video_type'] ?? '', Video::VALID_TYPES, true) ? $_POST['video_type'] : Video::DEFAULT_TYPE,
            'status' => in_array($_POST['status'] ?? '', ['draft', 'published', 'private'], true) ? $_POST['status'] : 'draft',
            'views' => max(0, (int) ($_POST['views'] ?? 0)),
            'likes' => max(0, (int) ($_POST['likes'] ?? 0)),
            'dislikes' => max(0, (int) ($_POST['dislikes'] ?? 0)),
            'user_id' => Auth::id(),
        ];

        if ($data['status'] === 'published') {
            $data['published_at'] = date('Y-m-d H:i:s');
        }

         
        if ($data['embed_code'] !== '') {
            $data['embed_code'] = Sanitizer::embedCode($data['embed_code']);
        }

        $hasVideoFile = !empty($_FILES['video_file']['name']) && $_FILES['video_file']['error'] === UPLOAD_ERR_OK;
        $hasThumbnail = !empty($_FILES['thumbnail']['name']) && $_FILES['thumbnail']['error'] === UPLOAD_ERR_OK;

        if (($hasVideoFile || $hasThumbnail) && MediaStorage::isAllFull()) {
            $_SESSION['flash'] = ['type' => 'error', 'message' => 'All storage servers are full. Add more storage space before uploading.'];
            Router::redirect('/admin/videos/create');
            return;
        }

         
        if ($data['embed_code'] !== '' && $hasVideoFile) {
            $hasVideoFile = false;
        } elseif ($hasVideoFile) {
            $data['embed_code'] = '';
        }

         
        $folder = '';
        if ($hasVideoFile || $hasThumbnail) {
            $folder = VideoAsset::createFolder();
            $data['video_folder'] = $folder;
            $defaultStorageId = MediaStorage::activeDefaultId();
            if ($defaultStorageId > 0) $data['storage_id'] = $defaultStorageId;
        }

        $sid = isset($data['storage_id']) ? (int)$data['storage_id'] : null;

        $videoUploadOk = true;
        if ($hasVideoFile) {
            $mime = Mime::fromFile($_FILES['video_file']['tmp_name'], $_FILES['video_file']['name'] ?? null, 'video/mp4');
            $videoUploadOk = VideoAsset::saveVideo($folder, $_FILES['video_file']['tmp_name'], $mime, $sid);
        }

        if ($hasThumbnail) {
            if ($folder === '') {
                $folder = VideoAsset::createFolder();
                $data['video_folder'] = $folder;
            }
            VideoAsset::saveThumb($folder, $_FILES['thumbnail']['tmp_name'], 'thumb', $sid);
        }

        $videoId = Video::create($data);

         
        if (!empty($_POST['categories'])) {
            Video::syncCategories($videoId, $_POST['categories']);
        }
        if (!empty($_POST['tags'])) {
            Video::syncTags($videoId, $_POST['tags']);
        }
        if (!empty($_POST['performers'])) {
            Video::syncPerformers($videoId, $_POST['performers']);
        }
        if (!empty($_POST['channels'])) {
            Video::syncChannels($videoId, $_POST['channels']);
        }

        HookSystem::doAction('video.created', $videoId);

        if ($hasVideoFile && TranscodeManager::isEnabled()) {
            $queued = TranscodeManager::queue($videoId);
            if ($queued > 0 && TranscodeManager::needsSourceReencode()) {
                Database::query("UPDATE videos SET status = 'processing' WHERE id = ? AND status = 'published'", [$videoId]);
            }
        }

         
         
         
        if ($hasVideoFile && $sid && MediaStorage::isRemote($sid) && !$videoUploadOk) {
            Database::query("UPDATE videos SET status = 'error' WHERE id = ?", [$videoId]);
        } elseif ($hasVideoFile && $sid && MediaStorage::isRemote($sid) && empty($queued)) {
             
             
            VideoAsset::purgeLocalFolder($folder);
        }

        $_SESSION['flash'] = ['type' => 'success', 'message' => 'Video created successfully.' . (isset($queued) && $queued > 0 ? ' Transcoding queued.' : '')];
        SitemapController::markDirty();
        Router::redirect('/admin/videos');
    }

    public static function edit(): void
    {
        Auth::requireAdmin();
        $id = (int) Router::param('id');
        $video = Video::find($id);
        if (!$video) {
            $_SESSION['flash'] = ['type' => 'error', 'message' => 'Video not found.'];
            Router::redirect('/admin/videos');
        }

         
        $translations = Database::fetchAll(
            'SELECT lang_code, title, description FROM video_translations WHERE video_id = ?',
            [$id]
        );
        $translationMap = [];
        foreach ($translations as $tr) {
            $translationMap[$tr['lang_code']] = $tr;
        }

         
        $languages = Translator::available();
        $defaultLang = Translator::getDefaultCode();

        Router::render('admin/video_form', [
            'pageTitle' => 'Edit Video',
            'activeMenu' => 'videos',
            'contentTemplate' => '_video_form',
            'video' => $video,
            'categories' => Category::all(),
            'tags' => Tag::all(),
            'performers' => Performer::all('', 1000, 0),
            'channels' => Channel::all('', 1000, 0),
            'selectedCategories' => array_column($video['categories'], 'id'),
            'selectedTags' => array_column($video['tags'], 'id'),
            'selectedPerformers' => array_column($video['performers'], 'id'),
            'selectedChannels' => array_column($video['channels'] ?? [], 'id'),
            'videoTranslations' => $translationMap,
            'videoLanguages' => $languages,
            'defaultLang' => $defaultLang,
            'error' => null,
        ]);
    }

    public static function update(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            Router::redirect('/admin/videos');
        }

        $id = (int) Router::param('id');
        $video = Video::find($id);
        if (!$video) {
            Router::redirect('/admin/videos');
        }

        $data = [
            'title' => trim($_POST['title'] ?? ''),
            'slug' => Slug::unique('videos', $_POST['title'] ?? '', $id),
            'description' => trim($_POST['description'] ?? ''),
            'embed_code' => trim($_POST['embed_code'] ?? ''),
            'duration' => (int) ($_POST['duration'] ?? 0),
            'video_type' => in_array($_POST['video_type'] ?? '', Video::VALID_TYPES, true) ? $_POST['video_type'] : Video::DEFAULT_TYPE,
            'status' => in_array($_POST['status'] ?? '', ['draft', 'published', 'private'], true) ? $_POST['status'] : 'draft',
            'views' => max(0, (int) ($_POST['views'] ?? $video['views'])),
            'likes' => max(0, (int) ($_POST['likes'] ?? $video['likes'])),
            'dislikes' => max(0, (int) ($_POST['dislikes'] ?? $video['dislikes'])),
        ];

        if ($data['status'] === 'published' && empty($video['published_at'])) {
            $data['published_at'] = date('Y-m-d H:i:s');
        }

        if ($data['embed_code'] !== '') {
            $data['embed_code'] = Sanitizer::embedCode($data['embed_code']);
        }

        $hasVideoFile = !empty($_FILES['video_file']['name']) && $_FILES['video_file']['error'] === UPLOAD_ERR_OK;
        $hasThumbnail = !empty($_FILES['thumbnail']['name']) && $_FILES['thumbnail']['error'] === UPLOAD_ERR_OK;

         
        if ($data['embed_code'] !== '' && $hasVideoFile) {
            $hasVideoFile = false;
        } elseif ($hasVideoFile) {
            $data['embed_code'] = '';
        }

        $folder = $video['video_folder'] ?? '';
        if (($hasVideoFile || $hasThumbnail) && $folder === '') {
            $folder = VideoAsset::createFolder();
            $data['video_folder'] = $folder;
            $defaultStorageId = MediaStorage::activeDefaultId();
            if ($defaultStorageId > 0 && empty($video['storage_id'])) {
                $data['storage_id'] = $defaultStorageId;
            }
        }

        $sid = isset($video['storage_id']) ? (int)$video['storage_id'] : null;

        $videoUploadOk = true;
        if ($hasVideoFile) {
            $mime = Mime::fromFile($_FILES['video_file']['tmp_name'], $_FILES['video_file']['name'] ?? null, 'video/mp4');
            $videoUploadOk = VideoAsset::saveVideo($folder, $_FILES['video_file']['tmp_name'], $mime, $sid);
        }

        if ($hasThumbnail) {
            VideoAsset::saveThumb($folder, $_FILES['thumbnail']['tmp_name'], 'thumb', $sid);
        }

        Video::update($id, $data);

        Video::syncCategories($id, $_POST['categories'] ?? []);
        Video::syncTags($id, $_POST['tags'] ?? []);
        Video::syncPerformers($id, $_POST['performers'] ?? []);
        Video::syncChannels($id, $_POST['channels'] ?? []);

        if ($hasVideoFile && TranscodeManager::isEnabled()) {
            Database::delete('transcode_jobs', 'video_id = ?', [$id]);
            $queued = TranscodeManager::queue($id);
            if ($queued > 0 && TranscodeManager::needsSourceReencode()) {
                Database::query("UPDATE videos SET status = 'processing' WHERE id = ? AND status = 'published'", [$id]);
            }
        }

         
         
        if ($hasVideoFile && $sid && MediaStorage::isRemote($sid) && !$videoUploadOk) {
            Database::query("UPDATE videos SET status = 'error' WHERE id = ?", [$id]);
        } elseif ($hasVideoFile && $sid && MediaStorage::isRemote($sid) && empty($queued)) {
             
            VideoAsset::purgeLocalFolder($folder);
        }

        $_SESSION['flash'] = ['type' => 'success', 'message' => 'Video updated successfully.' . (isset($queued) && $queued > 0 ? ' Transcoding queued.' : '')];
        SitemapController::markDirty();
        Router::redirect('/admin/videos');
    }

    public static function destroy(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            Router::redirect('/admin/videos');
        }

        $id = (int) Router::param('id');
        Video::delete($id);

        $_SESSION['flash'] = ['type' => 'success', 'message' => 'Video deleted successfully.'];
        SitemapController::markDirty();
        Router::redirect('/admin/videos');
    }

    public static function bulkDelete(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            http_response_code(403);
            echo json_encode(['error' => 'Invalid CSRF token']);
            return;
        }
        $input = json_decode(file_get_contents('php://input'), true);
        $ids = array_filter(array_map('intval', $input['ids'] ?? []), fn($id) => $id > 0);
        foreach ($ids as $id) {
            Video::delete($id);
        }
        $_SESSION['flash'] = ['type' => 'success', 'message' => count($ids) . ' video(s) deleted.'];
        echo json_encode(['deleted' => count($ids)]);
    }

    

    public static function bulkDeleteStart(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            Router::json(['error' => 'Invalid CSRF token'], 403);
            return;
        }
        $input = json_decode(file_get_contents('php://input'), true) ?: [];
        $ids = array_filter(array_map('intval', $input['ids'] ?? []), fn($id) => $id > 0);
        $filters = $input['filters'] ?? null;
        $selectAll = !empty($input['select_all']);

        if ($selectAll && is_array($filters)) {
             
            $adminFilters = array_merge($filters, ['admin' => true]);
            $total = Video::count($adminFilters);
            if ($total === 0) {
                Router::json(['error' => 'No videos match the current filters.'], 400);
                return;
            }
            $jobId = Database::insert('bulk_delete_jobs', [
                'total_count' => $total,
                'deleted_count' => 0,
                'status' => 'pending',
                'filters' => json_encode($adminFilters),
            ]);
        } elseif (!empty($ids)) {
            $jobId = Database::insert('bulk_delete_jobs', [
                'total_count' => count($ids),
                'deleted_count' => 0,
                'status' => 'pending',
                'filters' => json_encode(['ids' => $ids]),
            ]);
        } else {
            Router::json(['error' => 'No videos selected.'], 400);
            return;
        }

         
        self::spawnDeleteWorker();

        Router::json(['job_id' => $jobId]);
    }

    

    public static function processDeleteChunk(): bool
    {
         
        Database::query(
            "UPDATE bulk_delete_jobs SET status = 'pending', started_at = NULL
             WHERE status = 'processing' AND started_at < DATE_SUB(NOW(), INTERVAL 5 MINUTE)"
        );

        $job = Database::fetchOne("SELECT * FROM bulk_delete_jobs WHERE status IN ('pending','processing') ORDER BY id ASC LIMIT 1");
        if (!$job) return false;

        $jobId = (int) $job['id'];
        $lockName = 'bulkdel_' . $jobId;
         
         
        if ((int) (Database::fetchOne('SELECT GET_LOCK(?, 0) AS l', [$lockName])['l'] ?? 0) !== 1) {
            return true;  
        }

         
        $affected = Database::query(
            "UPDATE bulk_delete_jobs SET status = 'processing', started_at = NOW() WHERE id = ? AND status IN ('pending','processing')",
            [$jobId]
        )->rowCount();
        if ($affected === 0) { Database::query('SELECT RELEASE_LOCK(?)', [$lockName]); return false; }

        $filters = json_decode($job['filters'], true) ?: [];
        $chunkSize = 50;
        $deleted = 0;

        if (isset($filters['ids'])) {
            $remainingIds = array_values(array_filter($filters['ids'], fn($id) => $id > 0));
            $chunk = array_slice($remainingIds, 0, $chunkSize);
            foreach ($chunk as $vid) {
                try {
                    Video::delete($vid);
                    $deleted++;
                } catch (\Throwable $e) {
                    error_log("Bulk delete: failed to delete video {$vid}: " . $e->getMessage());
                }
            }
            $filters['ids'] = array_values(array_slice($remainingIds, $chunkSize));
            Database::query('UPDATE bulk_delete_jobs SET filters = ?, deleted_count = deleted_count + ?, started_at = NOW() WHERE id = ?', [
                json_encode($filters), $deleted, $jobId,
            ]);
        } else {
            $videoIds = array_column(Video::all($filters, $chunkSize, 0), 'id');
            foreach ($videoIds as $vid) {
                try {
                    Video::delete((int) $vid);
                    $deleted++;
                } catch (\Throwable $e) {
                    error_log("Bulk delete: failed to delete video {$vid}: " . $e->getMessage());
                }
            }
            Database::query('UPDATE bulk_delete_jobs SET deleted_count = deleted_count + ?, started_at = NOW() WHERE id = ?', [$deleted, $jobId]);
        }

        $job = Database::fetchOne('SELECT * FROM bulk_delete_jobs WHERE id = ?', [$jobId]);
        $isDone = (int) $job['deleted_count'] >= (int) $job['total_count'] || $deleted === 0;

        if ($isDone) {
            Database::query("UPDATE bulk_delete_jobs SET status = 'completed', completed_at = NOW() WHERE id = ?", [$jobId]);
            SitemapController::markDirty();
        }
        Database::query('SELECT RELEASE_LOCK(?)', [$lockName]);
        return !$isDone;
    }

    

    public static function spawnDeleteWorker(): void
    {
        $pidFile = APP_ROOT . '/storage/tmp/bulk-delete-worker.pid';
        if (file_exists($pidFile)) {
            $pid = (int) @file_get_contents($pidFile);
            if (Env::processAlive($pid)) {
                return;  
            }
            @unlink($pidFile);
        }

        $script = APP_ROOT . '/bin/bulk-delete-worker.php';
        if (!is_file($script) || !function_exists('exec')) {
             
            App::selfPing();
            return;
        }

        $phpBin = Env::phpCli();

        $tmpDir = APP_ROOT . '/storage/tmp';
        if (!is_dir($tmpDir)) mkdir($tmpDir, 0755, true);

        @exec(escapeshellarg($phpBin) . ' ' . escapeshellarg($script) . ' > /dev/null 2>&1 &');
    }

    

    public static function bulkDeleteChunk(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            Router::json(['error' => 'Invalid CSRF token'], 403);
            return;
        }
         
         
         
        self::processDeleteChunk();

        $input = json_decode(file_get_contents('php://input'), true) ?: [];
        $jobId = (int) ($input['job_id'] ?? ($_GET['job_id'] ?? 0));
        $job = $jobId > 0
            ? Database::fetchOne('SELECT * FROM bulk_delete_jobs WHERE id = ?', [$jobId])
            : Database::fetchOne("SELECT * FROM bulk_delete_jobs ORDER BY id DESC LIMIT 1");
        if (!$job) {
            Router::json(['done' => true, 'deleted_count' => 0, 'total_count' => 0]);
            return;
        }
        Router::json([
            'deleted_count' => (int) $job['deleted_count'],
            'total_count' => (int) $job['total_count'],
            'status' => $job['status'],
            'done' => in_array($job['status'], ['completed', 'cancelled'], true),
        ]);
    }

    

    public static function bulkDeleteStatus(): void
    {
        Auth::requireAdmin();
        $jobId = (int) ($_GET['job_id'] ?? 0);
        $job = Database::fetchOne('SELECT * FROM bulk_delete_jobs WHERE id = ?', [$jobId]);
        if (!$job) {
            Router::json(['error' => 'Job not found.'], 404);
            return;
        }
        Router::json([
            'deleted_count' => (int) $job['deleted_count'],
            'total_count' => (int) $job['total_count'],
            'status' => $job['status'],
            'done' => in_array($job['status'], ['completed', 'cancelled'], true),
        ]);
    }

    

    public static function bulkDeleteCancel(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            Router::json(['error' => 'Invalid CSRF token'], 403);
            return;
        }
        $input = json_decode(file_get_contents('php://input'), true) ?: [];
        $jobId = (int) ($input['job_id'] ?? 0);
        Database::query("UPDATE bulk_delete_jobs SET status = 'cancelled', completed_at = NOW() WHERE id = ? AND status IN ('pending','processing')", [$jobId]);
        Router::json(['cancelled' => true]);
    }

    public static function saveTranslations(): void
    {
        Auth::requireAdmin();
        if (!Router::verifyCsrf()) {
            Router::json(['error' => 'Invalid CSRF token'], 403);
        }
        $id = (int) Router::param('id');
        $input = json_decode(file_get_contents('php://input'), true) ?: [];
        $translations = $input['translations'] ?? [];

        foreach ($translations as $langCode => $fields) {
            $langCode = preg_replace('/[^a-z]/', '', strtolower($langCode));
            if ($langCode === '' || strlen($langCode) > 5) continue;

            $title = mb_substr(trim($fields['title'] ?? ''), 0, 500);
            $description = trim($fields['description'] ?? '');

            if ($title === '') {
                Database::query(
                    'DELETE FROM video_translations WHERE video_id = ? AND lang_code = ?',
                    [$id, $langCode]
                );
            } else {
                $slug = Slug::uniqueVideoTranslation($title, $langCode, $id);
                $existing = Database::fetchOne(
                    'SELECT id FROM video_translations WHERE video_id = ? AND lang_code = ?',
                    [$id, $langCode]
                );
                if ($existing) {
                    Database::query(
                        'UPDATE video_translations SET title = ?, slug = ?, description = ? WHERE video_id = ? AND lang_code = ?',
                        [$title, $slug, $description, $id, $langCode]
                    );
                } else {
                    Database::query(
                        'INSERT INTO video_translations (video_id, lang_code, title, slug, description) VALUES (?, ?, ?, ?, ?)',
                        [$id, $langCode, $title, $slug, $description]
                    );
                }
            }
        }

        SitemapController::markDirty();
        Router::json(['success' => true]);
    }
}
