<?php
/**
 * 闂傚倻鍘ч幖顐︻敄閸涙潙桅闁硅法鍏係
 * ============================================================================
 * 闂傚倸鍠涚紞鈧繛鎾崇秺楠炲骞嬮敂钘夆偓鐢告偡濞嗗繐顏悗?016-2028 闂佺绻堥崝鎴濃枍閻旂厧鍌ㄥ璺烘憸椤撳鏌熼崹顐€块柛瀣功缁辨棃骞嬮悩鍨礋闂佸搫鐗嗙粔瀛樻叏閻旂厧瀚夊鑸靛姈椤庢瑩鏌涜箛锝呭鐎垫澘鍟撮弫宥囦沪閸婄喎鐝繛锝呮处缁诲嫰寮抽埀顒勬煙绾版ê浜鹃梺鍝勭墕椤︽澘顭囬崼銉ョ闁?#8203;閸?
 * 缂傚倸鍟崹褰掓偟椤栫偛鎹堕柡澶嬪缁? http://www.yutoucms.cn
 * ----------------------------------------------------------------------------
 * 婵犵鈧啿鈧綊鎮樻径鎰柈闁糕剝娲滈悷褰掓煟椤剙濮傞柍褜鍓氶弻銊︽叏閻旇崵鐤€闁告侗鍘奸悡鍌炴倵鐟欏媶鎴﹀蓟閻旂儤瀚绘い鎾寸箖鐎氳櫕鎱ㄥ┑鎾舵偧濠⒀勵殜楠炴帡宕奸悢鍝ョК, 婵炲濮伴崕閬嶅储閵堝拋鍤曢柡鍥ｅ墲瀹曞啿鈽夐幘宕囆㈢紒鐑╁亾闁荤喐娲戦懗璺衡枔閹存績鏋栭柡鍥╁仧娴兼劗绱掗崜褍啸闁?
 * ============================================================================
 * Author: 闂傚倻鍘ч幖顐︻敄?<mxgsf@qq.com>
 * Date: 2026-5-20
 */

require_once dirname(__DIR__) . '/core/lib/session.php';
cmsStartSession();

define('ROOT_PATH', dirname(__FILE__) . '/../');
define('CORE_PATH', ROOT_PATH . 'core/');
define('PUBLIC_PATH', ROOT_PATH . 'public/');

require_once CORE_PATH . 'db/db.php';
$db = \Core\Db\DB::getInstance();

require_once CORE_PATH . 'lib/common.php';
require_once CORE_PATH . 'lib/scheduled_publisher.php';
require_once CORE_PATH . 'lib/redirect_manager.php';
require_once CORE_PATH . 'lib/online_service.php';

cmsMaybePublishScheduledArticles($db, 60);

trackPageView();

$configs = $db->fetchAll("SELECT config_key, config_value FROM {$db->table('config')}");
$siteConfig = [];
foreach ($configs as $cfg) {
    $siteConfig[$cfg['config_key']] = $cfg['config_value'];
}

$requestUri = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : '/';
$requestPath = (string) parse_url($requestUri, PHP_URL_PATH);
$indexNowKey = trim((string) ($siteConfig['indexnow_key'] ?? ''));

if ($requestPath === '/sitemap.xml') {
    header('Content-Type: application/xml; charset=UTF-8');
    echo cmsGenerateSitemapXml();
    exit;
}

if ($requestPath === '/robots.txt') {
    header('Content-Type: text/plain; charset=UTF-8');
    echo cmsGenerateRobotsTxt();
    exit;
}

if ($indexNowKey !== '' && $requestPath === '/' . $indexNowKey . '.txt') {
    header('Content-Type: text/plain; charset=UTF-8');
    echo $indexNowKey;
    exit;
}

$managedRedirect = cmsFindRedirect($db, $requestUri);
if ($managedRedirect) {
    header('Location: ' . $managedRedirect['target'], true, $managedRedirect['status_code']);
    exit;
}

