<?php

use xmvc\Encoder;

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

function parseRemark($previousLines)
{
    $previousLines = trim($previousLines);
    $strArr = explode("\n", $previousLines);
    $previousLines = [];
    foreach ($strArr as $i => $str) {
        $str = trim($str, '/* ');
        if ($str) {
            // 替换 - 与 - 之间的空格
            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];
}

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)
{
    $html = '';
    $html .= $key . ' <span class="c">=</span> ';
    $disabled = $disabled ? 'readonly' : '';
    if (is_array($value)) {
        return '' . $key . '&nbsp;&nbsp;<span class="blue"> ↓ </span> ';
    } elseif (!empty($selectArr)) {
        $html .= " &nbsp; <select name='{$fullkey}' {$disabled}>";
        foreach ($selectArr as $sk => $sv) {
            $selected = ($sv == $value) ? 'selected' : '';
            $html .= "<option value='{$sv}' {$selected}>{$sk}</option>";
        }
        $html .= "</select>";
    } elseif ($isMark) {
        $html .= "<input type='password' name='{$fullkey}' value='{$value}' readonly>";
        $html .= ($disabled == '') ? "<a href=\"javascript:editMark('{$fullkey}', '{$key}', '{$value}')\">修改</a>" : '';
    } 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, string $parentKey = '', int $level = 1)
{
    $i = 0;
    foreach ($array as $key => $value) {
        $fullkey = ($parentKey ? $parentKey . '>' : '') . $key;
        $bg = $level == 1 ? ($i % 2 == 0 ? 'bg-even' : 'bg-old') : '';
        $disabled = false;
        $isMark = false;
        $selectArr = [];
        $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 == '[select]:') {
                        if (preg_match('/\[select\]\:[^\{]*\{(.*?)\}/', $rule, $m)) {
                            $selectArr = json_decode('{' . $m[1] . '}', true);
                        }
                    }
                }
            }
        }
        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) . '</div>';
        if (is_array($value) && isset($comments[$fullkey])) {
            echo '<hr>';
            showItems($value, $comments, $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);
        }
        $lines[] = $comment .  $indent . "    " . $key_str . " => " . $value_str . ",";
    }

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


$fileList = [];
$shortFile = '';
$configFileRemark = '';
forEachDir(DIR_CONFIG, function ($path, $basename, $type) use (&$fileList) {
    $shortFile = substr($path, strlen(DIR_CONFIG) + 1);
    if ($type == 'file') {
        $fileList[] = [$shortFile, Encoder::encode($path)];
    }
});

$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()));
        foreach ($post as $key => $value) {
            $dns = str_replace('>', '.', $key);

            $oldValue = getArrayFromStrLink($dns, $config);
            if (is_bool($oldValue)) {
                $value = (bool)$value;
            } elseif (is_int($oldValue) || is_float($oldValue)) {
                $value = $value * 1;
            }
            setArrayFromStrLink($dns, $value, $config);
        }

        if ($configFileRemark) {
            if (substr(trim($configFileRemark), -2) != '*/') {
                $configFileRemark = $configFileRemark . " */\n";
            }
        }
        $contents = "<?php\n\n";
        $contents .= $configFileRemark;
        $contents .= "return ";
        $contents .= var_export_short($config, '', $comments, "");
        $contents .= ";\n";
        file_put_contents($file, $contents);
        header('Location: ' . url('self'));
        exit();
    }
}
?>

<!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="checkbox"] {
            transform: scale(1.5);
            margin: 5px;
        }

        select {
            /*transform: scale(1.3);*/
            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;
        }

        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;
            }
        }
    </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>
        </div>

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

</html>