<?php
/**
 * ITSWEBER CMS – Page Builder Controller
 *
 * Manages the page builder for homepage, pages, and blog posts.
 * Section CRUD, reordering, duplication, and AJAX-based form loading/saving.
 *
 * Supported contexts:
 *   - 'homepage'    (default, GET /admin/pagebuilder)
 *   - 'page:{id}'   (GET /admin/pages/{id}/pagebuilder)
 *   - 'blog:{id}'   (GET /admin/blog/{id}/pagebuilder)
 *
 * @author    Benny Weber (ITSWEBER)
 * @copyright © ITSWEBER – www.itsweber.de
 * @contact   kontakt@itsweber.de
 */

namespace App\Http\Controllers\Admin;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Models\PageSection;
use App\Models\SectionRevision;
use App\Models\SectionType;
use App\Sections\SectionRegistry;

class PageBuilderController extends Controller
{
    private const SECTION_LIMIT = 20;

    /**
     * Main page builder view.
     * GET /admin/pagebuilder                (homepage)
     * GET /admin/pages/{id}/pagebuilder     (page)
     * GET /admin/blog/{id}/pagebuilder      (blog post)
     */
    public function index(Request $request, array $params = []): void
    {
        $context = $this->resolveContext($request, $params);
        $contextMeta = $this->contextMeta($context);

        $sections = PageSection::byContext($context);

        foreach ($sections as &$section) {
            $section['data'] = json_decode($section['content'] ?? '{}', true) ?: [];
        }
        unset($section);

        $activeTheme = $this->app->service('view')->activeTheme();
        $sectionTypes = SectionRegistry::byCategory($activeTheme);

        $this->renderAdmin('pagebuilder/index', [
            'pageTitle'    => $contextMeta['title'],
            'sections'     => $sections,
            'sectionTypes' => $sectionTypes,
            'sectionLimit' => self::SECTION_LIMIT,
            'auth'         => $this->auth(),
            'csrf'         => $this->csrf(),
            'context'      => $context,
            'contextMeta'  => $contextMeta,
        ]);
    }

    /**
     * Add a new section instance.
     * POST /admin/pagebuilder/section/add (AJAX)
     */
    public function addSection(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $context = $this->resolveContext($request, $params);

        $typeKey = trim($request->input('type_key', ''));
        $reg = SectionRegistry::get($typeKey);

        if (!$reg) {
            Response::json(['success' => false, 'message' => 'Unknown section type.'], 400);
            return;
        }

        // Guard: theme-bound sections only allowed when their theme is active
        $themeSlug = $reg::themeSlug();
        if ($themeSlug !== null) {
            $activeTheme = $this->app->service('view')->activeTheme();
            if ($themeSlug !== $activeTheme) {
                Response::json(['success' => false, 'message' => 'This section requires the ' . ucfirst($themeSlug) . ' theme.'], 403);
                return;
            }
        }

        // Check section limit
        $currentCount = PageSection::count(['page_context' => $context]);
        if ($currentCount >= self::SECTION_LIMIT) {
            Response::json(['success' => false, 'message' => 'Section limit (' . self::SECTION_LIMIT . ') reached.'], 400);
            return;
        }

        // Check single-instance constraint
        if (!$reg::allowMultiple()) {
            $existing = PageSection::countByType($typeKey, $context);
            if ($existing > 0) {
                Response::json(['success' => false, 'message' => 'This section type allows only one instance.'], 400);
                return;
            }
        }

        // Ensure section type exists in DB (plugin may only be in SectionRegistry)
        if (!SectionType::findByKey($typeKey)) {
            try {
                SectionType::create([
                    'type_key'       => $typeKey,
                    'label'          => $reg::label(),
                    'category'       => $reg::category(),
                    'source'         => 'plugin',
                    'allow_multiple' => $reg::allowMultiple() ? 1 : 0,
                    'is_available'   => 1,
                    'sort_order'     => 99,
                ]);
            } catch (\Throwable $e) {
                error_log('Auto-register section type failed: ' . $e->getMessage());
            }
        }

        $sortOrder = PageSection::nextSortOrder($context);
        $defaultData = $reg->defaultData();

        $id = PageSection::create([
            'page_context'  => $context,
            'section_type'  => $typeKey,
            'instance_label' => null,
            'content'       => json_encode($defaultData, JSON_UNESCAPED_UNICODE),
            'is_active'     => 0,
            'sort_order'    => $sortOrder,
        ]);

        $section = PageSection::find($id);
        $section['data'] = $defaultData;

        // Render the section card HTML
        $html = $this->renderSectionCard($section, true);

        Response::json([
            'success' => true,
            'html'    => $html,
            'message' => __('admin.pagebuilder.section_added'),
        ]);
    }

