<?php
/**
 * install.php — IPCLOAKAPI 一键安装程序
 *
 * 功能：
 *   1. 首次部署时展示配置表单（MySQL / Redis / 登录密码 / API 秘钥）
 *   2. 提交后校验 MySQL 连接，创建数据表，写入 cong.php，写入 .install.lock 锁文件
 *   3. 锁文件存在时拒绝重新安装（防止覆盖生产配置）
 */

define('LOCK_FILE',    __DIR__ . '/.install.lock');
define('CONG_FILE',    __DIR__ . '/cong.php');
define('CONG_BACKUP',  __DIR__ . '/cong.php.bak');

require_once __DIR__ . '/lib/CloakPhpCompat.php';
$phpCompatReport = CloakPhpCompat::buildReport();

$errors    = [];
$success   = false;
$isLocked  = file_exists(LOCK_FILE);
$schemaMsg = '';

// ── 重置安装锁（仅允许凭旧密码强制重置，用于迁移场景）──────────────────
if (!empty($_POST['action']) && $_POST['action'] === 'unlock') {
    if (file_exists(CONG_FILE)) {
        @include_once(CONG_FILE);
    }
    $oldPwd = defined('LOGIN_PASSWORD') ? LOGIN_PASSWORD : '';
    if (!empty($_POST['unlock_password']) && $_POST['unlock_password'] === $oldPwd) {
        @unlink(LOCK_FILE);
        $isLocked = false;
    } else {
        $errors[] = '旧密码不正确，无法重置安装锁。';
    }
}

