<?php
declare(strict_types=1);

header('Content-Type: text/html; charset=utf-8');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('Referrer-Policy: strict-origin-when-cross-origin');
header('Permissions-Policy: geolocation=(), microphone=(), camera=()');

$installLock = __DIR__ . '/../storage/install.lock';
$installPermanentLock = __DIR__ . '/../storage/install.permanent.lock';
$zh = static function (string $escaped): string {
    $decoded = json_decode('"' . $escaped . '"');
    return is_string($decoded) ? $decoded : $escaped;
};

$renderInstallBlocked = static function (string $message): void {
    global $zh;
    http_response_code(503);
    echo '<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">';
    echo '<title>' . htmlspecialchars($zh('安装器已禁用'), ENT_QUOTES, 'UTF-8') . '</title>';
    echo '<style>body{font-family:Segoe UI,Arial,sans-serif;background:#f8fafc;color:#0f172a;margin:0;padding:40px}';
    echo '.box{max-width:760px;margin:0 auto;background:#fff;border:1px solid #e2e8f0;border-radius:14px;padding:24px;box-shadow:0 10px 24px rgba(15,23,42,.06)}';
    echo 'h1{margin:0 0 12px;font-size:24px}p{margin:0 0 10px;line-height:1.7;color:#334155}code{background:#f1f5f9;padding:2px 6px;border-radius:6px}</style>';
    echo '</head><body><div class="box">';
    echo '<h1>' . htmlspecialchars($zh('安装器已禁用'), ENT_QUOTES, 'UTF-8') . '</h1>';
    echo '<p>' . htmlspecialchars($message, ENT_QUOTES, 'UTF-8') . '</p>';
    echo '<p>' . htmlspecialchars($zh('安装器不会自动重新开放。如确实需要全新安装，请手动删除'), ENT_QUOTES, 'UTF-8')
        . ' <code>config/database.php</code> '
        . htmlspecialchars($zh('和'), ENT_QUOTES, 'UTF-8')
        . ' <code>storage/install*.lock</code> '
        . htmlspecialchars($zh('后再访问安装页。'), ENT_QUOTES, 'UTF-8')
        . '</p>';
    echo '</div></body></html>';
    exit;
};

$detectExistingInstall = static function (string $dbConfigPath): bool {
    if (!is_file($dbConfigPath)) {
        return false;
    }

    $cfg = require $dbConfigPath;
    if (!is_array($cfg)) {
        return false;
    }

    $host = trim((string)($cfg['host'] ?? ''));
    $port = (int)($cfg['port'] ?? 3306);
    $name = trim((string)($cfg['database'] ?? ''));
    $user = trim((string)($cfg['username'] ?? ''));
    $pass = (string)($cfg['password'] ?? '');
    if ($host === '' || $port <= 0 || $name === '' || $user === '') {
        return false;
    }

    try {
        $dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $host, $port, $name);
        $pdo = new PDO($dsn, $user, $pass, [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        $stmt = $pdo->query("SHOW TABLES LIKE 'users'");
        return (bool)$stmt->fetch();
    } catch (Throwable $e) {
        return false;
    }
};

$hasConfiguredDbConfig = static function (string $dbConfigPath): bool {
    if (!is_file($dbConfigPath)) {
        return false;
    }

    $cfg = require $dbConfigPath;
    if (!is_array($cfg)) {
        return false;
    }

    $host = trim((string)($cfg['host'] ?? ''));
    $name = trim((string)($cfg['database'] ?? ''));
    $user = trim((string)($cfg['username'] ?? ''));
    $port = (int)($cfg['port'] ?? 0);

    return $host !== '' && $port > 0 && $name !== '' && $user !== '';
};

$dbConfigPath = __DIR__ . '/../config/database.php';
if (!is_file($installPermanentLock)) {
    $installed = $detectExistingInstall($dbConfigPath);
    if ($installed) {
        $ts = (string)time();
        @file_put_contents($installLock, $ts);
        @file_put_contents($installPermanentLock, $ts);
    } else {
        if ($hasConfiguredDbConfig($dbConfigPath)) {
            $renderInstallBlocked($zh('检测到已有应用配置，但安装状态无法验证。为避免误重装，系统已阻止自动进入安装器。请先检查数据库服务和 config/database.php。'));
        }
        require __DIR__ . '/install.php';
        exit;
    }
}

require __DIR__ . '/../app/helpers.php';
app_ensure_security_runtime();
app_ensure_bridge_security_runtime();
app_sanitize_request_globals();
app_send_security_headers();

if (empty($_SERVER['APP_REQUEST_ID'])) {
    try {
        $_SERVER['APP_REQUEST_ID'] = bin2hex(random_bytes(8));
    } catch (Throwable $e) {
        $_SERVER['APP_REQUEST_ID'] = substr(hash('sha256', microtime(true) . '|' . mt_rand()), 0, 16);
    }
}
header('X-Request-Id: ' . (string)$_SERVER['APP_REQUEST_ID']);

$cfg = app_config();
if (!empty($cfg['timezone'])) {
    date_default_timezone_set((string)$cfg['timezone']);
}

$defaultSessionName = function_exists('app_default_session_name') ? app_default_session_name() : 'lyapp_session';
session_name((string)($cfg['session_name'] ?? $defaultSessionName));
ini_set('session.use_strict_mode', '1');
ini_set('session.use_only_cookies', '1');

$secure = app_request_is_https();
$sameSite = strtolower((string)($cfg['session_cookie_samesite'] ?? 'strict'));
if (!in_array($sameSite, ['strict', 'lax', 'none'], true)) {
    $sameSite = 'strict';
}

ini_set('session.cookie_httponly', '1');
ini_set('session.cookie_secure', $secure ? '1' : '0');
ini_set('session.cookie_samesite', ucfirst($sameSite));
@ini_set('session.sid_length', '48');
@ini_set('session.sid_bits_per_character', '6');

session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'secure' => $secure,
    'httponly' => true,
    'samesite' => ucfirst($sameSite),
]);
session_start();

spl_autoload_register(function ($class) {
    $prefix = 'App\\';
    if (strpos($class, $prefix) !== 0) {
        return;
    }
    $relative = substr($class, strlen($prefix));
    $file = __DIR__ . '/../app/' . str_replace('\\', '/', $relative) . '.php';
    if (file_exists($file)) {
        require $file;
    }
});

use App\Core\Router;

$router = new Router();
$routes = require __DIR__ . '/../config/routes.php';
foreach ($routes as $route) {
    [$method, $path, $handler] = $route;
    $router->add($method, $path, $handler);
}

$dispatchUri = (string)($_SERVER['REQUEST_URI'] ?? '/');
$routeKey = trim((string)($cfg['entry_route_key'] ?? 'r'));
if ($routeKey !== '') {
    $routeFromQuery = (string)($_GET[$routeKey] ?? '');
    if ($routeFromQuery !== '') {
        $dispatchUri = '/' . ltrim(urldecode($routeFromQuery), '/');
    }
}

$router->dispatch((string)($_SERVER['REQUEST_METHOD'] ?? 'GET'), $dispatchUri);
