<?php
/**
 * 炎酷CMS - 公共函数库
 * 配置读取、SEO 三级回退、URL 生成、数据调用、转义输出
 */
defined('YKCMS') or exit('Access Denied');

require_once __DIR__ . '/db.php';

/* ---------------- 配置 ---------------- */

/**
 * 读取站点配置（带静态缓存）
 * site_config()        返回全部配置数组
 * site_config('key')   返回单个值，不存在返回 $default
 */
function site_config($key = null, $default = '') {
    static $cfg = null;
    if ($cfg === null) {
        $cfg = array();
        foreach (db_all('SELECT ckey, cvalue FROM ' . DB_PREFIX . 'config') as $row) {
            $cfg[$row['ckey']] = $row['cvalue'];
        }
    }
    if ($key === null) return $cfg;
    return isset($cfg[$key]) && $cfg[$key] !== '' ? $cfg[$key] : $default;
}

/** 写入配置（不存在则新增） */
function config_set($key, $value) {
    db_exec('INSERT INTO ' . DB_PREFIX . 'config (ckey, cvalue) VALUES (?, ?)
             ON DUPLICATE KEY UPDATE cvalue = VALUES(cvalue)', array($key, $value));
}

/* ---------------- 输出与安全 ---------------- */

/** HTML 转义输出 */
function e($str) {
    return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
}

/** 裁剪纯文本摘要 */
function str_cut($str, $len = 100) {
    $str = trim(strip_tags((string)$str));
    return mb_strlen($str, 'UTF-8') > $len ? mb_substr($str, 0, $len, 'UTF-8') . '…' : $str;
}

/**
 * 裁剪富文本为纯文本摘要（过滤标签/图片/脚本样式，保留段落空行）
 * 用于首页「关于我们」模块调用单页内容
 */
function str_cut_br($html, $len = 120) {
    $html = (string)$html;
    // 去掉脚本/样式整块
    $html = preg_replace('#<(script|style)[^>]*>.*?</\1>#is', '', $html);
    // 块级闭合标签与 <br> 转换为换行，保留空行结构
    $html = preg_replace('#</(p|div|h[1-6]|li|ul|ol|blockquote|tr|section)\s*>#i', "\n", $html);
    $html = preg_replace('#<br\s*/?>#i', "\n", $html);
    $text = trim(strip_tags($html));
    // 解码 HTML 实体（&quot; &amp; &#039; 等），避免摘要出现实体乱码
    $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    $text = preg_replace('/[ \t\x{3000}]+/u', ' ', $text);
    $text = preg_replace("/ *\n+ */", "\n", $text);
    $text = preg_replace("/\n{3,}/", "\n\n", $text);
    if (mb_strlen($text, 'UTF-8') > $len) {
        $text = mb_substr($text, 0, $len, 'UTF-8') . '…';
    }
    return $text;
}

/** 时间格式化 */
function fdate($ts, $fmt = 'Y-m-d') {
    return $ts ? date($fmt, (int)$ts) : '';
}

/* ---------------- SEO 三级回退：文章/单页/栏目 > 全局 ---------------- */

/**
 * 输出 <title> 与 meta 标签
 * @param string $title 页面级 SEO 标题（空则回退全局）
 * @param string $keywords
 * @param string $description
 */
function seo_render($title = '', $keywords = '', $description = '') {
    $title       = $title       !== '' ? $title       : site_config('seo_title', '炎酷CMS演示站');
    $keywords    = $keywords    !== '' ? $keywords    : site_config('seo_keywords');
    $description = $description !== '' ? $description : site_config('seo_description');
    echo '<title>' . e($title) . '</title>' . "\n";
    echo '<meta name="keywords" content="' . e($keywords) . '">' . "\n";
    echo '<meta name="description" content="' . e($description) . '">' . "\n";
}

/* ---------------- URL 生成（伪静态开关 rewrite_on 控制） ---------------- */

/** 是否开启伪静态 */
function rewrite_on() {
    return site_config('rewrite_on', '0') === '1';
}

/** 栏目 id => flag 映射（静态缓存，伪静态目录式地址用） */
function col_flag_map() {
    static $map = null;
    if ($map === null) {
        $map = array();
        foreach (db_all("SELECT id, flag FROM " . DB_PREFIX . "column WHERE flag != ''") as $r) {
            $map[(int)$r['id']] = $r['flag'];
        }
    }
    return $map;
}

/**
 * 栏目地址：伪静态开启时优先 /{flag}/ 目录式（分页 /{flag}/2/），
 * 未填 flag 回退 /col-{id}.html；未开伪静态用动态地址
 */
function url_col($id, $page = 1) {
    $id = (int)$id;
    if (rewrite_on()) {
        $map = col_flag_map();
        if (isset($map[$id])) {
            return '/' . $map[$id] . '/' . ($page > 1 ? (int)$page . '/' : '');
        }
        return '/col-' . $id . ($page > 1 ? '-' . (int)$page : '') . '.html';
    }
    return 'index.php?col=' . $id . ($page > 1 ? '&p=' . (int)$page : '');
}
function url_art($id) {
    return rewrite_on() ? '/art-' . (int)$id . '.html' : 'index.php?art=' . (int)$id;
}
function url_page($flag) {
    return rewrite_on() ? '/' . urlencode($flag) . '.html' : 'index.php?page=' . urlencode($flag);
}
function url_home() {
    return rewrite_on() ? '/' : 'index.php';
}

/* ---------------- 数据调用 ---------------- */

/**
 * 导航数据（一级栏目 + 单页合并，均按 is_nav=1 且启用过滤）
 * nav_name 非空时优先作为导航显示名；栏目与单页按 sort 统一混排
 * 每行含 id/type/key/name/url（key 用于导航高亮：col-{id} / page-{flag}）
 */
function nav_columns() {
    $nav = array();
    foreach (db_all("SELECT id, pid, sort, IF(nav_name != '', nav_name, name) AS name FROM " . DB_PREFIX . "column
                     WHERE pid = 0 AND status = 1 AND is_nav = 1 ORDER BY sort ASC, id ASC") as $r) {
        $nav[] = array('id' => (int)$r['id'], 'type' => 'col', 'key' => 'col-' . (int)$r['id'],
                       'name' => $r['name'], 'url' => url_col($r['id']), 'sort' => (int)$r['sort']);
    }
    foreach (db_all("SELECT id, flag, sort, IF(nav_name != '', nav_name, name) AS name FROM " . DB_PREFIX . "page
                     WHERE status = 1 AND is_nav = 1 ORDER BY sort ASC, id ASC") as $r) {
        $nav[] = array('id' => 0, 'type' => 'page', 'key' => 'page-' . $r['flag'],
                       'name' => $r['name'], 'url' => url_page($r['flag']), 'sort' => (int)$r['sort']);
    }
    // 栏目与单页统一按 sort 混排（sort 相同按类型再按 id 稳定排序）
    usort($nav, function ($a, $b) {
        if ($a['sort'] !== $b['sort']) return $a['sort'] - $b['sort'];
        if ($a['type'] !== $b['type']) return $a['type'] === 'col' ? -1 : 1;
        return $a['id'] - $b['id'];
    });
    return $nav;
}

/**
 * 栏目的所有后代 id（含自身），用于内容聚合调用
 */
function column_child_ids($id) {
    $id   = (int)$id;
    $ids  = array($id);
    foreach (db_all('SELECT id FROM ' . DB_PREFIX . 'column WHERE pid = ?', array($id)) as $c) {
        $ids = array_merge($ids, column_child_ids($c['id']));
    }
    return $ids;
}

/**
 * 栏目的顶级祖先 id（导航高亮用，自身为一级栏目时返回自身）
 */
function column_top_id($id) {
    $id    = (int)$id;
    $guard = 0;
    while ($id > 0 && $guard++ < 20) {
        $pid = (int)db_val('SELECT pid FROM ' . DB_PREFIX . 'column WHERE id = ?', array($id));
        if ($pid <= 0) break;
        $id = $pid;
    }
    return $id;
}

/**
 * 栏目树（无限级）
 */
function column_tree($pid = 0) {
    $rows = db_all('SELECT * FROM ' . DB_PREFIX . 'column WHERE pid = ? ORDER BY sort ASC, id ASC', array($pid));
    foreach ($rows as &$r) {
        $r['children'] = column_tree($r['id']);
    }
    return $rows;
}

/**
 * 调取文章列表（模块数据源）；选择本级栏目时自动包含其所有下级栏目内容
 * @param int    $colId 栏目 ID，0 表示全部
 * @param int    $num   条数
 * @param string $order new|hot|recommend 最新|热门|推荐
 * @return array 每行含 url 字段
 */
function get_articles($colId = 0, $num = 6, $order = 'new') {
    $where = 'WHERE status = 1';
    $args  = array();
    if ($colId > 0) {
        $ids   = column_child_ids($colId);
        $where .= ' AND col_id IN (' . implode(',', array_map('intval', $ids)) . ')';
    }
    $orderBy = 'is_top DESC, sort ASC, id DESC';
    if ($order === 'hot')       $orderBy = 'views DESC, id DESC';
    if ($order === 'recommend') $orderBy = 'is_recommend DESC, id DESC';
    $num  = max(1, (int)$num);
    $rows = db_all('SELECT * FROM ' . DB_PREFIX . "article $where ORDER BY $orderBy LIMIT $num", $args);
    foreach ($rows as &$r) {
        $r['url']  = url_art($r['id']);
        $r['desc'] = str_cut($r['content'], 120);
    }
    return $rows;
}

/**
 * 栏目分页文章（含所有下级栏目的内容）
 */
function get_column_articles($colId, $page, $pageSize, &$total) {
    $ids   = column_child_ids($colId);
    $in    = implode(',', array_map('intval', $ids));
    $total = (int)db_val('SELECT COUNT(*) FROM ' . DB_PREFIX . "article WHERE col_id IN ($in) AND status = 1");
    $pageSize = max(1, (int)$pageSize);
    $page  = max(1, (int)$page);
    $start = ($page - 1) * $pageSize;
    $rows  = db_all('SELECT * FROM ' . DB_PREFIX . "article
                     WHERE col_id IN ($in) AND status = 1
                     ORDER BY is_top DESC, sort ASC, id DESC LIMIT $start, $pageSize");
    foreach ($rows as &$r) {
        $r['url']  = url_art($r['id']);
        $r['desc'] = str_cut($r['content'], 150);
    }
    return $rows;
}

/**
 * 分页 HTML
 */
function pager_html($total, $page, $pageSize, $colId) {
    $pages = max(1, (int)ceil($total / max(1, $pageSize)));
    if ($pages <= 1) return '';
    $html = '<div class="yk-pager">';
    if ($page > 1) $html .= '<a href="' . e(url_col($colId, $page - 1)) . '">上一页</a>';
    for ($i = 1; $i <= $pages; $i++) {
        $cls = $i == $page ? ' class="on"' : '';
        $html .= '<a' . $cls . ' href="' . e(url_col($colId, $i)) . '">' . $i . '</a>';
    }
    if ($page < $pages) $html .= '<a href="' . e(url_col($colId, $page + 1)) . '">下一页</a>';
    return $html . '</div>';
}

/**
 * 顶部广告条数据（配置 banner_images 为 JSON 数组，banner_notice 为文字公告）
 * @return array {images:[{img,url}], notice:''}
 */
function banner_data() {
    $images = json_decode(site_config('banner_images', '[]'), true);
    if (!is_array($images)) $images = array();
    return array(
        'images' => $images,
        'notice' => site_config('banner_notice', ''),
    );
}

/** 当前请求基础路径（模板中引用静态资源用） */
function tpl_assets() {
    return 'assets';
}

/**
 * 友情链接（存在"显示中"的友情链接模块时返回链接数组，否则空数组）
 * 每行 {name, url}，页脚模板统一展示
 */
function friend_links() {
    static $links = null;
    if ($links === null) {
        $links = array();
        $on = (int)db_val("SELECT COUNT(*) FROM " . DB_PREFIX . "index_block WHERE mod_type = 'link' AND is_show = 1");
        if ($on > 0) {
            $arr = json_decode(site_config('friend_links', '[]'), true);
            if (is_array($arr)) $links = $arr;
        }
    }
    return $links;
}

/* ---------------- 访问统计（按天聚合：PV + 去重 IP，不记录访问明细） ---------------- */

/**
 * 记录一次前台访问：当天 PV +1、当天 IP 去重（IP 以 md5 哈希存储，不留存明文）
 * 只按天聚合，不逐条入库，避免访问明细垃圾数据持续增长
 */
function stats_record() {
    $ip  = isset($_SERVER['REMOTE_ADDR']) ? trim($_SERVER['REMOTE_ADDR']) : '';
    $day = date('Y-m-d');
    db_exec('INSERT INTO ' . DB_PREFIX . 'stats_day (day, pv) VALUES (?, 1)
             ON DUPLICATE KEY UPDATE pv = pv + 1', array($day));
    if ($ip !== '') {
        db_exec('INSERT IGNORE INTO ' . DB_PREFIX . 'stats_ip (day, ip) VALUES (?, ?)',
            array($day, md5($ip)));
    }
}

/**
 * 访问概况（IP 数 / 浏览量）：今天/昨天/本周/上周/本月/上月/今年/去年/总访问量
 * 数据来源为按天聚合表 stats_day（PV）与 stats_ip（去重 IP），后台仪表盘/访问统计页共用
 * @return array [['label'=>, 'ip'=>, 'pv'=>], ...]
 */
function stats_overview() {
    $Td = DB_PREFIX . 'stats_day';
    $Ti = DB_PREFIX . 'stats_ip';
    $today = date('Y-m-d');
    // [标签, 起始日期, 结束日期(空=到今天)]
    $periods = array(
        array('今天',   $today,                                        ''),
        array('昨天',   date('Y-m-d', strtotime('-1 day')),            $today),
        array('本周',   date('Y-m-d', strtotime('monday this week')),  ''),
        array('上周',   date('Y-m-d', strtotime('monday last week')),  date('Y-m-d', strtotime('monday this week'))),
        array('本月',   date('Y-m-01'),                                ''),
        array('上月',   date('Y-m-01', strtotime('first day of last month')), date('Y-m-01')),
        array('今年',   date('Y-01-01'),                               ''),
        array('去年',   date('Y-01-01', strtotime('-1 year')),         date('Y-01-01')),
        array('总访问量', '',                                          ''),
    );
    $cards = array();
    foreach ($periods as $pd) {
        list($label, $from, $to) = $pd;
        $where = 'WHERE 1=1';
        $args  = array();
        if ($from !== '') { $where .= ' AND day >= ?'; $args[] = $from; }
        if ($to !== '')   { $where .= ' AND day < ?';  $args[] = $to; }
        $cards[] = array(
            'label' => $label,
            'pv'    => (int)db_val("SELECT IFNULL(SUM(pv),0) FROM $Td $where", $args),
            'ip'    => (int)db_val("SELECT COUNT(DISTINCT ip) FROM $Ti $where", $args),
        );
    }
    return $cards;
}