// ── 表单提交处理 ────────────────────────────────────────────────────────
if (!$isLocked && !empty($_POST['action']) && $_POST['action'] === 'install') {

    if (!$phpCompatReport['ok']) {
        $errors = array_merge($errors, $phpCompatReport['errors']);
    }

    // 读取表单值
    $db_host      = trim($_POST['db_host']      ?? '127.0.0.1') ?: '127.0.0.1';
    $db_name      = trim($_POST['db_name']      ?? '');
    $db_username  = trim($_POST['db_username']  ?? '');
    $db_password  = $_POST['db_password']       ?? '';
    $redis_enabled= (isset($_POST['redis_enabled']) && $_POST['redis_enabled'] === 'ON') ? 'ON' : 'OFF';
    $redis_host   = trim($_POST['redis_host']   ?? '127.0.0.1') ?: '127.0.0.1';
    $redis_port   = max(1, min(65535, (int)($_POST['redis_port'] ?? 6379)));
    $redis_timeout= trim($_POST['redis_timeout']?? '0.5')       ?: '0.5';
    $redis_pwd    = $_POST['redis_password']    ?? '';
    $login_pwd    = $_POST['login_password']    ?? '';
    $check_key    = trim($_POST['check_key']    ?? '');
    $server_ip    = trim($_POST['server_ip']    ?? '');
    $cf_token     = trim($_POST['cloudflare_api_token'] ?? '');
    $cf_account   = trim($_POST['cloudflare_account_id'] ?? '');

    // 基础校验
    if (empty($db_name))     $errors[] = '数据库名不能为空。';
    if (empty($db_username)) $errors[] = '数据库用户名不能为空。';
    if (empty($login_pwd))   $errors[] = '登录密码不能为空。';

    // MySQL 连接测试并创建数据表
    if (empty($errors)) {
        $conn = @new mysqli($db_host, $db_username, $db_password, $db_name);
        if ($conn->connect_error) {
            $errors[] = 'MySQL 连接失败：' . $conn->connect_error;
        } else {
            require_once __DIR__ . '/lib/InstallSchema.php';
            $schemaResult = InstallSchema::install($conn);
            if (!$schemaResult['ok']) {
                $errors[] = '数据库建表失败：' . ($schemaResult['error'] ?? '未知错误');
            } else {
                $schemaMsg = '已创建/确认数据表：' . implode('、', $schemaResult['tables']);
            }
            $conn->close();
        }
    }

    // Redis 连接测试（可跳过）
    $redisOk  = null;
    $redisMsg = '';
    if (empty($errors) && $redis_enabled === 'ON') {
        if (extension_loaded('redis')) {
            try {
                $r = new Redis();
                if (!@$r->connect($redis_host, $redis_port, 0.5)) {
                    $redisMsg = 'Redis 连接失败，已跳过（安装仍可继续）。';
                    $redisOk  = false;
                } else {
                    if ($redis_pwd !== '') $r->auth($redis_pwd);
                    $r->ping();
                    $redisOk  = true;
                }
            } catch (Throwable $e) {
                $redisMsg = 'Redis 连接异常：' . $e->getMessage() . '（已跳过）';
                $redisOk  = false;
            }
        } else {
            $redisMsg = 'phpredis 扩展未安装，Redis 功能不可用（已跳过）。';
            $redisOk  = false;
        }
    }

    // 写入 cong.php
    if (empty($errors)) {
        // 备份旧文件
        if (file_exists(CONG_FILE)) {
            @copy(CONG_FILE, CONG_BACKUP);
        }

        $cong_content = '<?php' . PHP_EOL
            . PHP_EOL
            . '// error_reporting(E_ALL);' . PHP_EOL
            . '// ini_set(\'display_errors\', 1);' . PHP_EOL
            . PHP_EOL
            . 'define(\'LOGIN_PASSWORD\', ' . var_export($login_pwd,   true) . ');' . PHP_EOL
            . PHP_EOL
            . 'define(\'DB_USERNAME\', ' . var_export($db_username, true) . ');' . PHP_EOL
            . 'define(\'DB_NAME\',     ' . var_export($db_name,     true) . ');' . PHP_EOL
            . 'define(\'DB_PASSWORD\', ' . var_export($db_password, true) . ');' . PHP_EOL
            . PHP_EOL
            . '// --- API 鉴权秘钥（全局通用，对接 tiktokba.com cloak 服务）---' . PHP_EOL
            . 'define(\'CHECK_KEY\', ' . var_export($check_key, true) . ');' . PHP_EOL
            . PHP_EOL
            . '// --- Redis 通用配置（可选）---' . PHP_EOL
            . 'define(\'REDIS_ENABLED\',  ' . var_export($redis_enabled,         true) . ');' . PHP_EOL
            . 'define(\'REDIS_HOST\',     ' . var_export($redis_host,            true) . ');' . PHP_EOL
            . 'define(\'REDIS_PORT\',     ' . (int)$redis_port                        . ');' . PHP_EOL
            . 'define(\'REDIS_TIMEOUT\',  ' . (float)$redis_timeout                   . ');' . PHP_EOL
            . 'define(\'REDIS_PASSWORD\', ' . var_export($redis_pwd,             true) . ');' . PHP_EOL
            . PHP_EOL
            . '// --- 访客日志异步写入（ON=队列落库，OFF=同步 INSERT）---' . PHP_EOL
            . 'define(\'VISITOR_LOG_ASYNC\', \'ON\');' . PHP_EOL
            . PHP_EOL
            . '// --- Cookie 域（可选，留空则按 HTTP_HOST 自动推断）---' . PHP_EOL
            . '// define(\'CLOAK_COOKIE_DOMAIN\', \'.example.com\');' . PHP_EOL
            . PHP_EOL
            . '// --- GeoIP 本地国家库（MaxMind GeoLite2 Country）---' . PHP_EOL
            . 'define(\'CLOAK_GEOIP_ENABLED\', \'ON\');' . PHP_EOL
            . 'define(\'CLOAK_GEOIP_DB_PATH\', __DIR__ . \'/storage/runtime/c7f2a9e1/cc_idx.dat\');' . PHP_EOL
            . 'define(\'CLOAK_GEOIP_CACHE_TTL\', 2592000);' . PHP_EOL
            . PHP_EOL
            . '// --- Cloudflare（可选；留空则域名仅本地登记，不走 API）---' . PHP_EOL
            . 'define(\'SERVER_IP\', ' . var_export($server_ip, true) . ');' . PHP_EOL
            . 'define(\'CLOUDFLARE_API_TOKEN\', ' . var_export($cf_token, true) . ');' . PHP_EOL
            . 'define(\'CLOUDFLARE_ACCOUNT_ID\', ' . var_export($cf_account, true) . ');' . PHP_EOL;

        if (file_put_contents(CONG_FILE, $cong_content) === false) {
            $errors[] = '写入 cong.php 失败，请检查目录写入权限。';
        } else {
            // 写入锁文件
            file_put_contents(LOCK_FILE, date('Y-m-d H:i:s') . ' installed');
            $success = true;
        }
    }
}

