<?php

use xmvc\Encoder;

$fileList = [];
$shortFile = '';
$configFileRemark = '';
forEachDir(DIR_CONFIG, function ($path, $basename, $type, $level) use (&$fileList) {
    $shortFile = substr($path, strlen(DIR_CONFIG) + 1);
    if (
        $type == 'file' &&
        !in_array(
            $shortFile,
            // 过滤掉不进行在线管理的配置文件
            [
                'service.php',
                'events.php',
                'view.php'
            ]
        )
    ) {
        $fileList[] = [$shortFile, Encoder::encode($path)];
    }
});

/** 统计 $line 前面有多少空格 */
function countLeadingSpaces($line)
{
    return strlen($line) - strlen(ltrim($line));
}

function parseRemark($previousLines)
{
    $previousLines = trim($previousLines);
    $strArr = explode("\n", $previousLines);
    $previousLines = [];
    $vars = [];
    foreach ($strArr as $i => $str) {
        $str = trim($str, '/* ');
        if ($str && preg_match('/\$(\b[A-Z_]+)\b\s*\=\s*(\{.*?\})/', $str, $m)) {
            // 全局注释变量, 大写加下划线
            $vars[$m[1]] = $m[2];
            $previousLines[] = '<span style="font-size:12px"><span style="color:#008">$' . $m[1] . '</span> = <span style="color:#333">' . $m[2] . '</span></span>';
        } else {
            // 替换 - 与 - 之间的空格
            while (preg_match('/(-)\s+(-)/', $str)) {
                $str = preg_replace('/(-)\s+(-)/', '--', $str);
            }
            $str = preg_replace_callback('/^(-+)/', function ($m) {
                return str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', strlen($m[0]));
            }, $str);
            $previousLines[] = trim($str, '/* ');
        }
    }
    $title = array_shift($previousLines) ?: '';
    $remark = implode('<br >', $previousLines);
    return ['title' => $title, 'remark' => $remark, 'vars' => $vars];
}

function getgComments($file)
{
    // 获取原始配置文件内容
    $fileContent = file($file);

    // 提取注释
    $configFileRemark = '';
    $comments = [];
    $previousLines = '';
    $collectingComment = false;
    $keyChains = []; //键链

    foreach ($fileContent as $line) {
        $trimmedLine = trim($line);
        if (strpos($trimmedLine, '/**') === 0) {
            $collectingComment = true;
            $previousLines = $line;
        }
        if (strpos($trimmedLine, '*/') !== false) {
            $collectingComment = false;
        }


        if ($collectingComment && strpos($trimmedLine, '/**') === false) {
            $previousLines .= $line;
        } elseif (strpos($trimmedLine, "'") === 0) {
            $key = preg_replace("/^'([^']+)'.*$/", "$1", $trimmedLine);
            $level = countLeadingSpaces($line) / 4;

            $keyChains[$level] = $key;
            if (isset($keyChains[$level + 1])) {
                // 降维时清空前面的多维
                for ($i = $level + 1; $i < count($keyChains) + 1; $i++) {
                    unset($keyChains[$i]);
                }
            }
            $comments[implode('>', $keyChains)] = $previousLines;
            $previousLines = '';
        } elseif ($trimmedLine === '],') {
            $previousLines = '';
            $level = countLeadingSpaces($line) / 4;
            if ($level == 1) {
                $keyChains = [];
            }
        } elseif ($trimmedLine === 'return [') {
            $configFileRemark = $previousLines;
            $previousLines = '';
        }
    }
    return [$configFileRemark, $comments];
}

