<?php
/**
 * license-php/router.php
 * Authoritative Router for PHP / cPanel Environment.
 * Handles License, Tenant Bootstrap, and Unified Authentication Natively.
 */

$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = rtrim($uri, '/');

// Clean URI prefix if script is accessed with /license-php/router.php prefix
$uri = preg_replace('#^/license-php/router\.php#', '', $uri);

$docRoot = $_SERVER['DOCUMENT_ROOT'] ?? dirname(__DIR__);

// STRICT HTTP PROTECTION: Block direct access to data files, databases, and protected directories
if (
    preg_match('#^/license-php/data/#i', $uri) ||
    preg_match('#^/data/#i', $uri) ||
    preg_match('/\.(sqlite|db|key|pem|env|sql|log|bak)$/i', $uri)
) {
    http_response_code(403);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode([
        'success' => false,
        'code'    => 403,
        'message' => 'Access Denied: Direct HTTP access to database and storage files is strictly forbidden.'
    ], JSON_UNESCAPED_SLASHES);
    exit;
}

require_once __DIR__ . '/lib/InstallerService.php';

if ($uri === '/install' || $uri === '/installer') {
    $installPath = $docRoot . '/install.html';
    if (file_exists($installPath)) {
        header('Content-Type: text/html; charset=utf-8');
        readfile($installPath);
        exit;
    }
}

if ($uri === '' || $uri === '/index.html') {
    if (!InstallerService::isInstalled()) {
        $installPath = $docRoot . '/install.html';
        if (file_exists($installPath)) {
            header('Location: /install');
            exit;
        }
    }
    $indexPath = $docRoot . '/index.html';
    if (file_exists($indexPath)) {
        header('Content-Type: text/html; charset=utf-8');
        readfile($indexPath);
        exit;
    }
}

if ((file_exists(__DIR__ . $uri) && !is_dir(__DIR__ . $uri)) || (file_exists($docRoot . $uri) && !is_dir($docRoot . $uri))) {
    return false;
}

// Client Operational Data Storage Gateway (Protected Administrative Endpoint - SEC-01 Remediated)
if (preg_match('#^/api/data/([a-zA-Z0-9_\-]+)$#', $uri, $m)) {
    require_once __DIR__ . '/lib/Response.php';
    require_once __DIR__ . '/lib/LicenseCrypto.php';
    Response::handleCors();
    $key = $m[1];
    $allowedKeys = ['siswa', 'guru', 'tendik', 'users', 'config', 'libur', 'perizinan', 'developers', 'absensi'];
    if (!in_array($key, $allowedKeys, true)) {
        Response::json(400, ['success' => false, 'code' => 'INVALID_COLLECTION_KEY', 'message' => 'Invalid collection key']);
    }

    $sanitizedKey = basename($key);
    $dataFile = __DIR__ . '/data/' . $sanitizedKey . '.json';

    if ($_SERVER['REQUEST_METHOD'] === 'GET') {
        if (file_exists($dataFile)) {
            $content = file_get_contents($dataFile);
            $decoded = json_decode($content, true);
            Response::json(200, ['success' => true, 'data' => $decoded]);
        } else {
            Response::json(200, ['success' => true, 'data' => ($key === 'config' ? new stdClass() : [])]);
        }
    } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // SEC-01 Remediation: Require administrative JWT token to mutate operational JSON files
        $token = $_COOKIE['presensi_auth'] ?? '';
        if (!$token && isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $token = trim((string)preg_replace('/^Bearer\s+/i', '', $_SERVER['HTTP_AUTHORIZATION']));
        }

        $config = require __DIR__ . '/config/config.php';
        $pubKeyPath = $config['keys']['public'] ?? (dirname(__DIR__, 2) . '/keys/license_public.key');
        $authorized = false;

        if ($token && file_exists($pubKeyPath)) {
            $verified = LicenseCrypto::verifyToken($token, file_get_contents($pubKeyPath));
            if ($verified['valid']) {
                $role = $verified['payload']['role'] ?? '';
                if (in_array($role, ['admin', 'developer', 'super_admin', 'operator_absensi'], true)) {
                    $authorized = true;
                }
            }
        }

        if (!$authorized) {
            Response::json(401, [
                'success' => false,
                'code'    => 'UNAUTHORIZED_DATA_MUTATION',
                'message' => 'Akses ditolak: Operasi penulisan data memerlukan autentikasi administrator.'
            ]);
        }

        $raw = file_get_contents('php://input');
        $data = json_decode($raw, true);
        if ($data !== null) {
            $dir = __DIR__ . '/data';
            if (!is_dir($dir)) @mkdir($dir, 0755, true);
            file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
            Response::json(200, ['success' => true, 'message' => 'Data saved successfully']);
        }
        Response::json(400, ['success' => false, 'code' => 'INVALID_PAYLOAD', 'message' => 'Invalid JSON payload']);
    }
    exit;
}