    /**
     * Save a section's content.
     * POST /admin/pagebuilder/section/{id}/save (AJAX)
     */
    public function saveSection(Request $request, array $params = []): void
    {
        // Wrap entire method in try/catch for robust error reporting
        try {
            $this->validateCsrf();

            $id = (int) ($params['id'] ?? 0);
            $section = PageSection::find($id);

            if (!$section) {
                Response::json(['success' => false, 'message' => 'Section not found.'], 404);
                return;
            }

            $typeKey = $section['section_type'];

            $data = SectionRegistry::buildData($typeKey, $request);

            if ($data === null) {
                $data = [];
            }

            $instanceLabel = trim($request->input('instance_label', ''));

            // Store revision of current content before overwriting
            $oldContent = $section['content'] ?? '{}';
            $changedBy  = (string) ($this->auth()->userId() ?? '');
            SectionRevision::store($id, $oldContent, $changedBy !== '' ? $changedBy : null);

            PageSection::updateById($id, [
                'instance_label' => $instanceLabel !== '' ? $instanceLabel : null,
                'content'        => json_encode($data, JSON_UNESCAPED_UNICODE),
                'updated_at'     => date('Y-m-d H:i:s'),
            ]);

            $revisionCount = SectionRevision::countForSection($id);

            Response::json([
                'success'        => true,
                'message'        => __('admin.pagebuilder.section_saved'),
                'revisionCount'  => $revisionCount,
            ]);
        } catch (\Throwable $e) {
            error_log('[PageBuilder] saveSection error: ' . $e->getMessage());
            Response::json([
                'success' => false,
                'message' => 'Save error: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Toggle a section's active state.
     * POST /admin/pagebuilder/section/{id}/toggle (AJAX)
     */
    public function toggleSection(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);
        $section = PageSection::find($id);

        if (!$section) {
            Response::json(['success' => false, 'message' => 'Section not found.'], 404);
            return;
        }

        $newState = $section['is_active'] ? 0 : 1;
        PageSection::updateById($id, [
            'is_active'  => $newState,
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        $label = $newState
            ? __('admin.pagebuilder.status_active')
            : __('admin.pagebuilder.status_inactive');

        Response::json([
            'success'  => true,
            'isActive' => $newState,
            'message'  => $label,
        ]);
    }

    /**
     * Delete a section.
     * POST /admin/pagebuilder/section/{id}/delete (AJAX)
     */
    public function deleteSection(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);
        $section = PageSection::find($id);

        if (!$section) {
            Response::json(['success' => false, 'message' => 'Section not found.'], 404);
            return;
        }

        SectionRevision::deleteForSection($id);
        PageSection::deleteById($id);

        Response::json([
            'success' => true,
            'message' => __('admin.pagebuilder.section_deleted'),
        ]);
    }

    /**
     * Duplicate a section.
     * POST /admin/pagebuilder/section/{id}/duplicate (AJAX)
     */
    public function duplicateSection(Request $request, array $params = []): void
    {
        $this->validateCsrf();

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

        // Determine context from the original section
        $original = PageSection::find($id);
        $context = $original['page_context'] ?? 'homepage';

        // Check section limit
        $currentCount = PageSection::count(['page_context' => $context]);
        if ($currentCount >= self::SECTION_LIMIT) {
            Response::json(['success' => false, 'message' => 'Section limit (' . self::SECTION_LIMIT . ') reached.'], 400);
            return;
        }

        // Check single-instance constraint
        if ($original) {
            $reg = SectionRegistry::get($original['section_type'] ?? '');
            if ($reg && !$reg::allowMultiple()) {
                Response::json(['success' => false, 'message' => 'This section type allows only one instance.'], 400);
                return;
            }
        }

        $newId = PageSection::duplicate($id);

        if (!$newId) {
            Response::json(['success' => false, 'message' => 'Section not found.'], 404);
            return;
        }

        $newSection = PageSection::find($newId);
        $newSection['data'] = json_decode($newSection['content'] ?? '{}', true) ?: [];

        $html = $this->renderSectionCard($newSection, true);

        Response::json([
            'success' => true,
            'html'    => $html,
            'message' => __('admin.pagebuilder.section_duplicated'),
        ]);
    }

    /**
     * Reorder sections via drag & drop.
     * POST /admin/pagebuilder/reorder (AJAX)
     */
    public function reorder(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $ids = $request->input('ids', []);

        // JS may send 'order' as JSON string instead of 'ids' array
        if (empty($ids)) {
            $orderJson = $request->input('order', '');
            if ($orderJson) {
                $ids = json_decode($orderJson, true);
            }
        }

        if (!is_array($ids) || empty($ids)) {
            Response::json(['success' => false, 'message' => 'No IDs provided.'], 400);
            return;
        }

        // Sanitize to integers
        $ids = array_map('intval', $ids);
        PageSection::reorder($ids);

        Response::json([
            'success' => true,
            'message' => __('admin.pagebuilder.order_saved'),
        ]);
    }

    /**
     * Load a section's edit form (lazy load on expand).
     * GET /admin/pagebuilder/section/{id}/form (AJAX)
     */
    public function loadForm(Request $request, array $params = []): void
    {
        // Wrap entire method in try/catch for robust error reporting
        try {
            $id = (int) ($params['id'] ?? 0);
            $section = PageSection::find($id);

            if (!$section) {
                Response::json(['success' => false, 'message' => 'Section not found.'], 404);
                return;
            }

            $section['data'] = json_decode($section['content'] ?? '{}', true) ?: [];

            $html = $this->renderSectionForm($section);

            Response::json([
                'success' => true,
                'html'    => $html,
            ]);
        } catch (\Throwable $e) {
            error_log('[PageBuilder] loadForm error: ' . $e->getMessage());
            Response::json([
                'success' => false,
                'message' => 'Form load error: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Render a live preview of a section.
     * POST /admin/pagebuilder/section/{id}/preview (AJAX)
     */
    public function previewSection(Request $request, array $params = []): void
    {
        // Wrap entire method in try/catch for robust error reporting
        try {
            $this->validateCsrf();

            $id = (int) ($params['id'] ?? 0);
            $section = PageSection::find($id);

            if (!$section) {
                Response::json(['success' => false, 'message' => 'Section not found.'], 404);
                return;
            }

            // Build data: from form submission (live preview) or from saved content
            $typeKey = $section['section_type'];

            if ($request->input('_use_saved', '')) {
                $data = json_decode($section['content'] ?? '{}', true) ?: [];
            } else {
                $data = SectionRegistry::buildData($typeKey, $request) ?? [];
            }

            $previewSection = $section;
            $previewSection['content'] = json_encode($data, JSON_UNESCAPED_UNICODE);
            $previewSection['is_active'] = 1;

            // Seed view render data for preview context with real data
            $view = $this->app->service('view');
            $db   = $this->app->service('database');
            $previewData = [
                'latest_posts'          => [],
                'upcoming_events'       => [],
                'gallery_preview_albums'=> [],
                'downloads'             => [],
            ];

            // Load real data for dynamic preview sections
            $limit = (int) ($data['count'] ?? 3);
            if ($limit < 1 || $limit > 12) $limit = 3;

            if ($typeKey === 'blog_preview') {
                $previewData['latest_posts'] = $db->fetchAll(
                    "SELECT * FROM iw_blog_posts WHERE status = 'published' ORDER BY published_at DESC LIMIT " . (int) $limit
                );
            } elseif ($typeKey === 'events_preview') {
                $previewData['upcoming_events'] = $db->fetchAll(
                    "SELECT * FROM iw_events WHERE publish_status = 'published' AND start_date >= CURDATE() ORDER BY start_date ASC LIMIT " . (int) $limit
                );
            } elseif ($typeKey === 'gallery_preview') {
                $previewData['gallery_preview_albums'] = $db->fetchAll(
                    "SELECT a.*, COUNT(i.id) AS image_count FROM iw_gallery_albums a LEFT JOIN iw_gallery_images i ON i.album_id = a.id WHERE a.is_visible = 1 GROUP BY a.id ORDER BY a.sort_order ASC LIMIT " . (int) $limit
                );
            }

            $view->setPreviewData($previewData);

            $html = render_page_section($previewSection, [$previewSection]);

            // Collect section-specific CSS
            $reg = SectionRegistry::get($typeKey);
            $cssLinks = '';
            if ($reg) {
                $version = cms_version();
                foreach ($reg->styles() as $url) {
                    $cssLinks .= '<link rel="stylesheet" href="' . e($url) . '?v=' . e($version) . '">' . "\n";
                }
            }

            $theme = $view->activeTheme();
            $previewHtml = '<!DOCTYPE html>'
                . '<html lang="' . e(setting('locale', 'de')) . '">'
                . '<head>'
                . '<meta charset="UTF-8">'
                . '<meta name="viewport" content="width=device-width, initial-scale=1.0">'
                . '<link rel="stylesheet" href="/themes/' . e($theme) . '/assets/css/style.css?v=' . e(cms_version()) . '">'
                . $cssLinks
                . '<style>body{margin:0;padding:0;overflow-x:hidden;}.reveal{opacity:1!important;transform:none!important;}</style>'
                . '</head>'
                . '<body>'
                . $html
                . '</body></html>';

            Response::json([
                'success' => true,
                'html'    => $previewHtml,
            ]);
        } catch (\Throwable $e) {
            Response::json([
                'success' => false,
                'message' => 'Preview error: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Export a section as JSON.
     * GET /admin/pagebuilder/section/{id}/export (AJAX)
     */
    public function exportSection(Request $request, array $params = []): void
    {
        $id = (int) ($params['id'] ?? 0);
        $section = PageSection::find($id);

        if (!$section) {
            Response::json(['success' => false, 'message' => 'Section not found.'], 404);
            return;
        }

        $data = json_decode($section['content'] ?? '{}', true) ?: [];
        $reg = SectionRegistry::get($section['section_type']);

        $exportData = [
            'iw_export'      => 'section',
            'version'        => cms_version(),
            'section_type'   => $section['section_type'],
            'instance_label' => $section['instance_label'] ?? null,
            'content'        => $data,
            'exported_at'    => date('c'),
        ];

        Response::json([
            'success'  => true,
            'export'   => $exportData,
            'filename' => ($section['section_type']) . '_' . $id . '_export.json',
        ]);
    }

    /**
     * Import a section from JSON.
     * POST /admin/pagebuilder/section/import (AJAX)
     */
    public function importSection(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $context = $this->resolveContext($request, $params);

        // Check section limit
        $currentCount = PageSection::count(['page_context' => $context]);
        if ($currentCount >= self::SECTION_LIMIT) {
            Response::json(['success' => false, 'message' => __('admin.pagebuilder.limit_reached', ['limit' => self::SECTION_LIMIT])], 400);
            return;
        }

        $jsonStr = $request->input('import_data', '');
        if (!$jsonStr) {
            Response::json(['success' => false, 'message' => __('admin.pagebuilder.import_invalid')], 400);
            return;
        }

        $importData = json_decode($jsonStr, true);
        if (!$importData || ($importData['iw_export'] ?? '') !== 'section') {
            Response::json(['success' => false, 'message' => __('admin.pagebuilder.import_invalid')], 400);
            return;
        }

        $typeKey = $importData['section_type'] ?? '';
        $reg = SectionRegistry::get($typeKey);

        if (!$reg) {
            Response::json(['success' => false, 'message' => __('admin.pagebuilder.import_unknown_type', ['type' => $typeKey])], 400);
            return;
        }

        // Check single-instance constraint
        if (!$reg::allowMultiple()) {
            $existing = PageSection::countByType($typeKey, $context);
            if ($existing > 0) {
                Response::json(['success' => false, 'message' => 'This section type allows only one instance.'], 400);
                return;
            }
        }

        $content = $importData['content'] ?? [];
        $instanceLabel = $importData['instance_label'] ?? null;
        $sortOrder = PageSection::nextSortOrder($context);

        $id = PageSection::create([
            'page_context'   => $context,
            'section_type'   => $typeKey,
            'instance_label' => $instanceLabel ? $instanceLabel . ' (Import)' : null,
            'content'        => json_encode($content, JSON_UNESCAPED_UNICODE),
            'is_active'      => 0,
            'sort_order'     => $sortOrder,
        ]);

        $section = PageSection::find($id);
        $section['data'] = $content;

        $html = $this->renderSectionCard($section, true);

        Response::json([
            'success' => true,
            'html'    => $html,
            'message' => __('admin.pagebuilder.section_imported'),
        ]);
    }

    /**
     * List revisions for a section.
     * GET /admin/pagebuilder/section/{id}/revisions (AJAX)
     */
    public function revisions(Request $request, array $params = []): void
    {
        $id = (int) ($params['id'] ?? 0);
        $section = PageSection::find($id);

        if (!$section) {
            Response::json(['success' => false, 'message' => 'Section not found.'], 404);
            return;
        }

        $revisions = SectionRevision::forSection($id);
        $currentContent = json_decode($section['content'] ?? '{}', true) ?: [];

        $items = [];
        foreach ($revisions as $rev) {
            $revContent = json_decode($rev['content'] ?? '{}', true) ?: [];
            $items[] = [
                'id'         => (int) $rev['id'],
                'changed_by' => $rev['changed_by'],
                'created_at' => $rev['created_at'],
                'summary'    => $this->buildRevisionSummary($revContent, $currentContent),
            ];
        }

        Response::json([
            'success'   => true,
            'revisions' => $items,
            'count'     => count($items),
        ]);
    }

    /**
     * Restore a section from a specific revision.
     * POST /admin/pagebuilder/section/{id}/restore/{revisionId} (AJAX)
     */
    public function restoreRevision(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);
        $revisionId = (int) ($params['revisionId'] ?? 0);

        $section = PageSection::find($id);
        if (!$section) {
            Response::json(['success' => false, 'message' => 'Section not found.'], 404);
            return;
        }

        $revision = SectionRevision::find($revisionId);
        if (!$revision || (int) $revision['section_id'] !== $id) {
            Response::json(['success' => false, 'message' => 'Revision not found.'], 404);
            return;
        }

        // Store current content as a new revision before restoring
        $changedBy = $this->auth()->userId();
        SectionRevision::store($id, $section['content'] ?? '{}', $changedBy);

        // Restore the revision content
        PageSection::updateById($id, [
            'content'    => $revision['content'],
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        Response::json([
            'success' => true,
            'message' => __('admin.pagebuilder.revision_restored'),
        ]);
    }

    // =========================================================================
    // Private helpers
    // =========================================================================

    /**
     * Render a single section card (for AJAX responses).
     */
    private function renderSectionCard(array $section, bool $expanded = false): string
    {
        $reg = SectionRegistry::get($section['section_type']);
        $csrf = $this->csrf();
        $data = $section['data'] ?? [];

        ob_start();
        include $this->resolvePath('admin/views/pagebuilder/section-card.php');
        return ob_get_clean();
    }

    /**
     * Render a section's edit form.
     */
    private function renderSectionForm(array $section): string
    {
        $data = $section['data'] ?? [];
        $csrf = $this->csrf();
        $typeKey = $section['section_type'];
        $basePath = $this->appBasePath();

        // Core form (primary source of form fields)
        $coreForm = $basePath . '/admin/views/sections/' . $typeKey . '.php';

        // Plugin form (section provides its own admin view via adminFormBasePath())
        $pluginForm = null;
        $reg = \App\Sections\SectionRegistry::get($typeKey);
        if ($reg) {
            $pluginBasePath = $reg->adminFormBasePath();
            if ($pluginBasePath !== null) {
                $pluginForm = $basePath . '/' . $pluginBasePath . '/' . $typeKey . '.php';
                if (!file_exists($pluginForm)) {
                    $pluginForm = null;
                }
            }
        }

        // Theme form (full replacement or extra fields)
        $theme = $this->app->service('view')->activeTheme();
        $themeForm = $basePath . '/themes/' . $theme . '/admin/sections/' . $typeKey . '.php';
        $hasThemeForm = file_exists($themeForm);

        // Theme forms marked with @theme-form-mode: replace are full replacements
        // (e.g. hero.php with premium-specific layout options).
        // All others are extras appended after the core form.
        if ($hasThemeForm && $this->isThemeFormReplacement($themeForm)) {
            ob_start();
            include $themeForm;
            return ob_get_clean();
        }

        // Resolve primary form: core → plugin fallback
        $primaryForm = file_exists($coreForm) ? $coreForm : $pluginForm;

        if (!$primaryForm) {
            // No core or plugin form – only theme form or empty
            if ($hasThemeForm) {
                ob_start();
                include $themeForm;
                return ob_get_clean();
            }
            return '';
        }

        ob_start();
        include $primaryForm;

        // Append premium theme extra fields (e.g. surface/atmosphere)
        if ($hasThemeForm) {
            include $themeForm;
        }

        return ob_get_clean();
    }

    /**
     * Check if a theme form file is a full replacement (not just extras).
     * Detected by @theme-form-mode: replace marker in the file's docblock.
     */
    private function isThemeFormReplacement(string $filePath): bool
    {
        $head = file_get_contents($filePath, false, null, 0, 512);
        return $head !== false && str_contains($head, '@theme-form-mode: replace');
    }

    /**
     * Get application base path.
     */
    private function appBasePath(): string
    {
        return defined('BASE_PATH') ? BASE_PATH : dirname(__DIR__, 4);
    }

    /**
     * Resolve a path relative to base path.
     */
    private function resolvePath(string $relativePath): string
    {
        return $this->appBasePath() . '/' . $relativePath;
    }

    /**
     * Build a short summary of what changed between revision and current content.
     */
    private function buildRevisionSummary(array $revContent, array $currentContent): string
    {
        $changed = 0;
        $added   = 0;
        $removed = 0;

        $allKeys = array_unique(array_merge(array_keys($revContent), array_keys($currentContent)));

        foreach ($allKeys as $key) {
            $inRev = array_key_exists($key, $revContent);
            $inCur = array_key_exists($key, $currentContent);

            if ($inRev && !$inCur) {
                $removed++;
            } elseif (!$inRev && $inCur) {
                $added++;
            } elseif ($revContent[$key] !== $currentContent[$key]) {
                $changed++;
            }
        }

        $parts = [];
        if ($changed > 0) {
            $parts[] = $changed . ' ' . ($changed === 1 ? __('admin.pagebuilder.rev_field_changed') : __('admin.pagebuilder.rev_fields_changed'));
        }
        if ($added > 0) {
            $parts[] = $added . ' ' . __('admin.pagebuilder.rev_fields_added');
        }
        if ($removed > 0) {
            $parts[] = $removed . ' ' . __('admin.pagebuilder.rev_fields_removed');
        }

        return $parts ? implode(', ', $parts) : __('admin.pagebuilder.rev_no_changes');
    }

    /**
     * Resolve page_context from route parameters or request input.
     *
     * Priority: route params (dedicated routes) → request input (AJAX fallback) → homepage default
     *
     * Supported formats:
     *   - 'homepage'    (default)
     *   - 'page:{id}'   (static page)
     *   - 'blog:{id}'   (blog post)
     */
    private function resolveContext(Request $request, array $params = []): string
    {
        // 1. Explicit context from POST/GET data (AJAX requests send this)
        $ctx = trim($request->input('context', '') ?: ($request->query('context', '') ?: ''));
        if ($ctx !== '' && $ctx !== 'homepage') {
            if (preg_match('/^(page|blog):(\d+)$/', $ctx)) {
                return $ctx;
            }
        }

        // 2. Dedicated routes: /admin/pages/{id}/pagebuilder or /admin/blog/{id}/pagebuilder
        $id = (int) ($params['id'] ?? 0);
        if ($id > 0) {
            $uri = $_SERVER['REQUEST_URI'] ?? '';
            if (str_contains($uri, '/pages/')) {
                return 'page:' . $id;
            }
            if (str_contains($uri, '/blog/')) {
                return 'blog:' . $id;
            }
        }

        return 'homepage';
    }

    /**
     * Build display metadata for a page_context.
     * Returns title, back URL, and context label for the admin UI.
     */
    private function contextMeta(string $context): array
    {
        $meta = [
            'context'  => $context,
            'title'    => __('admin.nav.pagebuilder'),
            'backUrl'  => admin_url(''),
            'backLabel'=> __('admin.nav.dashboard'),
            'label'    => 'Homepage',
        ];

        if (preg_match('/^page:(\d+)$/', $context, $m)) {
            $page = \App\Models\Page::find((int) $m[1]);
            if ($page) {
                $meta['title']    = __('admin.nav.pagebuilder') . ': ' . ($page['title'] ?? 'Page #' . $m[1]);
                $meta['backUrl']  = admin_url('pages/edit/' . $m[1]);
                $meta['backLabel']= $page['title'] ?? __('admin.nav.pages');
                $meta['label']    = $page['title'] ?? 'Page #' . $m[1];
            }
        } elseif (preg_match('/^blog:(\d+)$/', $context, $m)) {
            $post = \App\Models\BlogPost::find((int) $m[1]);
            if ($post) {
                $meta['title']    = __('admin.nav.pagebuilder') . ': ' . ($post['title'] ?? 'Post #' . $m[1]);
                $meta['backUrl']  = admin_url('blog/edit/' . $m[1]);
                $meta['backLabel']= $post['title'] ?? __('admin.nav.blog');
                $meta['label']    = $post['title'] ?? 'Post #' . $m[1];
            }
        }

        return $meta;
    }
}