$site_status = isset($siteConfig['site_status']) ? $siteConfig['site_status'] : '';
if ($site_status === 'close') {
    $isAdminRequest = (strpos($_SERVER['REQUEST_URI'], '/admin/') === 0 || strpos($_SERVER['REQUEST_URI'], '/admin') === 0);
    $isAdminLogin = $isAdminRequest && isset($_SESSION['admin_id']) && $_SESSION['admin_id'] > 0;
    if (!$isAdminLogin) {
        echo '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Website Maintenance</title>';
        echo '<style>body{font-family:Arial;text-align:center;padding:100px 20px;background:#667eea;min-height:100vh;display:flex;align-items:center;justify-content:center;}';
        echo '.container{background:rgba(255,255,255,0.95);padding:60px;border-radius:24px;max-width:500px;box-shadow:0 25px 50px rgba(0,0,0,0.3);}';
        echo 'h2{color:#1e293b;margin-bottom:20px;font-size:24px;}';
        echo 'p{color:#64748b;line-height:1.8;font-size:16px;}';
        echo '.admin-link{display:inline-block;margin-top:30px;padding:14px 28px;background:linear-gradient(135deg,#667eea,#764ba2);';
        echo 'color:#fff;text-decoration:none;border-radius:12px;font-weight:600;transition:all 0.3s;}';
        echo '.admin-link:hover{transform:translateY(-2px);box-shadow:0 8px 25px rgba(102,126,234,0.4);}';
        echo '</style></head><body>';
        echo '<div class="container">';
        echo '<h2>Maintenance</h2>';
        echo '<p>' . nl2br(htmlspecialchars($siteConfig['site_close_msg'] ?? 'Site is under maintenance, please come back later...')) . '</p>';
        echo '<a href="/admin/login.php" class="admin-link">Admin Login</a>';
        echo '</div></body></html>';
        exit;
    }
}

$urlMode = $siteConfig['url_mode'] ?? 'dynamic';
$rewriteAuto = cmsBoolConfigEnabled('rewrite_auto_enabled', false);
$hasExplicitModule = isset($_GET['m']) && trim((string) $_GET['m']) !== '';