// =============================================================================
// FIRST-RUN WEB INSTALLER & DATABASE BOOTSTRAP API GATEWAY (INSTALLER-01)
// =============================================================================
if (strpos($uri, '/api/installer') === 0) {
    require_once __DIR__ . '/lib/Response.php';
    require_once __DIR__ . '/lib/InstallerService.php';
    Response::handleCors();

    $installerRoute = rtrim(str_replace('/api/installer', '', $uri), '/');
    if ($installerRoute === '') $installerRoute = '/status';

    // 1. GET /api/installer/status (Always accessible for checking installation status)
    if ($installerRoute === '/status' && $_SERVER['REQUEST_METHOD'] === 'GET') {
        $isInstalled = InstallerService::isInstalled();
        $reqs = InstallerService::checkRequirements();
        Response::json(200, [
            'success'      => true,
            'is_installed' => $isInstalled,
            'requirements' => $reqs
        ]);
    }

    // 2. Strict Re-Run / Replay Protection: All other endpoints rejected if installed
    if (InstallerService::isInstalled()) {
        Response::json(403, [
            'success' => false,
            'code'    => 'ALREADY_INSTALLED',
            'message' => 'Aplikasi Presensi Digital sudah terinstal. Akses installer ditutup demi keamanan.'
        ]);
    }

    $body = Response::getJsonBody();

    switch ($installerRoute) {
        case '/test-db':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
            $host = trim((string)($body['host'] ?? '127.0.0.1'));
            $port = (int)($body['port'] ?? 3306);
            $name = trim((string)($body['name'] ?? ''));
            $user = trim((string)($body['user'] ?? ''));
            $pass = (string)($body['password'] ?? '');

            $res = InstallerService::testConnection($host, $port, $name, $user, $pass);
            Response::json($res['success'] ? 200 : 400, $res);
            break;

        case '/init-db':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
            $host = trim((string)($body['host'] ?? '127.0.0.1'));
            $port = (int)($body['port'] ?? 3306);
            $name = trim((string)($body['name'] ?? ''));
            $user = trim((string)($body['user'] ?? ''));
            $pass = (string)($body['password'] ?? '');

            // 1. Test connection
            $testRes = InstallerService::testConnection($host, $port, $name, $user, $pass);
            if (!$testRes['success']) {
                Response::json(400, $testRes);
            }

            // 2. Save configuration to server-side file
            InstallerService::saveConfiguration($host, $port, $name, $user, $pass);

            // 3. Initialize schema
            try {
                $dsn = "mysql:host={$host};port={$port};dbname={$name};charset=utf8mb4";
                $pdo = new PDO($dsn, $user, $pass, [
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
                ]);
                $schemaRes = InstallerService::initializeSchema($pdo);
                Response::json(200, $schemaRes);
            } catch (Throwable $e) {
                Response::json(500, [
                    'success' => false,
                    'message' => 'Inisialisasi skema database gagal: ' . $e->getMessage()
                ]);
            }
            break;

        case '/create-admin':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
            $username = trim((string)($body['username'] ?? ''));
            $password = (string)($body['password'] ?? '');
            $confirmPassword = (string)($body['confirm_password'] ?? '');

            try {
                require_once __DIR__ . '/lib/ClientDatabase.php';
                $pdo = ClientDatabase::getConnection();
                $adminRes = InstallerService::createFirstAdmin($pdo, $username, $password, $confirmPassword);
                $httpCode = 400;
                if (!empty($adminRes['success'])) {
                    $httpCode = 200;
                } elseif (!empty($adminRes['code']) && in_array($adminRes['code'], ['ADMIN_ALREADY_EXISTS', 'USERNAME_TAKEN', 'INCONSISTENT_ADMIN_RECORD', 'INCOMPLETE_SCHEMA_STATE'], true)) {
                    $httpCode = 409;
                }
                Response::json($httpCode, $adminRes);
            } catch (Throwable $e) {
                Response::json(500, [
                    'success' => false,
                    'message' => 'Gagal membuat akun administrator: ' . $e->getMessage()
                ]);
            }
            break;

        case '/activate-license':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
            $rawKey = strtoupper(trim((string)($body['license_key'] ?? '')));
            $domain = trim((string)($body['domain'] ?? ($_SERVER['HTTP_HOST'] ?? 'localhost')));
            $product = trim((string)($body['product'] ?? 'presensi-smansa-pro'));
            if (!$rawKey) {
                Response::json(400, ['success' => false, 'message' => 'Kunci lisensi wajib diisi']);
            }

            // Delegate to centralized activation bridge
            $actRes = InstallerService::activateCentralLicense($rawKey, $domain, $product);
            $statusCode = !empty($actRes['success']) ? 200 : (
                isset($actRes['code']) && in_array($actRes['code'], ['DOMAIN_MISMATCH', 'INVALID_SIGNATURE', 'LICENSE_EXPIRED', 'LICENSE_INACTIVE'], true) ? 403 : (
                    isset($actRes['code']) && $actRes['code'] === 'invalid' ? 404 : 400
                )
            );
            Response::json($statusCode, $actRes);
            break;

        case '/finalize':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
            try {
                require_once __DIR__ . '/lib/ClientDatabase.php';
                require_once __DIR__ . '/lib/LicenseEntitlement.php';
                $pdo = ClientDatabase::getConnection();

                $mode = strtolower(trim((string)($body['mode'] ?? '')));
                if ($mode === 'demo') {
                    // Lock installation in DEMO mode
                    $locked = InstallerService::lockInstallation($pdo, [
                        'installer_version' => '1.0.0',
                        'completed_at'      => date('c'),
                        'mode'              => 'DEMO'
                    ]);
                    // Reconcile existing records so Demo operational quotas are respected
                    LicenseEntitlement::reconcileEntitlement($pdo);

                    Response::json(200, [
                        'success'  => true,
                        'mode'     => 'DEMO',
                        'message'  => 'Instalasi selesai dalam Mode DEMO dan terkunci secara permanen. Silakan masuk ke aplikasi.',
                        'redirect' => 'index.html'
                    ]);
                } else {
                    $locked = InstallerService::lockInstallation($pdo, [
                        'installer_version' => '1.0.0',
                        'completed_at'      => date('c'),
                        'mode'              => 'FULL'
                    ]);
                    if (LicenseEntitlement::isFull($pdo)) {
                        LicenseEntitlement::promoteAllPending($pdo);
                    }
                    Response::json(200, [
                        'success'  => true,
                        'mode'     => LicenseEntitlement::isFull($pdo) ? 'FULL' : 'DEMO',
                        'message'  => 'Instalasi selesai dan terkunci secara permanen. Silakan masuk ke aplikasi.',
                        'redirect' => 'index.html'
                    ]);
                }
            } catch (Throwable $e) {
                Response::json(500, [
                    'success' => false,
                    'message' => 'Gagal mengunci instalasi: ' . $e->getMessage()
                ]);
            }
            break;

        default:
            Response::json(404, ['success' => false, 'message' => 'Endpoint installer tidak dikenal: ' . $uri]);
    }
    exit;
}