function renderField($fullkey, $key, $value, $disabled, $isMark, $selectArr, $checkBoxArr, $isTextarea, $configFileRemarkStruct)
{
    $fullkey = strtr($fullkey, ['_' => '@']);
    $html = '';
    $html .= $key . ' <span class="c">=</span> ';
    $disabled = $disabled ? 'readonly' : '';
    if (is_array($value) && empty($checkBoxArr)) {
        return '' . $key . '&nbsp;&nbsp;<span class="blue"> ↓ </span> ';
    } elseif (!empty($selectArr)) {
        $class = $disabled ? ' class="readonly"' : '';
        $html .= " &nbsp; <select name='{$fullkey}' {$disabled}{$class}>";
        foreach ($selectArr as $sk => $sv) {
            $selected = ($sk == $value) ? ' selected' : '';
            $html .= "<option value='{$sk}'{$selected}>{$sv}</option>";
        }
        $html .= "</select>";
    } elseif (!empty($checkBoxArr)) {
        $html .= '<span>';
        foreach ($checkBoxArr as $ck => $cv) {
            $checked = in_array($ck, $value) ? "checked='checked'" : "";
            $ckFull = $fullkey . $ck;
            $class = $disabled ? ' class="readonly"' : '';
            $html .= "<input type='checkbox' name='{$fullkey}[]' value='{$ck}' id='{$ckFull}'{$checked} {$disabled} {$class}><label for='{$ckFull}'{$class}>{$cv}</label> &nbsp; ";
        }
        $html .= '</span>';
    } elseif ($isMark) {
        $html .= "<input type='password' name='{$fullkey}' value='{$value}' readonly>";
        $html .= ($disabled == '') ? "<a href=\"javascript:editMark('{$fullkey}', '{$key}', '{$value}')\">修改</a>" : '';
    } elseif ($isTextarea) {
        $value_arr = explode("\n", $value);
        if (count($value_arr) > 1) {
            foreach ($value_arr as $ni => $nv) {
                $value_arr[$ni] = trim($nv);
            }
            $value = implode("\n", $value_arr);
        }
        $html .= "<textarea  name='{$fullkey}' {$disabled}>{$value}</textarea>";
    } elseif (is_bool($value)) {
        $checked = $value ? 'checked' : '';
        $html .= "<input type='checkbox' name='{$fullkey}' value='1' {$checked} {$disabled}>";
    } elseif (is_int($value) || is_float($value)) {
        $html .= "<input type='number' name='{$fullkey}' value='{$value}' class='input-number' {$disabled}>";
    } else {
        if (is_null($value)) {
            $value = 'NULL';
        }
        $html .= "<input type='text' name='{$fullkey}' value='{$value}' {$disabled}>";
    }
    return $html;
}

function showItems(array $array, array $comments, $configFileRemarkStruct, mixed $parentkey = '', string $parentFullKey = '', int $level = 1)
{
    $i = 0;
    foreach ($array as $key => $value) {
        $fullkey = ($parentFullKey ? $parentFullKey . '>' : '') . $key;
        $bg = $level == 1 ? ($i % 2 == 0 ? 'bg-even' : 'bg-old') : '';
        $disabled = false;
        $isMark = false;
        $isTextarea = false;
        $selectArr = [];
        $checkBoxArr = [];
        $comment = isset($comments[$fullkey]) ? parseRemark($comments[$fullkey]) : ['title' => '', 'remark' => ''];
        if ($comment['title'] || $comment['remark']) {
            $rule = $comment['title'];
            $rule .= ' ' . $comment['remark'];
            if (preg_match_all('/\[[a-zA-Z0-9_]+\]\:/', $rule, $rms)) {
                foreach ((array)$rms[0] as $option) {
                    if ($option == '[disabled]:') {
                        $disabled = true;
                    }
                    if ($option == '[textMark]:') {
                        $isMark = true;
                    }
                    if ($option == '[textarea]:') {
                        $isTextarea = true;
                    }
                    if ($option == '[select]:') {
                        if (preg_match('/\[select\]\:[^\{]*(\{.*?\})/', $rule, $m)) {
                            $selectArr = json_decode($m[1], true);
                        } elseif (preg_match('/\[select\]\:[^\{]*\$\b([A-Z_]+)\b\s*|$/', $rule, $m)) {
                            $selectArr = json_decode($configFileRemarkStruct['vars'][$m[1]], true);
                        }
                    }
                    if ($option == '[checkbox]:') {
                        if (preg_match('/\[checkbox\]\:[^\{]*(\{.*?\})/', $rule, $m)) {
                            $checkBoxArr = json_decode($m[1], true);
                        } elseif (preg_match('/\[checkbox\]\:[^\$]*\$\b([A-Z_]+)\b\s*|$/', $rule, $m)) {
                            $checkBoxArr = json_decode($configFileRemarkStruct['vars'][$m[1]], true);
                        }
                        foreach ($checkBoxArr as $ck => $cv) {
                            if ($cv == '') {
                                unset($checkBoxArr[$ck]);
                            }
                        }
                    }
                }
            }
        }
        echo '<div class="item ' . $bg . ' level-' . $level . '">';
        if ($comment['title']) {
            echo "<label>{$comment['title']}</label>";
        }
        if ($comment['remark']) {
            echo "<p>{$comment['remark']}</p>";
        }
        echo '<div class="editbox">' . renderField($fullkey, $key, $value, $disabled, $isMark, $selectArr, $checkBoxArr, $isTextarea, $configFileRemarkStruct) . '</div>';
        if (is_array($value) && isset($comments[$fullkey]) && empty($checkBoxArr)) {
            echo '<hr>';
            showItems($value, $comments, $configFileRemarkStruct, $key, $fullkey, $level + 1);
        }
        echo '</div>';
        $i++;
    }
}

