<?php
/**
* MVC 全局函数库
*/

/**
 * 从调用处的源文件解析 dd()/dump() 的参数名列表
 * 读取指定行，提取 dd(...) 或 dump(...) 括号内的顶层逗号分隔表达式
 * 例：dd($method, $params, $data)  →  ['$method', '$params', '$data']
 */
function _ddFormat(mixed $val, int $indent = 0): string
{
    $pad  = str_repeat('    ', $indent);
    $blue = 'style="color:#6badf7"';
    if (is_bool($val)) {
        return '<span ' . $blue . '>' . ($val ? 'True' : 'False') . '</span>';
    }
    if (is_null($val)) {
        return '<span ' . $blue . '>null</span>';
    }
    if (is_int($val) || is_float($val)) {
        return '<span ' . $blue . '>' . $val . '</span>';
    }
    if (is_string($val)) {
        return '"' . htmlspecialchars($val) . '"';
    }
    if (is_array($val)) {
        if (count($val) === 0) {
            return 'Array()';
        }
        $lines = ['Array('];
        foreach ($val as $k => $v) {
            $key = is_string($k) ? '"' . htmlspecialchars($k) . '"' : $k;
            $lines[] = $pad . '    [' . $key . '] => ' . _ddFormat($v, $indent + 1);
        }
        $lines[] = $pad . ')';
        return implode("\n", $lines);
    }
    return htmlspecialchars(print_r($val, true));
}

function _ddParseArgNames(string $file, int $line, string $fn): array
{
    if (!is_file($file)) {
        return [];
    }
    $lines = file($file);
    // 从目标行向后最多拼 5 行，应对多行写法
    $src = implode(' ', array_slice($lines, $line - 1, 5));
    // 找到第一个 dd( 或 dump(
    if (!preg_match('/\b' . preg_quote($fn, '/') . '\s*\(/', $src, $m, PREG_OFFSET_CAPTURE)) {
        return [];
    }
    $start = $m[0][1] + strlen($m[0][0]);
    // 按括号深度逐字符找到配对的 )
    $depth = 1;
    $inner = '';
    for ($i = $start, $len = strlen($src); $i < $len && $depth > 0; $i++) {
        $ch = $src[$i];
        if ($ch === '(') { $depth++; }
        elseif ($ch === ')') { $depth--; }
        if ($depth > 0) { $inner .= $ch; }
    }
    // 按顶层逗号分割（不拆括号内的逗号）
    $args = [];
    $cur = '';
    $d   = 0;
    foreach (str_split($inner) as $ch) {
        if (in_array($ch, ['(', '[', '{'])) { $d++; }
        elseif (in_array($ch, [')', ']', '}'])) { $d--; }
        if ($ch === ',' && $d === 0) {
            $args[] = trim($cur);
            $cur    = '';
        } else {
            $cur .= $ch;
        }
    }
    if (trim($cur) !== '') {
        $args[] = trim($cur);
    }
    return $args;
}

if(!function_exists('dump')){
    /**
     * 打印变量内容（不中断程序）
     * 显示调用位置和参数名，值用 print_r 格式（无类型/长度注释）
     */
    function dump(...$vars){
        $frame = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0] ?? [];
        $file  = $frame['file'] ?? '';
        $line  = $frame['line'] ?? 0;
        $names = _ddParseArgNames($file, $line, 'dump');

        $style = 'background:#272822;color:#f8f8f2;padding:10px;margin:5px;border-radius:4px;'
               . 'text-align:left;white-space:pre-wrap;word-break:break-all;font-size:14px;line-height:1.5;';
        $loc   = '<span style="color:#75715e;">' . htmlspecialchars($file ?: '?') . ':' . ($line ?: '?') . '</span>' . "\n";

        echo '<pre style="' . $style . '">' . $loc;
        foreach ($vars as $i => $var) {
            if (count($vars) > 1) {
                $label = $names[$i] ?? ('$var[' . $i . ']');
                echo '<span style="color:#66d9ef;">' . htmlspecialchars($label) . '</span>' . "\n";
            }
            $out = _ddFormat($var);
            echo $out . "\n";
        }
        echo '</pre>';
    }
}

if(!function_exists('dd')){
    /**
     * 打印变量内容并中断程序
     * 显示调用位置和参数名，值用 print_r 格式（无类型/长度注释）
     */
    function dd(...$vars){
        $frame = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0] ?? [];
        $file  = $frame['file'] ?? '';
        $line  = $frame['line'] ?? 0;
        $names = _ddParseArgNames($file, $line, 'dd');

        $style = 'background:#272822;color:#f8f8f2;padding:10px;margin:5px;border-radius:4px;'
               . 'text-align:left;white-space:pre-wrap;word-break:break-all;font-size:14px;line-height:1.5;';
        $loc   = '<span style="color:#75715e;">' . htmlspecialchars($file ?: '?') . ':' . ($line ?: '?') . '</span>' . "\n";

        echo '<pre style="' . $style . '">' . $loc;
        foreach ($vars as $i => $var) {
            if (count($vars) > 1) {
                $label = $names[$i] ?? ('$var[' . $i . ']');
                echo '<span style="color:#66d9ef;">' . htmlspecialchars($label) . '</span>' . "\n";
            }
            $out = _ddFormat($var);
            echo $out . "\n";
        }
        echo '</pre>';
        exit();
    }
}

if(!function_exists('viewSet')){
    /**
     * 给模板赋值（View::set 的全局快捷方式）
     * @param string|array $key
     * @param mixed $value
     * @return void
     */
    function viewSet($key, $value = null){
        View::set($key, $value);
    }
}

if(!function_exists('viewLoad')){
    /**
     * 加载子视图（View::load 的全局快捷方式），供模板内调用
     * @param string $view
     * @return void
     */
    function viewLoad($view){
        View::load($view);
    }
}

if(!function_exists('lg')){
    /**
     * 取多语言译文（Lang::get 的全局快捷方式），找不到 key 时原样返回 key
     * @param string $key
     * @return string
     */
    function lg($key){
        return Lang::get($key);
    }
}

if(!function_exists('clientIp')){
    /**
     * 当前客户端 IP，登录失败锁定等按 IP 统计的场景用
     * @return string
     */
    function clientIp(){
        return $_SERVER['REMOTE_ADDR'] ?? '';
    }
}

if(!function_exists('getSemiangle')){
    /**
     * 全角转半角（字母、数字、符号、空格），号码规整前的第一步
     * @param string $string
     * @return string
     */
    function getSemiangle($string){
        if ($string === '') {
            return '';
        }
        return mb_convert_kana($string, 'as', 'UTF-8');
    }
}

if(!function_exists('formatNum')){
    /**
     * 零件号码去格式：全角转半角 → 去掉白名单以外的字符 → 统一转大写
     * 默认只保留字母和数字，需要多留字符时用 $keep 传（只支持 ASCII 字符，逐字符匹配）
     * 例：formatNum('ＡＢ-12 34')  → 'AB1234'
     *     formatNum('ＡＢ-12 34', '-') → 'AB-1234'
     * @param string|int|float|null $string 原始号码
     * @param string $keep 额外保留的字符集合
     * @return string
     */
    function formatNum($string, $keep = ''){
        if ($string === null || $string === '') {
            return '';
        }
        $semi  = getSemiangle((string)$string);
        $allow = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' . $keep;
        $out   = '';
        for ($i = 0, $len = strlen($semi); $i < $len; $i++) {
            if (strpos($allow, $semi[$i]) !== false) {
                $out .= $semi[$i];
            }
        }
        return strtoupper($out);
    }
}