// Master Data MySQL Authoritative API Gateway
if (preg_match('#^/api/master/#', $uri)) {
    require __DIR__ . '/api/master.php';
    exit;
}

switch ($uri) {
    case '/api/tenant/bootstrap':
        if (file_exists(__DIR__ . '/api/tenant-bootstrap.php')) {
            require __DIR__ . '/api/tenant-bootstrap.php';
        } else {
            require_once __DIR__ . '/lib/Response.php';
            Response::handleCors();
            Response::json(200, [
                'success' => true,
                'status'  => 'READY',
                'tenant'  => [
                    'tenant_id' => $tenantId ?: 'client_local',
                    'name'      => 'Sistem Presensi Digital',
                    'domain'    => $domain ?: 'localhost',
                    'status'    => 'active'
                ]
            ]);
        }
        break;

    case '/api/attendance/scan':
    case '/api/attendance/self':
    case '/api/attendance/status':
    case '/api/attendance/leave':
    case '/api/attendance/logs':
        require __DIR__ . '/api/attendance.php';
        break;
    case '/api/auth/login':
        require __DIR__ . '/api/auth-login.php';
        break;

    case '/api/user/change-password':
    case '/api/user/photo':
    case '/api/user/profile':
        require __DIR__ . '/api/auth-profile.php';
        break;

    case '/api/auth/me':
        if (file_exists(__DIR__ . '/api/auth-me.php')) {
            require __DIR__ . '/api/auth-me.php';
        } else {
            require_once __DIR__ . '/lib/Response.php';
            require_once __DIR__ . '/lib/LicenseCrypto.php';
            Response::handleCors();

            $config = require __DIR__ . '/config/config.php';
            $pubKeyPath = $config['keys']['public'];
            if (!file_exists($pubKeyPath)) {
                $pubKeyPath = dirname(__DIR__) . '/keys/license_public.key';
            }

            $token = $_COOKIE['presensi_auth'] ?? '';
            if (!$token && isset($_SERVER['HTTP_AUTHORIZATION'])) {
                $token = trim((string)preg_replace('/^Bearer\s+/i', '', $_SERVER['HTTP_AUTHORIZATION']));
            }

            $payload = null;
            if ($token && file_exists($pubKeyPath)) {
                $pubKeyPem = file_get_contents($pubKeyPath);
                $verified = LicenseCrypto::verifyToken($token, $pubKeyPem);
                if ($verified['valid']) {
                    $payload = $verified['payload'];
                }
            }

            if (!$payload) {
                Response::json(401, ['success' => false, 'code' => 'UNAUTHENTICATED']);
            }

            Response::json(200, [
                'success'       => true,
                'authenticated' => true,
                'tenant_id'     => $payload['tenant_id'] ?? 'client_local',
                'role'          => $payload['role'] ?? 'admin',
                'username'      => $payload['username'] ?? ($payload['sub'] ?? 'admin'),
                'nama'          => $payload['nama'] ?? 'Administrator',
                'token'         => $token
            ]);
        }
        break;

    case '/api/auth/logout':
        setcookie('presensi_auth', '', time() - 3600, '/');
        header('Content-Type: application/json; charset=utf-8');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
        header('Expires: 0');
        echo json_encode(['success' => true]);
        break;

    case '/api/license/public-key':
        require __DIR__ . '/api/public-key.php';
        break;
    case '/api/license/status':
        require __DIR__ . '/api/status.php';
        break;
    case '/api/license/activate':
        require __DIR__ . '/api/activate.php';
        break;
    case '/api/license/verify':
        require __DIR__ . '/api/verify.php';
        break;
    case '/api/firebase/save':
    case '/api/firebase/config':
        require_once __DIR__ . '/lib/Response.php';
        Response::handleCors();
        Response::json(410, [
            'success' => false,
            'code'    => 'FIREBASE_DECOMMISSIONED',
            'message' => 'Firebase has been decommissioned. Presensi Digital operates strictly on MySQL.'
        ]);
        break;

    case '/api/license/save-client':
        require_once __DIR__ . '/lib/Response.php';
        require_once __DIR__ . '/lib/LicenseCrypto.php';
        Response::handleCors();

        // SEC-LIC-01 Remediation: Cryptographic Token Signature & Role Verification
        $token = $_COOKIE['presensi_auth'] ?? '';
        if (!$token && isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $token = trim((string)preg_replace('/^Bearer\s+/i', '', $_SERVER['HTTP_AUTHORIZATION']));
        }

        $config = require __DIR__ . '/config/config.php';
        $isAuthorized = false;

        if ($token) {
            $pubKeyPath = $config['keys']['public'] ?? (dirname(__DIR__, 2) . '/keys/license_public.key');
            if (file_exists($pubKeyPath)) {
                $verified = LicenseCrypto::verifyToken($token, file_get_contents($pubKeyPath));
                if ($verified && $verified['valid']) {
                    $exp = $verified['payload']['exp'] ?? 0;
                    if ($exp === 0 || $exp >= time()) {
                        $role = $verified['payload']['role'] ?? '';
                        if (in_array($role, ['admin', 'developer', 'super_admin'], true)) {
                            $isAuthorized = true;
                        }
                    }
                }
            }
        }

        // Fallback to explicit Admin API Key header
        if (!$isAuthorized) {
            $adminKey = $_SERVER['HTTP_X_ADMIN_KEY'] ?? ($_SERVER['HTTP_X_API_KEY'] ?? '');
            if ($adminKey && $adminKey === ($config['admin_api_key'] ?? '')) {
                $isAuthorized = true;
            }
        }

        if (!$isAuthorized) {
            Response::json(401, [
                'success' => false,
                'code'    => 'UNAUTHENTICATED',
                'message' => 'Akses ditolak: Operasi penyimpanan lisensi klien memerlukan otorisasi administrator.'
            ]);
        }

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $raw = file_get_contents('php://input');
            $data = json_decode($raw, true);
            $token = trim((string)($data['token'] ?? ''));

            if (empty($token) || substr_count($token, '.') !== 2) {
                Response::json(400, [
                    'success' => false,
                    'code'    => 'INVALID_TOKEN_FORMAT',
                    'message' => 'Token lisensi tidak valid atau tidak disediakan.'
                ]);
            }

            // Cryptographic RSA-256 verification against client public key
            $pubKeyPath = $config['keys']['public'] ?? (dirname(__DIR__, 2) . '/keys/license_public.key');
            if (!file_exists($pubKeyPath)) {
                $altPaths = [
                    dirname(__DIR__, 2) . '/keys/license_public.key',
                    dirname(__DIR__, 3) . '/keys/license_public.key',
                    dirname(__DIR__, 4) . '/keys/license_public.key'
                ];
                foreach ($altPaths as $ap) {
                    if (file_exists($ap)) { $pubKeyPath = $ap; break; }
                }
            }

            if (!file_exists($pubKeyPath)) {
                Response::json(500, [
                    'success' => false,
                    'code'    => 'PUBLIC_KEY_MISSING',
                    'message' => 'Kunci publik verifikasi lisensi klien tidak ditemukan.'
                ]);
            }

            $pubKeyContent = file_get_contents($pubKeyPath);
            $verified = LicenseCrypto::verifyToken($token, $pubKeyContent);

            if (!$verified || empty($verified['valid'])) {
                Response::json(403, [
                    'success' => false,
                    'code'    => 'INVALID_TOKEN_SIGNATURE',
                    'message' => 'Tanda tangan kriptografis token lisensi tidak valid atau telah dipalsukan.'
                ]);
            }

            $p = $verified['payload'] ?? [];
            $expectedProduct = $config['product_name'] ?? 'presensi-smansa-pro';
            if (!empty($p['product']) && strtolower($p['product']) !== strtolower($expectedProduct)) {
                Response::json(403, [
                    'success' => false,
                    'code'    => 'PRODUCT_MISMATCH',
                    'message' => 'Produk lisensi tidak cocok dengan aplikasi klien.'
                ]);
            }

            if (!empty($p['status']) && $p['status'] !== 'active') {
                Response::json(403, [
                    'success' => false,
                    'code'    => 'LICENSE_INACTIVE',
                    'message' => 'Status lisensi dalam token tidak aktif.'
                ]);
            }

            if (!empty($p['expires_at']) && strtotime($p['expires_at']) < time()) {
                Response::json(403, [
                    'success' => false,
                    'code'    => 'LICENSE_EXPIRED',
                    'message' => 'Masa berlaku lisensi telah berakhir.'
                ]);
            }

            // Save to file storage
            $dir = __DIR__ . '/data';
            if (!is_dir($dir)) @mkdir($dir, 0755, true);
            file_put_contents($dir . '/license.json', json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);

            // Also persist to MySQL app_settings
            try {
                require_once __DIR__ . '/lib/ClientDatabase.php';
                $pdo = ClientDatabase::getConnection();
                $stmt = $pdo->prepare("
                    INSERT INTO app_settings (setting_key, setting_value, description, updated_at)
                    VALUES ('system_license', :val, 'Authoritative Central License Metadata & Token', CURRENT_TIMESTAMP)
                    ON DUPLICATE KEY UPDATE setting_value = :val2, updated_at = CURRENT_TIMESTAMP
                ");
                $jsonLicense = json_encode($data);
                $stmt->execute([':val' => $jsonLicense, ':val2' => $jsonLicense]);
            } catch (Throwable $e) {
                error_log('[SAVE_CLIENT_DB_WARN] ' . $e->getMessage());
            }

            Response::json(200, ['success' => true, 'message' => 'License verified and saved to server storage']);
        }
        Response::json(400, ['success' => false, 'message' => 'Invalid request method']);
        break;

    case '/api/license/client-status':
        require_once __DIR__ . '/lib/Response.php';
        require_once __DIR__ . '/lib/ClientDatabase.php';
        require_once __DIR__ . '/lib/LicenseEntitlement.php';
        Response::handleCors();

        try {
            $pdo = ClientDatabase::getConnection();
            $summary = LicenseEntitlement::getStatusSummary($pdo);
            Response::json(200, [
                'success'      => true,
                'has_license'  => $summary['is_full'],
                'mode'         => $summary['mode'],
                'is_full'      => $summary['is_full'],
                'is_demo'      => $summary['is_demo'],
                'license'      => $summary['license'],
                'entitlements' => $summary['entitlements'],
                'limits'       => $summary['limits']
            ]);
        } catch (Throwable $e) {
            Response::json(200, [
                'success'     => true,
                'has_license' => false,
                'mode'        => 'DEMO',
                'is_full'     => false,
                'is_demo'     => true,
                'error'       => $e->getMessage()
            ]);
        }
        break;

    case '/api/license/client-activate':
        require_once __DIR__ . '/lib/Response.php';
        require_once __DIR__ . '/lib/ClientDatabase.php';
        require_once __DIR__ . '/lib/InstallerService.php';
        require_once __DIR__ . '/lib/LicenseCrypto.php';
        require_once __DIR__ . '/lib/LicenseEntitlement.php';
        Response::handleCors();

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
        }

        // RBAC Enforcement: Administrator Only!
        $config = require __DIR__ . '/config/config.php';
        $pubKeyPath = $config['keys']['public'] ?? (dirname(__DIR__, 2) . '/keys/license_public.key');
        if (!file_exists($pubKeyPath)) {
            $pubKeyPath = dirname(__DIR__) . '/keys/license_public.key';
        }

        $token = $_COOKIE['presensi_auth'] ?? '';
        if (!$token && isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $token = trim((string)preg_replace('/^Bearer\s+/i', '', $_SERVER['HTTP_AUTHORIZATION']));
        }

        $callerRole = null;
        if ($token && file_exists($pubKeyPath)) {
            $verified = LicenseCrypto::verifyToken($token, file_get_contents($pubKeyPath));
            if (!empty($verified['valid'])) {
                $callerRole = $verified['payload']['role'] ?? null;
            }
        }

        $authorizedRoles = ['admin', 'super_admin', 'developer'];
        if (!$callerRole || !in_array($callerRole, $authorizedRoles, true)) {
            Response::json(403, [
                'success' => false,
                'code'    => 'FORBIDDEN',
                'message' => 'Akses ditolak: Aktivasi lisensi resmi hanya dapat dilakukan oleh Administrator.'
            ]);
        }

        $body = Response::getJsonBody();
        $rawKey = strtoupper(trim((string)($body['license_key'] ?? '')));
        $domain = trim((string)($body['domain'] ?? ($_SERVER['HTTP_HOST'] ?? 'localhost')));
        $product = trim((string)($body['product'] ?? 'presensi-smansa-pro'));

        if (!$rawKey) {
            Response::json(400, ['success' => false, 'code' => 'EMPTY_LICENSE_KEY', 'message' => 'Kunci lisensi wajib diisi.']);
        }

        // Validate & Activate against centralized master authority
        $actRes = InstallerService::activateCentralLicense($rawKey, $domain, $product);
        if (empty($actRes['success'])) {
            $statusCode = isset($actRes['code']) && in_array($actRes['code'], ['DOMAIN_MISMATCH', 'INVALID_SIGNATURE', 'LICENSE_EXPIRED', 'LICENSE_INACTIVE'], true) ? 403 : 400;
            Response::json($statusCode, $actRes);
        }

        // Promotion of all pending records to operational status
        try {
            $pdo = ClientDatabase::getConnection();
            $promoted = LicenseEntitlement::promoteAllPending($pdo);
            Response::json(200, [
                'success'  => true,
                'mode'     => 'FULL',
                'code'     => 'LICENSE_ACTIVATED_FULL',
                'message'  => 'Lisensi FULL berhasil diaktifkan! Seluruh data master sekarang telah operasional tanpa batasan kuota.',
                'promoted' => $promoted,
                'license'  => $actRes['license'] ?? null
            ]);
        } catch (Throwable $e) {
            error_log('[PROMOTION_AFTER_ACTIVATION_ERROR] ' . $e->getMessage());
            Response::json(500, [
                'success' => false,
                'code'    => 'PROMOTION_FAILED',
                'message' => 'Lisensi berhasil divalidasi namun terjadi kesalahan saat memperbarui status data: ' . $e->getMessage()
            ]);
        }
        break;

    case '/api/firebase/delete':
        require_once __DIR__ . '/lib/Response.php';
        Response::handleCors();
        $cfgFile = __DIR__ . '/data/firebase-config.json';
        if (file_exists($cfgFile)) {
            @unlink($cfgFile);
        }
        Response::json(410, [
            'success' => false,
            'code'    => 'FIREBASE_DECOMMISSIONED',
            'message' => 'Firebase has been decommissioned. Presensi Digital operates strictly on MySQL.'
        ]);
        break;

    case '/api/license/deactivate':
        require __DIR__ . '/api/deactivate.php';
        break;
    case '/api/admin/licenses/generate':
        $_GET['action'] = 'generate';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/licenses/suspend':
        $_GET['action'] = 'suspend';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/licenses/revoke':
        $_GET['action'] = 'revoke';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/licenses/reactivate':
        $_GET['action'] = 'reactivate';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/licenses/reset-domain':
        $_GET['action'] = 'reset-domain';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/change-password':
        require __DIR__ . '/api/admin-change-password.php';
        break;
    case '/api/admin/licenses/extend':
        $_GET['action'] = 'extend';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/licenses':
        $_GET['action'] = 'list';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/stats':
        $_GET['action'] = 'stats';
        require __DIR__ . '/admin/api.php';
        break;
    case '/api/admin/audit-logs':
    case '/api/admin/license-logs':
        $_GET['action'] = 'logs';
        require __DIR__ . '/admin/api.php';
        break;
    default:
        if (strpos($uri, '/admin/') === 0 && file_exists(__DIR__ . $uri)) {
            require __DIR__ . $uri;
        } elseif (strpos($uri, '/api/') !== 0) {
            // SPA Fallback for frontend URL slug routes (e.g. /dashboard, /siswa, /guru, etc.)
            $indexPath = $docRoot . '/index.html';
            if (file_exists($indexPath)) {
                header('Content-Type: text/html; charset=utf-8');
                readfile($indexPath);
                exit;
            }
            http_response_code(404);
            echo "Not Found";
        } else {
            http_response_code(404);
            header('Content-Type: application/json; charset=utf-8');
            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
            header('Pragma: no-cache');
            header('Expires: 0');
            echo json_encode(['success' => false, 'message' => 'Endpoint not found: ' . $uri]);
        }
        break;
}