function var_export_short($array, $parentKey, $comments, $indent = "")
{
    $lines = [];
    $lines[] = "[";

    foreach ($array as $key => $value) {
        $fullkey = ($parentKey ? $parentKey . '>' : '') . $key;
        $comment = '';
        if (isset($comments[$fullkey]) && $comments[$fullkey]) {
            $comment = $comments[$fullkey];
            if (substr(trim($comment), -2) != '*/') {
                $comment .= $indent . "    " . " */\n";
            }
        }
        $key_str = var_export($key, true);
        if (is_array($value)) {
            $value_str = var_export_short($value, $fullkey, $comments, $indent . "    ");
        } else {
            $value_str = var_export($value, true);
            $value_str = str_replace("\r\n", "\n", $value_str);
            $value_arr = explode("\n", $value_str);
            if (count($value_arr) > 1) {
                foreach ($value_arr as $ni => $nv) {
                    if ($ni > 0) {
                        $value_arr[$ni] = $indent . "    " . "    " . trim($nv);
                    }
                }
                $value_str = implode("\n", $value_arr);
            }
        }
        $lines[] = $comment .  $indent . "    " . $key_str . " => " . $value_str . ",";
    }

    $lines[] = $indent . "]";
    return implode("\n", $lines);
}

function updateArray(&$array, $newArray, $parentKey = '')
{
    foreach ($array as $key => $value) {
        $fullkey = ($parentKey ? $parentKey . '>' : '') . $key;
        if (is_array($value) && is_string(reset(array_keys($value)))) {
            updateArray($array[$key], $newArray, $fullkey);
        } else {
            $dns = strtr($fullkey, ['_' => '@', '.' => '_']);
            $newValue = $newArray[$dns] ?? null;
            if (is_bool($value)) {
                $newValue = $newValue ? true : false;
            } elseif (is_int($value) || is_float($value)) {
                $newValue = $newValue * 1;
            } elseif (is_string($value)) {
                $newValue = $newValue ?: '';
            } elseif (is_array($value)) {
                $newValue = $newValue ?: [];
            }
            $array[$key] = $newValue;
        }
    }
}
$file = I('file', '');
if ($file) {
    $shortFile = substr($file, strlen(DIR_CONFIG) + 1);
    $config = require($file);
    list($configFileRemark, $comments) = getgComments($file);
    $configFileRemarkStruct = parseRemark($configFileRemark);
    if (hasPost()) {
        $post = array_intersect_key(I('*'), array_flip(postKeys()));
        updateArray($config, $post);
        //dd($post, $config);
        if ($configFileRemark) {
            if (substr(trim($configFileRemark), -2) != '*/') {
                $configFileRemark = $configFileRemark . " */\n";
            }
        }
        $contents = "<?php\n\n";
        $contents .= $configFileRemark . "\n";
        $contents .= "return ";
        $contents .= var_export_short($config, '', $comments, "");
        $contents .= ";\n";
        file_put_contents($file, $contents);
        header('Location: ' . url('SELF'));
        exit();
    }
}
// @codingStandardsIgnoreStart
?>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charSet="utf-8" />
    <title>Cfg UI</title>
    <style>
        h1,
        hr,
        p {
            padding: 0;
            margin: 0;
        }

        .menu {
            margin-top: 10px;
            margin-left: .5em;
            margin-right: 320px;
            margin-bottom: 1em;
            border: 1px solid #ddd;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            border-radius: 5px;
            padding: .3em 1em;
        }

        li.menu-selected {
            background: #006699;
        }

        li.menu-selected a {
            color: #fff;
        }

        .content {
            margin-left: .5em;
            /* 留出空间给悬停层 */
            margin-right: 320px;
        }

        .c {
            color: #ccc
        }

        .blue {
            color: #008
        }

        input[type="text"],
        input[type="password"],
        input[type="number"] {
            font-size: 16px;
            font-weight: bold;
            color: #C00;
            width: 50%;
            margin: 5px;
            padding: 5px;
            border: 1px solid #008;
            border-radius: 5px;
        }

        input[type="number"] {
            color: green
        }

        input[type="radio"] {
            transform: scale(1.1);
            margin: 5px;
            color: #006699
        }

        input[type="checkbox"] {
            transform: scale(1.5);
            margin: 5px;
        }

        textarea {
            transform: scale(1.1);
            margin: 10px 0 10px 40px;
            padding: 5px;
            font-size: 16px;
            font-weight: bold;
            border: 1px solid #008;
            border-radius: 5px;
            width: 50%;
            height: 100px;
        }

        select {
            margin: 5px;
            padding: 1px 10px 1px 2px;
            font-size: 18px;
            font-weight: bold;
            border: 1px solid #008;
            border-radius: 5px;
            color: #C00;

        }

        input[type="submit"] {
            transform: scale(1.5);
            margin: 5px;
            background-color: #008;
            color: #fff;
        }

        input[readonly],
        input[disabled] {
            border: 1px solid #ccc;
            color: #aaa;
        }

        .readonly {
            /* 阻止鼠标事件 */
            pointer-events: none;
            /* 降低透明度以表明它是只读的 */
            opacity: 0.6;
        }

        hr {
            border: none;
            height: 1px;
            background-color: #ccc;
        }

        .bg-even {
            background: none;
        }

        .bg-old {
            background: #fafafa;
        }

        .item {
            border: 1px solid #ccc;
            border-top: none;
            padding: .5em;
            padding-bottom: 0;
        }

        .item p {
            font-size: 14px;
            color: slategrey;
            border-bottom: 1px solid #ccc;
            margin: 2px -.55em;
            padding: 3px 0;
        }

        .item .editbox {
            font-size: 16px;
            font-weight: bold;
        }

        .item.level-1 {
            padding-left: 1em;
            border: 1px solid #aaa;
            border-radius: .5em;
            margin-bottom: .5em;
        }

        .item.level-2 {
            margin-left: 4em;
        }

        .item.level-3 {
            margin-left: 6em;
        }

        .item.level-4 {
            margin-left: 8em;
        }

        .item.level-5 {
            margin-left: 10em;
        }

        .item.level-1 label {
            color: darkblue;
            font-weight: bold;
            font-size: 18px;
        }

        .item.level-2 label {
            color: #363;
            font-weight: normal;
            font-size: 16px;
        }

        .item.level-3 label {
            color: #666;
            font-weight: normal;
            font-size: 16px;
        }

        .item.level-4 label {
            color: #666;
            font-weight: normal;
            font-size: 16px;
        }

        .item.level-5 label {
            color: #666;
            font-weight: normal;
            font-size: 16px;
        }

        .sidebar {
            position: fixed;
            top: 10px;
            right: 10px;
            width: 280px;
            background-color: #f9f9f9;
            border: 1px solid #ddd;
            padding: 10px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            border-radius: 5px;
        }

        .sidebar a {
            display: block;
            margin-bottom: 5px;
            color: #3498db;
            text-decoration: none;
        }

        .sidebar a:hover {
            text-decoration: underline;
        }
    </style>
    <script>
        document.addEventListener("DOMContentLoaded", function() {
            let toc = document.getElementById('toc');
            let headers = document.querySelectorAll('.level-1>label');
            headers.forEach(function(header, index) {
                let id = 'section-' + index;
                header.id = id;
                let link = document.createElement('a');
                link.href = '#' + id;
                link.textContent = header.textContent;
                toc.appendChild(link);
            });
        });

        function editMark(fullkey, key, value) {
            console.log(fullkey, key, value);
            let userInput = prompt(fullkey, value);
            if (userInput !== null) {
                const form = document.getElementById('cfgForm');
                let e = form.querySelector('[name="' + fullkey + '"]');
                e.value = userInput;
            }
        }

        /*
        function checkboxClick(that) {
            if (that.value == '' && that.checked) {
                var parentDiv = event.target.closest('DIV');
                var checkboxes = parentDiv.querySelectorAll('input[type="checkbox"]');
                checkboxes.forEach(function(e, i) {
                    if (e.id != that.id) {
                        e.checked = false;
                    }
                });
            }
        }*/
    </script>