// ── 工具函数 ─────────────────────────────────────────────────────────────
function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function post($k, $d = '') { return h($_POST[$k] ?? $d); }
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>IPCLOAKAPI 安装程序</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{background:#f0f2f5;font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:40px 16px}
.logo{text-align:center;margin-bottom:32px}
.logo h1{font-size:1.7rem;color:#16baaa;font-weight:700}
.logo p{color:#666;font-size:.9rem;margin-top:6px}
.card{background:#fff;border-radius:10px;box-shadow:0 4px 20px rgba(0,0,0,.1);width:100%;max-width:600px;overflow:hidden}
.card-header{background:linear-gradient(135deg,#16baaa,#0e8d81);color:#fff;padding:18px 24px}
.card-header h2{font-size:1.1rem;font-weight:600;margin:0}
.card-body{padding:24px}
.section-title{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:#1565c0;margin:20px 0 10px;padding-bottom:6px;border-bottom:2px solid #e3f2fd}
.section-title:first-child{margin-top:0}
.form-group{margin-bottom:14px}
.form-group label{display:block;font-size:.85rem;color:#444;margin-bottom:4px;font-weight:500}
.form-group input[type=text],.form-group input[type=password],.form-group input[type=number]{width:100%;padding:8px 12px;border:1px solid #ced4da;border-radius:5px;font-size:.9rem;transition:border .2s}
.form-group input:focus{outline:none;border-color:#16baaa;box-shadow:0 0 0 3px rgba(22,186,170,.15)}
.form-group small{color:#888;font-size:.78rem;margin-top:3px;display:block}
.toggle-row{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.toggle-row label{font-size:.85rem;color:#444;font-weight:500;white-space:nowrap}
.toggle-switch{position:relative;width:46px;height:24px;flex-shrink:0}
.toggle-switch input{opacity:0;width:0;height:0}
.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#ccc;border-radius:24px;transition:.3s}
.slider:before{position:absolute;content:"";height:18px;width:18px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.3s}
input:checked+.slider{background:#16baaa}
input:checked+.slider:before{transform:translateX(22px)}
.btn{display:inline-block;padding:10px 28px;border-radius:6px;font-size:.95rem;font-weight:600;cursor:pointer;border:none;text-decoration:none;transition:opacity .2s}
.btn:hover{opacity:.88}
.btn-primary{background:#16baaa;color:#fff;width:100%;margin-top:8px}
.btn-secondary{background:#6c757d;color:#fff}
.btn-sm{padding:6px 14px;font-size:.82rem}
.alert{padding:12px 16px;border-radius:6px;margin-bottom:16px;font-size:.88rem}
.alert-danger{background:#f8d7da;color:#721c24;border:1px solid #f5c6cb}
.alert-success{background:#d4edda;color:#155724;border:1px solid #c3e6cb}
.alert-warning{background:#fff3cd;color:#856404;border:1px solid #ffeeba}
.alert-info{background:#d1ecf1;color:#0c5460;border:1px solid #bee5eb}
.divider{border:none;border-top:1px solid #e9ecef;margin:20px 0}
.locked-notice{text-align:center;padding:24px}
.locked-notice .icon{font-size:3rem;margin-bottom:12px}
.locked-notice h3{color:#444;margin-bottom:8px}
.locked-notice p{color:#666;font-size:.88rem;margin-bottom:16px}
details{border:1px solid #dee2e6;border-radius:6px;margin-top:16px}
details summary{padding:10px 14px;cursor:pointer;font-size:.85rem;color:#666;user-select:none}
details summary:hover{background:#f8f9fa}
details .details-body{padding:16px}
.step-indicator{display:flex;gap:0;margin-bottom:28px}
.step{flex:1;text-align:center;padding:8px 4px;font-size:.78rem;color:#aaa;border-bottom:2px solid #dee2e6;font-weight:500}
.step.active{color:#16baaa;border-bottom-color:#16baaa;font-weight:600}
.step.done{color:#28a745;border-bottom-color:#28a745}
</style>
</head>
<body>

<div class="logo">
  <h1>IPCLOAKAPI</h1>
  <p>一键安装程序 · 首次部署配置向导</p>
</div>

<div class="card">
  <div class="card-header">
    <h2>环境初始化配置</h2>
  </div>
  <div class="card-body">

<?php
$phpOk = $phpCompatReport['ok'];
$phpAlertClass = $phpOk ? 'alert-info' : 'alert-danger';
?>
  <div class="alert <?php echo $phpAlertClass; ?>">
    <strong>PHP 运行环境：</strong>
    <?php echo htmlspecialchars(PHP_VERSION); ?>
    <?php if ($phpOk): ?>
      — 满足 Cloaka 要求（>= <?php echo CloakPhpCompat::MIN_PHP_VERSION; ?>）
    <?php else: ?>
      — <strong>不满足最低要求</strong>，请升级至 PHP <?php echo CloakPhpCompat::MIN_PHP_VERSION; ?>+
      <ul style="margin:8px 0 0 18px;padding:0;">
        <?php foreach ($phpCompatReport['errors'] as $pe): ?>
        <li><?php echo htmlspecialchars($pe); ?></li>
        <?php endforeach; ?>
      </ul>
    <?php endif; ?>
    <?php if (!empty($phpCompatReport['warnings'])): ?>
      <div style="margin-top:8px;font-size:.85rem;">
        <?php foreach ($phpCompatReport['warnings'] as $pw): ?>
        <div>⚠ <?php echo htmlspecialchars($pw); ?></div>
        <?php endforeach; ?>
      </div>
    <?php endif; ?>
  </div>

<?php if ($isLocked && empty($errors)): ?>
  <!-- ── 已安装状态 ── -->
  <div class="locked-notice">
    <div class="icon">🔒</div>
    <h3>系统已安装</h3>
    <p>安装锁文件存在，安装程序已被禁用，以防止覆盖生产配置。<br>如需重新配置，请输入当前登录密码以解锁。</p>
    <a href="dashboard.php" class="btn btn-primary" style="width:auto;display:inline-block;margin-bottom:16px;">进入管理后台</a>
  </div>
  <details>
    <summary>⚙️ 强制重新配置（危险操作，需验证旧密码）</summary>
    <div class="details-body">
      <div class="alert alert-warning">此操作将覆盖现有 cong.php，当前配置会备份到 cong.php.bak。</div>
      <form method="post">
        <input type="hidden" name="action" value="unlock">
        <div class="form-group">
          <label>当前登录密码</label>
          <input type="password" name="unlock_password" placeholder="输入当前后台密码以解锁">
        </div>
        <button type="submit" class="btn btn-secondary btn-sm">验证并解锁</button>
      </form>
    </div>
  </details>

<?php elseif ($success): ?>
  <!-- ── 安装成功 ── -->
  <div class="alert alert-success">
    <strong>安装成功！</strong> cong.php 已写入，安装锁已创建。
  </div>
  <?php if (!empty($schemaMsg)): ?>
  <div class="alert alert-info"><?php echo h($schemaMsg); ?></div>
  <?php endif; ?>
  <?php if (!empty($redisMsg)): ?>
  <div class="alert alert-warning"><?php echo h($redisMsg); ?></div>
  <?php endif; ?>
  <p style="color:#555;font-size:.9rem;margin-bottom:20px;">系统已完成初始化配置，请立即进入后台开始使用。</p>
  <a href="dashboard.php" class="btn btn-primary">进入管理后台 →</a>

<?php else: ?>
  <!-- ── 安装表单 ── -->

  <?php if (!empty($errors)): ?>
  <div class="alert alert-danger">
    <?php foreach ($errors as $e): ?><div>✗ <?php echo h($e); ?></div><?php endforeach; ?>
  </div>
  <?php endif; ?>

  <?php if (!empty($redisMsg) && empty($errors)): ?>
  <div class="alert alert-warning"><?php echo h($redisMsg); ?></div>
  <?php endif; ?>

  <form method="post" id="installForm">
    <input type="hidden" name="action" value="install">

    <!-- MySQL 配置 -->
    <div class="section-title">MySQL 数据库</div>
    <div class="form-group">
      <label>数据库主机</label>
      <input type="text" name="db_host" value="<?php echo post('db_host','127.0.0.1'); ?>" placeholder="127.0.0.1">
      <small>通常为 127.0.0.1 或 localhost</small>
    </div>
    <div class="form-group">
      <label>数据库名 <span style="color:#dc3545">*</span></label>
      <input type="text" name="db_name" value="<?php echo post('db_name'); ?>" placeholder="如：cloaka_db" required>
      <small>安装时将自动创建 ip_groups、ip_list、visitor_logs 数据表</small>
    </div>
    <div class="form-group">
      <label>数据库用户名 <span style="color:#dc3545">*</span></label>
      <input type="text" name="db_username" value="<?php echo post('db_username'); ?>" placeholder="如：cloaka_user" required>
    </div>
    <div class="form-group">
      <label>数据库密码</label>
      <input type="password" name="db_password" value="" placeholder="数据库用户密码" autocomplete="new-password">
    </div>

    <hr class="divider">

    <!-- Redis 配置 -->
    <div class="section-title">Redis 缓存（可选）</div>
    <div class="toggle-row">
      <label>启用 Redis</label>
      <label class="toggle-switch">
        <input type="checkbox" id="redisToggle" name="redis_enabled" value="ON" <?php echo (($_POST['redis_enabled'] ?? 'ON') === 'ON') ? 'checked' : ''; ?>>
        <span class="slider"></span>
      </label>
      <small style="color:#888">phpredis 扩展<?php echo extension_loaded('redis') ? ' <span style="color:#28a745">✓ 已安装</span>' : ' <span style="color:#dc3545">✗ 未安装</span>'; ?></small>
    </div>
    <div id="redisFields">
      <div class="form-group">
        <label>Redis 主机</label>
        <input type="text" name="redis_host" value="<?php echo post('redis_host','127.0.0.1'); ?>" placeholder="127.0.0.1">
      </div>
      <div class="form-group">
        <label>Redis 端口</label>
        <input type="number" name="redis_port" value="<?php echo post('redis_port','6379'); ?>" min="1" max="65535" style="max-width:120px;">
      </div>
      <div class="form-group">
        <label>连接超时（秒）</label>
        <input type="text" name="redis_timeout" value="<?php echo post('redis_timeout','0.5'); ?>" style="max-width:100px;">
      </div>
      <div class="form-group">
        <label>Redis 密码（无密码留空）</label>
        <input type="password" name="redis_password" value="" placeholder="无密码留空" autocomplete="new-password">
      </div>
    </div>

    <hr class="divider">

    <!-- 系统安全 -->
    <div class="section-title">系统安全</div>
    <div class="form-group">
      <label>后台登录密码 <span style="color:#dc3545">*</span></label>
      <input type="password" name="login_password" value="" placeholder="请设置强密码" required autocomplete="new-password">
      <small>用于登录 dashboard.php 后台管理页面</small>
    </div>
    <div class="form-group">
      <label>API 秘钥（CHECK_KEY）</label>
      <input type="text" name="check_key" value="<?php echo post('check_key'); ?>" placeholder="ipcloakapi.com | cloak 服务的 API 秘钥">
      <small>由服务商提供，可在安装后于 cong.php 中修改</small>
    </div>

    <hr class="divider">

    <!-- Cloudflare（可选） -->
    <div class="section-title">Cloudflare 域名自动化（可选）</div>
    <div class="form-group">
      <label>服务器公网 IP（SERVER_IP）</label>
      <input type="text" name="server_ip" value="<?php echo post('server_ip'); ?>" placeholder="例如 203.0.113.10">
      <small>NS 生效后用于创建 proxied 的 A 记录；可安装后在 cong.php 填写</small>
    </div>
    <div class="form-group">
      <label>Cloudflare API Token</label>
      <input type="password" name="cloudflare_api_token" value="" placeholder="需 Zone Edit、DNS Edit、SSL 权限" autocomplete="new-password">
      <small>在 Cloudflare 控制台 → My Profile → API Tokens 创建</small>
    </div>
    <div class="form-group">
      <label>Cloudflare Account ID</label>
      <input type="text" name="cloudflare_account_id" value="<?php echo post('cloudflare_account_id'); ?>" placeholder="控制台右侧 Account ID">
      <small>三项均留空时，域名功能保持本地登记（兼容宝塔手动建站）</small>
    </div>

    <hr class="divider">

    <button type="submit" class="btn btn-primary" id="submitBtn">开始安装</button>
  </form>

<?php endif; ?>

  </div><!-- /card-body -->
</div><!-- /card -->

<p style="color:#aaa;font-size:.78rem;margin-top:20px;text-align:center;">
  安装完成后请将 install.php 删除或设置服务器禁止访问，以保障安全。
</p>

<script>
(function() {
    var toggle = document.getElementById('redisToggle');
    var fields = document.getElementById('redisFields');
    if (!toggle || !fields) return;

    function updateFields() {
        fields.style.display = toggle.checked ? '' : 'none';
    }
    toggle.addEventListener('change', updateFields);
    updateFields();

    var form = document.getElementById('installForm');
    var btn  = document.getElementById('submitBtn');
    if (form && btn) {
        form.addEventListener('submit', function() {
            btn.disabled = true;
            btn.textContent = '安装中...';
        });
    }
})();
</script>
</body>
</html>