if ($urlMode === 'dynamic' || $hasExplicitModule) {
    $module = isset($_GET['m']) ? trim($_GET['m']) : 'index';
    $action = isset($_GET['a']) ? trim($_GET['a']) : 'index';
    $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
    $keyword = isset($_GET['keyword']) ? trim($_GET['keyword']) : '';
    $channelDir = isset($_GET['dir']) ? trim($_GET['dir']) : '';

    $module = preg_replace('/[^a-z0-9_]/i', '', $module);
    $action = preg_replace('/[^a-z0-9_]/i', '', $action);
    $channelDir = preg_replace('/[^a-z0-9_\-]/i', '', $channelDir);
    if ($rewriteAuto && $module === 'index' && empty($_GET['m'])) {
        $route = cmsResolveStaticRoute(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/');
        $module = $route['module'];
        $action = $route['action'];
        $id = intval($route['id']);
        $keyword = (string) $route['keyword'];
        $channelDir = (string) $route['dir'];
    }
} else {
    $route = cmsResolveStaticRoute(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/');
    $module = $route['module'];
    $action = $route['action'];
    $id = intval($route['id']);
    $keyword = (string) $route['keyword'];
    $channelDir = (string) $route['dir'];
}

$rawPathIsUnknown = !$hasExplicitModule && $module === 'index' && !in_array(rtrim($requestPath, '/'), ['', '/index.php', '/public/index.php'], true);
if ($rawPathIsUnknown || !cmsFrontendRouteExists($db, $module, $id, $channelDir)) {
    cmsRecordNotFound($db, $requestUri, $_SERVER);
    http_response_code(404);
    $notFoundTemplate = ROOT_PATH . 'template/' . ($siteConfig['site_template'] ?? 'default') . '/404.html';
    if (is_file($notFoundTemplate)) { include $notFoundTemplate; }
    else { echo '<!doctype html><html lang="zh-CN"><meta charset="utf-8"><title>页面未找到</title><body style="font-family:Microsoft YaHei,sans-serif;text-align:center;padding:12vh 20px;color:#334155"><h1>404</h1><p>您访问的页面不存在或已下线。</p><a href="/">返回首页</a></body></html>'; }
    exit;
}

$_GET['m'] = $module;
$_GET['a'] = $action;
if ($id > 0) {
    $_GET['id'] = $id;
} elseif (isset($_GET['id'])) {
    unset($_GET['id']);
}
if ($keyword !== '') {
    $_GET['keyword'] = $keyword;
}
if ($channelDir !== '') {
    $_GET['dir'] = $channelDir;
}

require_once CORE_PATH . 'lib/common.php';

require_once CORE_PATH . 'lib/license.php';
require_once CORE_PATH . 'lib/template_loader.php';
require_once CORE_PATH . 'lib/builder.php';
require_once CORE_PATH . 'lib/builder_renderer.php';
require_once CORE_PATH . 'lib/builder_components.php';
require_once CORE_PATH . 'lib/builder_frontend_overlay.php';
$license = new \Core\Lib\License();
$licenseStatus = $license->getStatus();
$canRemoveCopyright = $license->canRemoveCopyright();
$templateLoader = new \Core\Lib\TemplateLoader($license);
$builder = new \Core\Lib\Builder($db);
$activeTemplateKey = $templateLoader->resolveUsableTemplate($siteConfig['site_template'] ?? 'default', $db);

$site = $siteConfig;
$site['template_dir'] = '/template/' . $activeTemplateKey . '/';
$site['template_path'] = ROOT_PATH . 'template/' . $activeTemplateKey . '/';
$site['public_dir'] = '/public/';
$site['url_mode'] = $urlMode;
$onlineServiceHtml = cmsOnlineServiceRender(cmsOnlineServiceLoad($db, $site));
$canUseBuilder = $license->canUseBuilder();
$isAdminFrontendSession = !empty($_SESSION['admin_id']);
$builderEditRequested = !empty($_GET['builder_edit']) && intval($_GET['builder_edit']) === 1;
$builderEditType = $builder->normalizePageType($_GET['builder_type'] ?? 'home');
$builderEditRefId = intval($_GET['builder_ref_id'] ?? 0);
$builderAccessToken = trim((string) ($_GET['builder_token'] ?? ''));
$hasBuilderAccessToken = cmsVerifyBuilderAccessToken($builderAccessToken, $builderEditType, $builderEditRefId);
$isBuilderEditMode = $canUseBuilder
    && ($isAdminFrontendSession || $hasBuilderAccessToken)
    && $builderEditRequested;
$builderEditLayout = null;
$builderEditBlockedReason = '';
if ($isBuilderEditMode) {
    $builderDraftPage = $builder->getDraftByType($builderEditType, $builderEditRefId);
    $builderEditLayout = $builderDraftPage && isset($builderDraftPage['layout']) && is_array($builderDraftPage['layout'])
        ? $builderDraftPage['layout']
        : $builder->getDefaultLayout($siteConfig['site_name'] ?? '网站首页');
} elseif ($builderEditRequested) {
    if (!$canUseBuilder) {
        $builderEditBlockedReason = '模板装修功能仅限专业版使用。';
    } elseif (!$isAdminFrontendSession && !$hasBuilderAccessToken) {
        $builderEditBlockedReason = '当前前台页面未检测到后台管理员登录会话，请先登录后台后再进入模板装修。';
    }
}

function getChannelRedirectUrl($channel) {
    if (!is_array($channel)) {
        return '';
    }
    if (intval($channel['channel_type'] ?? 0) === 3) {
        return '';
    }
    $redirectUrl = isset($channel['redirect_url']) ? trim($channel['redirect_url']) : '';
    return $redirectUrl;
}

function getChannelUrlById($id, $dir = '') {
    global $db, $urlMode;
    $id = intval($id);
    if ($id > 0) {
        $channel = $db->fetch("SELECT id, channel_dir, channel_type, redirect_url FROM {$db->table('channel')} WHERE id = ?", [$id]);
        $redirectUrl = getChannelRedirectUrl($channel);
        if ($redirectUrl !== '') {
            return $redirectUrl;
        }
        if (empty($dir) && $channel && isset($channel['channel_dir'])) {
            $dir = $channel['channel_dir'];
        }
    }

    if ($urlMode === 'dynamic') {
        return '/public/index.php?m=channel&id=' . $id;
    }

    return $dir ? '/' . trim($dir, '/') . '/' : '/channel/' . $id . '/';
}

function getUrl($type, $id = 0, $dir = '') {
    global $urlMode, $siteConfig;
    $base = rtrim($siteConfig['site_url'] ?? 'http://' . $_SERVER['HTTP_HOST'], '/');

    if ($type === 'page' && intval($id) <= 0) {
        global $db;
        $pageRow = $db->fetch("SELECT id FROM {$db->table('page')} WHERE status = 1 ORDER BY sort_order ASC, id ASC LIMIT 1");
        $id = intval($pageRow['id'] ?? 0);
        if ($id <= 0) {
            return cmsRewriteModeEnabled() ? '/' : '/public/index.php?m=index';
        }
    }

    if (!cmsRewriteModeEnabled()) {
        switch ($type) {
            case 'home': return '/public/index.php?m=index';
            case 'channel': return getChannelUrlById($id, $dir);
            case 'product': return $id > 0 ? '/public/index.php?m=product&id=' . $id : '/public/index.php?m=product';
            case 'article': return $id > 0 ? '/public/index.php?m=article&id=' . $id : '/public/index.php?m=article';
            case 'search': return '/public/index.php?m=search';
            case 'guestbook': return '/public/index.php?m=guestbook';
            case 'page': return '/public/index.php?m=page&id=' . $id;
            case 'image': return $id > 0 ? '/public/index.php?m=image&id=' . $id : '/public/index.php?m=image';
            case 'download': return $id > 0 ? '/public/index.php?m=download&id=' . $id : '/public/index.php?m=download';
            case 'video': return $id > 0 ? '/public/index.php?m=video&id=' . $id : '/public/index.php?m=video';
            case 'recruit': return $id > 0 ? '/public/index.php?m=recruit&id=' . $id : '/public/index.php?m=recruit';
            default: return '/public/index.php';
        }
    } else {
        switch ($type) {
            case 'home': return '/';
            case 'channel': return getChannelUrlById($id, $dir);
            case 'article': return $id > 0 ? '/article/' . $id . '.html' : '/article/';
            case 'product': return $id > 0 ? '/product/' . $id . '.html' : '/product/';
            case 'search': return '/search/';
            case 'guestbook': return '/guestbook/';
            case 'image': return $id > 0 ? '/image/' . $id . '.html' : '/image/';
            case 'download': return $id > 0 ? '/download/' . $id . '.html' : '/download/';
            case 'video': return $id > 0 ? '/video/' . $id . '.html' : '/video/';
            case 'recruit': return $id > 0 ? '/recruit/' . $id . '.html' : '/recruit/';
            case 'page': return '/page/' . $id . '.html';
            default: return '/';
        }
    }
}

function cmsResolveChannelBuilderTarget(array $channel)
{
    global $db;

    $channelId = intval($channel['id'] ?? 0);
    $channelType = intval($channel['channel_type'] ?? 0);
    $targetType = '';
    $targetRefId = 0;

    if ($channelId <= 0) {
        return ['supported' => false, 'type' => '', 'ref_id' => 0];
    }

    if ($channelType === 1) {
        $targetType = 'article_list';
    } elseif ($channelType === 2) {
        $targetType = 'product_list';
    } elseif ($channelType === 3) {
        $pageRow = $db->fetch(
            "SELECT id FROM {$db->table('page')} WHERE channel_id = ? AND status = 1 ORDER BY id DESC LIMIT 1",
            [$channelId]
        );
        $targetRefId = intval($pageRow['id'] ?? 0);
        if ($targetRefId > 0) {
            $targetType = 'page';
        }
    } elseif ($channelType === 4) {
        $targetType = 'image_list';
    } elseif ($channelType === 5) {
        $targetType = 'download_list';
    } elseif ($channelType === 7) {
        $targetType = 'video_list';
    } elseif ($channelType === 9) {
        $targetType = 'recruit_list';
    }

    return [
        'supported' => $targetType !== '',
        'type' => $targetType,
        'ref_id' => $targetRefId,
    ];
}

function cmsResolveRequestBuilderTarget($module, $id = 0)
{
    global $db;

    $module = trim((string) $module);
    $id = intval($id);
    $type = null;
    $refId = 0;

    if ($module === 'page' && $id > 0) {
        $type = 'page';
        $refId = $id;
    } elseif ($module === 'channel' && $id > 0) {
        $channel = $db->fetch(
            "SELECT id, channel_type, channel_dir, redirect_url FROM {$db->table('channel')} WHERE id = ? LIMIT 1",
            [$id]
        );
        $channelTarget = $channel ? cmsResolveChannelBuilderTarget($channel) : ['supported' => false];
        if (!empty($channelTarget['supported'])) {
            $type = (string) $channelTarget['type'];
            $refId = intval($channelTarget['ref_id'] ?? 0);
        }
    } elseif ($module === 'article') {
        $type = $id > 0 ? 'article_detail' : 'article_list';
        $refId = $id > 0 ? $id : 0;
    } elseif ($module === 'product') {
        $type = $id > 0 ? 'product_detail' : 'product_list';
        $refId = $id > 0 ? $id : 0;
    } elseif ($module === 'image') {
        $type = $id > 0 ? 'image_detail' : 'image_list';
        $refId = $id > 0 ? $id : 0;
    } elseif ($module === 'download') {
        $type = $id > 0 ? 'download_detail' : 'download_list';
        $refId = $id > 0 ? $id : 0;
    } elseif ($module === 'video') {
        $type = $id > 0 ? 'video_detail' : 'video_list';
        $refId = $id > 0 ? $id : 0;
    } elseif ($module === 'recruit') {
        $type = $id > 0 ? 'recruit_detail' : 'recruit_list';
        $refId = $id > 0 ? $id : 0;
    } elseif ($module === 'index' || $module === '') {
        $type = 'home';
    }

    return [
        'supported' => $type !== null,
        'type' => $type,
        'ref_id' => $refId,
    ];
}

if (!function_exists('cmsBuilderTargetMatchesRequest')) {
    function cmsBuilderTargetMatchesRequest($builderPageType, $builderRefId, $module, $id)
    {
        $builderPageType = trim((string) $builderPageType);
        $module = trim((string) $module);
        $id = intval($id);
        $builderRefId = intval($builderRefId);

        $map = [
            'article_list' => ['module' => 'article', 'detail' => false],
            'article_detail' => ['module' => 'article', 'detail' => true],
            'product_list' => ['module' => 'product', 'detail' => false],
            'product_detail' => ['module' => 'product', 'detail' => true],
            'image_list' => ['module' => 'image', 'detail' => false],
            'image_detail' => ['module' => 'image', 'detail' => true],
            'download_list' => ['module' => 'download', 'detail' => false],
            'download_detail' => ['module' => 'download', 'detail' => true],
            'video_list' => ['module' => 'video', 'detail' => false],
            'video_detail' => ['module' => 'video', 'detail' => true],
            'recruit_list' => ['module' => 'recruit', 'detail' => false],
            'recruit_detail' => ['module' => 'recruit', 'detail' => true],
            'page' => ['module' => 'page', 'detail' => true],
            'home' => ['module' => 'index', 'detail' => false],
        ];

        if (!isset($map[$builderPageType])) {
            return false;
        }

        $target = $map[$builderPageType];
        if ($target['module'] !== $module && !($target['module'] === 'index' && $module === '')) {
            return false;
        }

        if ($target['detail']) {
            return $id > 0 && ($builderRefId === 0 || $builderRefId === $id);
        }

        return $id <= 0;
    }
}

function cmsBuildBuilderEntryUrl($builderType, $refId = 0, $fallbackUrl = '')
{
    $builderType = trim((string) $builderType);
    $refId = intval($refId);
    if ($builderType === '') {
        return '';
    }

    $baseUrl = trim((string) $fallbackUrl);
    if ($baseUrl === '') {
        $baseUrl = cmsResolveBuilderFrontendUrl($builderType, $refId, cmsBuildFrontendUrl('home'));
    }
    $params = [
        'builder_edit' => 1,
        'builder_type' => $builderType,
        'builder_ref_id' => $refId,
        'builder_token' => cmsBuildBuilderAccessToken($builderType, $refId, time() + 7200),
    ];

    return $baseUrl . (strpos($baseUrl, '?') !== false ? '&' : '?') . http_build_query($params);
}

function cmsCollectBuilderColumnLinks()
{
    global $db;

    $links = [];
    $seen = [];
    $addLink = function ($label, $url, $editUrl, $builderType, $refId) use (&$links, &$seen) {
        $url = trim((string) $url);
        $editUrl = trim((string) $editUrl);
        if ($url === '' || $editUrl === '' || isset($seen[$url])) {
            return;
        }
        $seen[$url] = true;
        $links[] = [
            'label' => (string) $label,
            'url' => $url,
            'edit_url' => $editUrl,
            'builder_type' => (string) $builderType,
            'builder_ref_id' => intval($refId),
        ];
    };

    $homeUrl = cmsBuildFrontendUrl('home');
    $addLink('首页', $homeUrl, cmsBuildBuilderEntryUrl('home', 0, $homeUrl), 'home', 0);

    $channels = $db->fetchAll(
        "SELECT id, channel_name, channel_type, channel_dir, redirect_url
         FROM {$db->table('channel')}
         WHERE status = 1 AND is_show = 1
         ORDER BY list_order ASC, id ASC"
    );
    foreach ($channels as $channel) {
        $target = cmsResolveChannelBuilderTarget($channel);
        if (empty($target['supported'])) {
            continue;
        }
        $channelUrl = cmsBuildChannelUrl($channel);
        $addLink(
            (string) ($channel['channel_name'] ?? ('栏目' . intval($channel['id'] ?? 0))),
            $channelUrl,
            cmsBuildBuilderEntryUrl((string) $target['type'], intval($target['ref_id'] ?? 0), $channelUrl),
            (string) $target['type'],
            intval($target['ref_id'] ?? 0)
        );
    }

    $pages = $db->fetchAll("SELECT id, page_title FROM {$db->table('page')} WHERE status = 1 ORDER BY id ASC");
    foreach ($pages as $page) {
        $pageId = intval($page['id'] ?? 0);
        if ($pageId <= 0) {
            continue;
        }
        $pageUrl = cmsBuildFrontendUrl('page', $pageId);
        $addLink(
            (string) ($page['page_title'] ?? ('单页' . $pageId)),
            $pageUrl,
            cmsBuildBuilderEntryUrl('page', $pageId, $pageUrl),
            'page',
            $pageId
        );
    }

    return $links;
}

$channels = $db->fetchAll("SELECT * FROM {$db->table('channel')} WHERE parent_id = 0 AND is_show = 1 ORDER BY list_order ASC, id ASC");
$slides = $db->fetchAll("SELECT * FROM {$db->table('slide')} WHERE status = 1 ORDER BY sort_order ASC, id DESC LIMIT 5");
$topArticles = $db->fetchAll("SELECT a.*, c.channel_name FROM {$db->table('article')} a LEFT JOIN {$db->table('channel')} c ON a.channel_id = c.id WHERE a.status = 1 AND a.flag LIKE '%top%' ORDER BY a.create_time DESC LIMIT 5");
$latestArticles = $db->fetchAll("SELECT a.*, c.channel_name FROM {$db->table('article')} a LEFT JOIN {$db->table('channel')} c ON a.channel_id = c.id WHERE a.status = 1 ORDER BY a.create_time DESC LIMIT 10");
$latestProducts = $db->fetchAll("SELECT * FROM {$db->table('product')} WHERE status = 1 ORDER BY create_time DESC LIMIT 8");
$links = $db->fetchAll("SELECT * FROM {$db->table('link')} WHERE status = 1 ORDER BY sort_order ASC, id DESC");
$frontendPublishedLayout = null;
$frontendPublishedType = 'home';
$frontendPublishedRefId = 0;

$templateDir = ROOT_PATH . 'template/' . $activeTemplateKey . '/';

if ($canUseBuilder && !$isBuilderEditMode && ($module === 'index' || $module === '')) {
    $homeLayout = $builder->getLayoutByType('home', 0);
    if (is_array($homeLayout)) {
        if (($homeLayout['page']['render_mode'] ?? '') === 'frontend_template') {
            $frontendPublishedLayout = $homeLayout;
            $frontendPublishedType = 'home';
            $frontendPublishedRefId = 0;
        } else {
            $renderer = new \Core\Lib\BuilderRenderer($db, $site);
            ob_start();
            $renderer->render($homeLayout, ['module' => 'index']);
            echo cmsInjectOnlineService(ob_get_clean(), $onlineServiceHtml);
            exit;
        }
    }
}

if ($canUseBuilder && !$isBuilderEditMode) {
    $builderTarget = cmsResolveRequestBuilderTarget($module, $id);
    if (!empty($builderTarget['supported'])) {
        $builderPageType = (string) $builderTarget['type'];
        $builderRefId = intval($builderTarget['ref_id'] ?? 0);
        $builderLayout = $builder->getLayoutByType($builderPageType, $builderRefId);
        if (is_array($builderLayout) && cmsBuilderTargetMatchesRequest($builderPageType, $builderRefId, $module, $id)) {
            if (($builderLayout['page']['render_mode'] ?? '') === 'frontend_template') {
                $frontendPublishedLayout = $builderLayout;
                $frontendPublishedType = $builderPageType;
                $frontendPublishedRefId = $builderRefId;
            } else {
                $renderer = new \Core\Lib\BuilderRenderer($db, $site);
                ob_start();
                $renderer->render($builderLayout, ['module' => $module, 'id' => $id]);
                echo cmsInjectOnlineService(ob_get_clean(), $onlineServiceHtml);
                exit;
            }
        }
    }
}

if (empty($module)) {
    $module = 'index';
}

if ($module === 'channel' && $id > 0) {
    $redirectChannel = $db->fetch("SELECT id, channel_type, redirect_url FROM {$db->table('channel')} WHERE id = ? AND is_show = 1", [$id]);
    $redirectUrl = getChannelRedirectUrl($redirectChannel);
    if ($redirectUrl !== '') {
        header('Location: ' . $redirectUrl);
        exit;
    }
}

if ($module === 'channel' && $id <= 0 && !empty($channelDir)) {
    $channelByDir = $db->fetch("SELECT id, channel_type, redirect_url FROM {$db->table('channel')} WHERE channel_dir = ? AND is_show = 1 LIMIT 1", [$channelDir]);
    if ($channelByDir) {
        $id = intval($channelByDir['id'] ?? 0);
        $redirectUrl = getChannelRedirectUrl($channelByDir);
        if ($redirectUrl !== '') {
            header('Location: ' . $redirectUrl);
            exit;
        }
    }
}

if ($module === 'channel' && $id > 0) {
    $channelForPage = $db->fetch("SELECT id, channel_type FROM {$db->table('channel')} WHERE id = ? AND is_show = 1 LIMIT 1", [$id]);
    if (intval($channelForPage['channel_type'] ?? 0) === 3) {
        $pageRow = $db->fetch(
            "SELECT id FROM {$db->table('page')} WHERE channel_id = ? AND status = 1 ORDER BY sort_order ASC, id ASC LIMIT 1",
            [$id]
        );
        $pageId = intval($pageRow['id'] ?? 0);
        if ($pageId > 0) {
            $module = 'page';
            $id = $pageId;
            $_GET['m'] = 'page';
            $_GET['id'] = $pageId;
        }
    }
}

switch ($module) {
    case 'article':
        $tplFile = $id > 0 ? $templateDir . 'article/article.html' : $templateDir . 'article/list.html';
        break;
    case 'product':
        $tplFile = $id > 0 ? $templateDir . 'product/article.html' : $templateDir . 'product/list.html';
        break;
    case 'channel':
        $tplFile = $templateDir . 'channel/list.html';
        break;
    case 'image':
        $tplFile = $id > 0 ? $templateDir . 'image.html' : $templateDir . 'channel/list.html';
        break;
    case 'search':
        $tplFile = $templateDir . 'search.html';
        break;
    case 'guestbook':
        $tplFile = $templateDir . 'guestbook.html';
        break;
    case 'page':
        $tplFile = ($id > 0) ? $templateDir . 'page.html' : $templateDir . 'channel/list.html';
        break;
    case 'download':
        $tplFile = $id > 0 ? $templateDir . 'download.html' : $templateDir . 'channel/list.html';
        break;
    case 'video':
        $tplFile = $id > 0 ? $templateDir . 'video.html' : $templateDir . 'channel/list.html';
        break;
    case 'recruit':
        $tplFile = $id > 0 ? $templateDir . 'recruit.html' : $templateDir . 'channel/list.html';
        break;
    case 'cart':
        $tplFile = $templateDir . 'member/cart.html';
        break;
    default:
        $tplFile = $templateDir . 'index.html';
        break;
}

if (file_exists($tplFile)) {
    $builderOverlayHtml = '';
    if ($isBuilderEditMode || is_array($frontendPublishedLayout)) {
        $overlayLayout = $isBuilderEditMode ? $builderEditLayout : $frontendPublishedLayout;
        $overlayType = $isBuilderEditMode ? $builderEditType : $frontendPublishedType;
        $overlayRefId = $isBuilderEditMode ? $builderEditRefId : $frontendPublishedRefId;
        if (!$isBuilderEditMode && !cmsBuilderTargetMatchesRequest($overlayType, $overlayRefId, $module, $id)) {
            $overlayLayout = null;
        }
        if (is_array($overlayLayout)) {
            $builderOverlayHtml = cmsRenderFrontendBuilderOverlay([
                'edit_mode' => $isBuilderEditMode,
                'can_operate' => $canUseBuilder && ($isAdminFrontendSession || $hasBuilderAccessToken),
                'builder_type' => $overlayType,
                'builder_ref_id' => $overlayRefId,
                'builder_page_id' => $isBuilderEditMode ? intval($builderDraftPage['id'] ?? 0) : 0,
                'builder_version' => $isBuilderEditMode ? intval($builderDraftPage['version_no'] ?? 0) : 0,
                'builder_token' => $hasBuilderAccessToken ? $builderAccessToken : ($isBuilderEditMode ? cmsBuildBuilderAccessToken($overlayType, $overlayRefId, time() + 7200) : ''),
                'csrf_token' => getAdminCsrfToken(),
                'api_url' => '/admin/main.php?act=builder_api',
                'upload_url' => '/admin/main.php?act=upload',
                'exit_url' => cmsResolveBuilderFrontendUrl($overlayType, $overlayRefId, cmsBuildFrontendUrl('home')),
                'page_title' => (string) (($overlayLayout['page']['title'] ?? '') !== '' ? $overlayLayout['page']['title'] : ($siteConfig['site_name'] ?? '网站首页')),
                'layout' => $overlayLayout,
                'published_layout' => $isBuilderEditMode ? $builder->getLayoutByType($overlayType, $overlayRefId) : null,
                'default_layout' => $builder->getDefaultLayout((string) ($overlayLayout['page']['title'] ?? '页面装修')),
                'definitions' => \Core\Lib\BuilderComponents::getDefinitions(),
                'column_links' => cmsCollectBuilderColumnLinks(),
            ]);
        }
    }
    $GLOBALS['cmsBuilderFrontendOverlayHtml'] = $builderOverlayHtml;

    $builderEntryHtml = '';
    $builderBlockedNoticeHtml = '';
    if ($builderEditBlockedReason !== '') {
        $builderBlockedNoticeHtml = '<div data-cms-builder-blocked="1" style="position:fixed;left:50%;top:24px;transform:translateX(-50%);z-index:2147483646;width:min(860px,calc(100vw - 32px));padding:16px 18px;border-radius:18px;background:rgba(17,24,39,.96);color:#fff;box-shadow:0 20px 48px rgba(15,23,42,.26);font:500 14px/1.8 Microsoft YaHei,sans-serif;">'
            . '<div style="font-size:16px;font-weight:700;margin-bottom:6px;">模板装修</div>'
            . '<div>' . htmlspecialchars($builderEditBlockedReason, ENT_QUOTES, 'UTF-8') . '</div>'
            . '<div style="margin-top:10px;"><a href="/admin/login.php" target="_blank" rel="noopener" style="display:inline-flex;align-items:center;height:36px;padding:0 14px;border-radius:999px;background:#f97316;color:#fff;text-decoration:none;font-weight:700;">后台登录</a></div>'
            . '</div>';
    }
    if ($canUseBuilder && $isAdminFrontendSession && !$isBuilderEditMode) {
        $builderEntryTarget = cmsResolveRequestBuilderTarget($module, $id);
        $builderEntryType = !empty($builderEntryTarget['supported']) ? (string) $builderEntryTarget['type'] : 'home';
        $builderEntryId = !empty($builderEntryTarget['supported']) ? intval($builderEntryTarget['ref_id'] ?? 0) : 0;
        if ($module === 'page' && $id > 0) {
            $builderEntryType = 'page';
            $builderEntryId = $id;
        } elseif ($module === 'article') {
            $builderEntryType = $id > 0 ? 'article_detail' : 'article_list';
        } elseif ($module === 'product') {
            $builderEntryType = $id > 0 ? 'product_detail' : 'product_list';
        } elseif ($module === 'image') {
            $builderEntryType = $id > 0 ? 'image_detail' : 'image_list';
        } elseif ($module === 'download') {
            $builderEntryType = $id > 0 ? 'download_detail' : 'download_list';
        } elseif ($module === 'video') {
            $builderEntryType = $id > 0 ? 'video_detail' : 'video_list';
        } elseif ($module === 'recruit') {
            $builderEntryType = $id > 0 ? 'recruit_detail' : 'recruit_list';
        } elseif ($module === 'channel' && $id > 0) {
            $channelRow = $db->fetch("SELECT channel_type FROM {$db->table('channel')} WHERE id = ? LIMIT 1", [$id]);
            $channelType = intval($channelRow['channel_type'] ?? 0);
            if ($channelType === 1) {
                $builderEntryType = 'article_list';
            } elseif ($channelType === 2) {
                $builderEntryType = 'product_list';
            } elseif ($channelType === 4) {
                $builderEntryType = 'image_list';
            } elseif ($channelType === 5) {
                $builderEntryType = 'download_list';
            } elseif ($channelType === 7) {
                $builderEntryType = 'video_list';
            } elseif ($channelType === 9) {
                $builderEntryType = 'recruit_list';
            }
        }
        $currentPageUrl = ($module === 'channel' && $id > 0)
            ? getChannelUrlById($id)
            : getUrl($module === '' ? 'home' : $module, $id);
        $builderEntryUrl = cmsBuildBuilderEntryUrl($builderEntryType, $builderEntryId, $currentPageUrl);
        $builderEntryHtml = '<a data-cms-builder-entry="1" href="' . htmlspecialchars($builderEntryUrl, ENT_QUOTES, 'UTF-8') . '" style="position:fixed;right:24px;bottom:24px;z-index:2147483400;padding:12px 18px;border-radius:999px;background:#111827;color:#fff;text-decoration:none;font:600 14px/1 -apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;box-shadow:0 16px 36px rgba(15,23,42,.18);">模板装修</a>';
    }

    ob_start();
    include $tplFile;
    $renderedHtml = ob_get_clean();
    $injectHtml = '';
    if ($builderOverlayHtml !== '' && stripos($renderedHtml, 'id="cms_frontend_builder_root"') === false) {
        $injectHtml .= $builderOverlayHtml;
    }
    if ($builderBlockedNoticeHtml !== '' && stripos($renderedHtml, 'data-cms-builder-blocked="1"') === false) {
        $injectHtml .= $builderBlockedNoticeHtml;
    }
    if ($builderEntryHtml !== '' && stripos($renderedHtml, 'data-cms-builder-entry="1"') === false) {
        $injectHtml .= $builderEntryHtml;
    }
    if ($injectHtml !== '') {
        if (stripos($renderedHtml, '</body>') !== false) {
            $renderedHtml = preg_replace('/<\/body>/i', $injectHtml . '</body>', $renderedHtml, 1);
        } else {
            $renderedHtml .= $injectHtml;
        }
    }
    echo cmsInjectOnlineService($renderedHtml, $onlineServiceHtml);
} else {
    http_response_code(404);
    echo 'Template not found';
}