</head>

<body>
    <div class="menu">
        <ul>
            <?php foreach ($fileList as $i => $item) : ?>
                <?php $class = ($shortFile == $item['0']) ? 'menu-selected' : '' ?>
                <li class="<?= $class ?>"><a href="<?= url('xmvc/core/cmd-cfgUI', ['file' => $item['1']]) ?>"><?= $item['0'] ?></a></li>
            <?php endforeach; ?>
        </ul>
    </div>
    <?php if (I('file')) :
    ?>

        <div class="sidebar" id="sidebar">
            <h3><?= $configFileRemarkStruct['title'] ?></h3>
            <a href="#">↑ TOP </a>
            <div id="toc"></div>
            <a href="#foot">↓ FOOT </a>
            <a href="javascript:cfgForm.submit();">保存配置</a>
        </div>

        <div class="content">
            <h1 style="color:brown"><?= $configFileRemarkStruct['title'] ?> <?= $shortFile ?></h1>
            <h3 style="color:darkgreen"><?= $configFileRemarkStruct['remark'] ?></h3>
            <form id="cfgForm" name="cfgForm" action="<?= url('SELF') ?>" method="post">
                <input type="hidden" name='csrfToken' value="<?= getCsrfToken() ?>">
                <?php showItems($config, $comments, $configFileRemarkStruct); ?>
                <div style="padding-left:1em"><input type="submit" value="保存配置"></div>
            </form>
            <div style="height:5em" id="foot"></div>
        </div>
    <?php endif; //file
    ?>
</body>

</html>