<?php

declare(strict_types=1);

error_reporting(E_ALL);

require_once __DIR__ . '/../vendor/autoload.php';

if (file_exists(__DIR__ . '/../.env')) {
    $dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/..');
    $dotenv->load();
}

ini_set('display_errors', ($_ENV['APP_DEBUG'] ?? 'false') === 'true' ? '1' : '0');

// CORS Headers
$originHeader = $_SERVER['HTTP_ORIGIN'] ?? '';
$allowedOrigin = $_ENV['FRONTEND_URL'] ?? '';
if ($allowedOrigin && $originHeader) {
    $allowedOrigins = array_filter(array_map('trim', explode(',', $allowedOrigin)));
    if (in_array($originHeader, $allowedOrigins, true)) {
        header("Access-Control-Allow-Origin: {$originHeader}");
        header('Access-Control-Allow-Credentials: true');
        header('Vary: Origin');
    }
} elseif ($allowedOrigin && !$originHeader) {
    header("Access-Control-Allow-Origin: {$allowedOrigin}");
    header('Access-Control-Allow-Credentials: true');
}
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With, X-API-Key');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

use App\Utils\Response;
use App\Middleware\AuthMiddleware;
use App\Middleware\AdminMiddleware;
use App\Controllers\AuthController;
use App\Controllers\ModuleController;
use App\Controllers\SubscriptionController;
use App\Controllers\PaymentController;
use App\Controllers\LicenseController;
use App\Controllers\UserController;
use App\Controllers\VerificationController;
use App\Controllers\CouponController;
use App\Controllers\UpdateController;
use App\Controllers\LegalController;
use App\Controllers\ReviewController;
use App\Controllers\FeedbackController;
use App\Controllers\FavoriteController;
use App\Controllers\ShareController;
use App\Controllers\OrderController;
use App\Controllers\TicketController;
use App\Controllers\DocumentController;
use App\Controllers\AnnouncementController;
use App\Controllers\RedeemController;
use App\Controllers\DeployController;
use App\Controllers\CookieConsentController;
use App\Controllers\Admin\DashboardController as AdminDashboardController;
use App\Controllers\Admin\ModuleController as AdminModuleController;
use App\Controllers\Admin\UserController as AdminUserController;
use App\Controllers\Admin\LicenseController as AdminLicenseController;
use App\Controllers\Admin\CouponController as AdminCouponController;
use App\Controllers\Admin\LegalController as AdminLegalController;
use App\Controllers\Admin\VersionController as AdminVersionController;
use App\Controllers\Admin\OrderController as AdminOrderController;
use App\Controllers\Admin\TicketController as AdminTicketController;
use App\Controllers\Admin\ReviewController as AdminReviewController;
use App\Controllers\Admin\FeedbackController as AdminFeedbackController;
use App\Controllers\Admin\AnnouncementController as AdminAnnouncementController;
use App\Controllers\Admin\DocumentController as AdminDocumentController;
use App\Controllers\Admin\DataClassificationController as AdminDataClassificationController;
use App\Controllers\Admin\RedeemCodeController as AdminRedeemCodeController;
use App\Controllers\Admin\SettingController as AdminSettingController;
use App\Controllers\Admin\ScreenshotController as AdminScreenshotController;
use App\Controllers\BalanceController;
use App\Controllers\PasskeyController;
use App\Controllers\ActivityLogController;
use App\Controllers\DocumentFeedbackController;
use App\Controllers\Admin\BalanceController as AdminBalanceController;
use App\Controllers\Admin\ActivityLogController as AdminActivityLogController;
use App\Controllers\Admin\UploadController as AdminUploadController;
use App\Controllers\Admin\AuditLogController as AdminAuditLogController;
use App\Controllers\Admin\AiController as AdminAiController;
use App\Controllers\Admin\CryptoAddressController as AdminCryptoAddressController;
use App\Controllers\NotificationController;
use App\Controllers\WebhookController;
use App\Controllers\TotpController;
use App\Controllers\FavoriteCollectionController;
use App\Controllers\ExportController;
use App\Controllers\InvoiceController;
use App\Controllers\SearchController;
use App\Controllers\AffiliateController;
use App\Controllers\CronController;
use App\Controllers\Admin\AffiliateController as AdminAffiliateController;
use App\Controllers\Admin\EmailTemplateController as AdminEmailTemplateController;
use App\Services\TurnstileService;

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

$body = json_decode(file_get_contents('php://input'), true) ?? [];

// Serve uploaded files
if (preg_match('#^/uploads/(.+)$#', $uri, $matches)) {
    $basePath = realpath(__DIR__ . '/../uploads');
    if (!$basePath) {
        Response::notFound('File not found');
    }
    $requestedPath = ltrim($matches[1], '/');
    $filePath = realpath($basePath . '/' . $requestedPath);
    if ($filePath && str_starts_with($filePath, $basePath . DIRECTORY_SEPARATOR) && is_file($filePath)) {
        $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        $mimeTypes = ['jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png',
                      'gif' => 'image/gif', 'webp' => 'image/webp', 'zip' => 'application/zip'];
        $mime = $mimeTypes[$ext] ?? 'application/octet-stream';
        header("Content-Type: {$mime}");
        header("Content-Length: " . filesize($filePath));
        header("Cache-Control: public, max-age=86400");
        readfile($filePath);
        exit;
    }
    Response::notFound('File not found');
}

$isApiRequest = str_starts_with($uri, '/api');
if (!$isApiRequest) {
    $staticRoot = __DIR__;
    $requestPath = $uri === '' ? '/index.html' : $uri;
    $filePath = $staticRoot . $requestPath;
    if (is_dir($filePath)) {
        $filePath = rtrim($filePath, '/') . '/index.html';
    }
    if (file_exists($filePath)) {
        $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        $mimeTypes = [
            'html' => 'text/html',
            'css' => 'text/css',
            'js' => 'application/javascript',
            'json' => 'application/json',
            'png' => 'image/png',
            'jpg' => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'gif' => 'image/gif',
            'svg' => 'image/svg+xml',
            'webp' => 'image/webp',
            'woff' => 'font/woff',
            'woff2' => 'font/woff2',
            'ttf' => 'font/ttf',
            'ico' => 'image/x-icon',
        ];
        $mime = $mimeTypes[$ext] ?? 'application/octet-stream';
        header("Content-Type: {$mime}");
        header("Content-Length: " . filesize($filePath));
        header("Cache-Control: public, max-age=86400");
        readfile($filePath);
        exit;
    }
    $indexPath = $staticRoot . '/index.html';
    if (file_exists($indexPath)) {
        header('Content-Type: text/html');
        readfile($indexPath);
        exit;
    }
}

$verifyCronKey = function(): void {
    $cronKey = $_GET['key'] ?? '';
    $expectedKey = $_ENV['CRON_SECRET'] ?? 'default-cron-key';
    if ($cronKey !== $expectedKey) {
        Response::unauthorized('Invalid cron key');
    }
};

$routes = [
    // =====================
    // Auth routes
    // =====================
    'POST /api/auth/register' => function() use ($body) {
        if (!TurnstileService::verify($body['turnstile_token'] ?? '', $_SERVER['REMOTE_ADDR'] ?? null)) {
            Response::error('CAPTCHA verification failed', 422);
        }
        AuthController::register($body);
    },
    'POST /api/auth/login' => function() use ($body) {
        if (!TurnstileService::verify($body['turnstile_token'] ?? '', $_SERVER['REMOTE_ADDR'] ?? null)) {
            Response::error('CAPTCHA verification failed', 422);
        }
        AuthController::login($body);
    },
    'POST /api/auth/logout' => function() {
        $user = AuthMiddleware::optional();
        AuthController::logout($user);
    },
    'GET /api/auth/me' => function() {
        $user = AuthMiddleware::handle();
        if ($user) AuthController::me($user);
    },

    // Email verification
    'POST /api/auth/send-verification' => function() {
        $user = AuthMiddleware::handle();
        if ($user) VerificationController::sendVerification($user);
    },
    'GET /api/auth/verify-email/([a-f0-9]+)' => fn($token) => VerificationController::verifyEmail($token),

    // Email code login
    'POST /api/auth/send-login-code' => function() use ($body) {
        if (!TurnstileService::verify($body['turnstile_token'] ?? '', $_SERVER['REMOTE_ADDR'] ?? null)) {
            Response::error('CAPTCHA verification failed', 422);
        }
        AuthController::sendLoginCode($body);
    },
    'POST /api/auth/login-with-code' => function() use ($body) {
        if (!TurnstileService::verify($body['turnstile_token'] ?? '', $_SERVER['REMOTE_ADDR'] ?? null)) {
            Response::error('CAPTCHA verification failed', 422);
        }
        AuthController::loginWithCode($body);
    },

    // Password reset
    'POST /api/auth/forgot-password' => fn() => AuthController::forgotPassword($body),
    'POST /api/auth/verify-reset-code' => fn() => AuthController::verifyResetCode($body),
    'GET /api/auth/verify-reset-token/([a-f0-9]+)' => fn($token) => AuthController::verifyResetToken($token),
    'POST /api/auth/reset-password' => fn() => AuthController::resetPassword($body),

    // OAuth - Google
    'GET /api/auth/google' => fn() => AuthController::googleRedirect(),
    'GET /api/auth/google/callback' => fn() => AuthController::googleCallback(),

    // OAuth - Telegram
    'GET /api/auth/telegram' => fn() => AuthController::telegramLoginData(),
    'POST /api/auth/telegram/callback' => fn() => AuthController::telegramCallback($body),

    // =====================
    // Global Search
    // =====================
    'GET /api/search' => fn() => SearchController::search(),

    // =====================
    // Module routes
    // =====================
    'GET /api/modules/categories' => fn() => Response::success(\App\Models\ModuleCategory::getTree()),
    'GET /api/modules/tags' => fn() => Response::success(\App\Models\Module::getAllTags()),
    'GET /api/modules' => fn() => ModuleController::index(),
    'GET /api/modules/by-slug/([a-z0-9-]+)' => fn($slug) => ModuleController::showBySlug($slug),
    'GET /api/modules/(\d+)' => fn($id) => ModuleController::show((int)$id),
    'GET /api/modules/(\d+)/download' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) ModuleController::download((int)$id, $user);
    },
    'GET /api/modules/(\d+)/file' => function($id) {
        $user = AuthMiddleware::optional();
        ModuleController::serveFile((int)$id, $user);
    },
    'GET /api/modules/(\d+)/screenshots' => fn($id) => ModuleController::screenshots((int)$id),
    'GET /api/modules/(\d+)/versions' => fn($id) => ModuleController::versions((int)$id),
    'GET /api/modules/(\d+)/reviews' => fn($id) => ReviewController::getByModule((int)$id),
    'GET /api/modules/(\d+)/docs' => fn($id) => DocumentController::getByModule((int)$id),

    // =====================
    // Reviews
    // =====================
    'POST /api/reviews' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) ReviewController::store($user, $body);
    },
    'PUT /api/reviews/(\d+)' => function($id) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) ReviewController::update($user, (int)$id, $body);
    },
    'DELETE /api/reviews/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) ReviewController::delete($user, (int)$id);
    },
    'GET /api/user/reviews' => function() {
        $user = AuthMiddleware::handle();
        if ($user) ReviewController::getByUser($user);
    },

    // =====================
    // Feature Requests & Bug Reports
    // =====================
    'GET /api/feature-requests' => fn() => FeedbackController::listFeatureRequests(),
    'GET /api/feature-requests/(\d+)' => fn($id) => FeedbackController::showFeatureRequest((int)$id),
    'POST /api/feature-requests' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) FeedbackController::createFeatureRequest($user, $body);
    },
    'POST /api/feature-requests/(\d+)/vote' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) FeedbackController::voteFeatureRequest($user, (int)$id);
    },
    'GET /api/user/feature-requests' => function() {
        $user = AuthMiddleware::handle();
        if ($user) FeedbackController::getUserFeatureRequests($user);
    },

    'GET /api/bug-reports' => fn() => FeedbackController::listBugReports(),
    'GET /api/bug-reports/(\d+)' => fn($id) => FeedbackController::showBugReport((int)$id),
    'POST /api/bug-reports' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) FeedbackController::createBugReport($user, $body);
    },
    'GET /api/user/bug-reports' => function() {
        $user = AuthMiddleware::handle();
        if ($user) FeedbackController::getUserBugReports($user);
    },

    // =====================
    // Favorites & Shares
    // =====================
    'POST /api/favorites/toggle' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteController::toggle($user, $body);
    },
    'GET /api/favorites' => function() {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteController::list($user);
    },
    'GET /api/favorites/check/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteController::check($user, (int)$id);
    },

    'POST /api/shares' => function() use ($body) {
        $user = AuthMiddleware::optional();
        ShareController::createShare($body, $user);
    },
    'GET /api/shares/click/([a-f0-9]+)' => fn($token) => ShareController::trackClick($token),

    // =====================
    // Subscriptions
    // =====================
    'GET /api/subscriptions/plans' => fn() => SubscriptionController::plans(),
    'GET /api/subscriptions/current' => function() {
        $user = AuthMiddleware::handle();
        if ($user) SubscriptionController::current($user);
    },
    'GET /api/subscriptions/upgrade-options' => function() {
        $user = AuthMiddleware::handle();
        if ($user) SubscriptionController::upgradeOptions($user);
    },
    'POST /api/subscriptions/subscribe' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) SubscriptionController::subscribe($user, $body);
    },
    'POST /api/subscriptions/cancel' => function() {
        $user = AuthMiddleware::handle();
        if ($user) SubscriptionController::cancel($user);
    },
    'POST /api/subscriptions/upgrade' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) SubscriptionController::upgrade($user, $body);
    },
    'GET /api/subscriptions/renew' => function() {
        $user = AuthMiddleware::handle();
        if ($user) SubscriptionController::renew($user);
    },

    // =====================
    // Payments
    // =====================
    'POST /api/payment/stripe/create' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) PaymentController::createStripePayment($user, $body);
    },
    'POST /api/payment/stripe/webhook' => fn() => PaymentController::stripeWebhook(),
    'POST /api/payment/crypto/create' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) PaymentController::createCryptoPayment($user, $body);
    },
    'GET /api/payment/crypto/verify/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) PaymentController::verifyCryptoPayment((int)$id, $user);
    },
    'GET /api/payment/crypto/addresses' => fn() => PaymentController::getCryptoAddresses(),

    // =====================
    // Licenses
    // =====================
    'POST /api/license/verify' => fn() => LicenseController::verify($body),
    'GET /api/licenses' => function() {
        $user = AuthMiddleware::handle();
        if ($user) LicenseController::index($user);
    },
    'GET /api/licenses/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) LicenseController::show($user, (int)$id);
    },
    'POST /api/licenses/generate' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) LicenseController::generate($user, $body);
    },
    'POST /api/licenses/(\d+)/reissue' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) LicenseController::reissue($user, (int)$id);
    },
    'GET /api/licenses/(\d+)/checks' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) LicenseController::checks($user, (int)$id);
    },

    // =====================
    // Orders
    // =====================
    'GET /api/orders' => function() {
        $user = AuthMiddleware::handle();
        if ($user) OrderController::index($user);
    },
    'POST /api/orders' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) OrderController::store($user, $body);
    },
    'GET /api/orders/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) OrderController::show($user, (int)$id);
    },
    'POST /api/orders/(\d+)/cancel' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) OrderController::cancel($user, (int)$id);
    },

    // =====================
    // Tickets
    // =====================
    'GET /api/tickets' => function() {
        $user = AuthMiddleware::handle();
        if ($user) TicketController::index($user);
    },
    'GET /api/tickets/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) TicketController::show($user, (int)$id);
    },
    'POST /api/tickets' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) TicketController::store($user, $body);
    },
    'POST /api/tickets/(\d+)/reply' => function($id) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) TicketController::reply($user, (int)$id, $body);
    },
    'POST /api/tickets/(\d+)/close' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) TicketController::close($user, (int)$id);
    },

    // =====================
    // Passkey auth (unauthenticated)
    // =====================
    'GET /api/auth/passkey/options' => fn() => PasskeyController::authenticateOptions($_GET),
    'POST /api/auth/passkey/verify' => fn() => PasskeyController::authenticateVerify($body),

    // =====================
    // Passkey management (authenticated)
    // =====================
    'GET /api/passkeys' => function() {
        $user = AuthMiddleware::handle();
        if ($user) PasskeyController::list($user);
    },
    'GET /api/passkeys/register-options' => function() {
        $user = AuthMiddleware::handle();
        if ($user) PasskeyController::registerOptions($user);
    },
    'POST /api/passkeys/register-verify' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) PasskeyController::registerVerify($user, $body);
    },
    'PUT /api/passkeys/(\d+)' => function($id) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) PasskeyController::rename($user, (int)$id, $body);
    },
    'DELETE /api/passkeys/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) PasskeyController::delete($user, (int)$id);
    },

    // =====================
    // Balance
    // =====================
    'GET /api/balance' => function() {
        $user = AuthMiddleware::handle();
        if ($user) BalanceController::getBalance($user);
    },
    'GET /api/balance/transactions' => function() {
        $user = AuthMiddleware::handle();
        if ($user) BalanceController::getTransactions($user);
    },

    // =====================
    // User routes
    // =====================
    'GET /api/user/downloads' => function() {
        $user = AuthMiddleware::handle();
        if ($user) UserController::downloads($user);
    },
    'PUT /api/user/profile' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) UserController::updateProfile($user, $body);
    },
    'PUT /api/user/password' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) UserController::updatePassword($user, $body);
    },
    'POST /api/user/avatar' => function() {
        $user = AuthMiddleware::handle();
        if ($user) UserController::uploadAvatar($user);
    },
    'DELETE /api/user/avatar' => function() {
        $user = AuthMiddleware::handle();
        if ($user) UserController::deleteAvatar($user);
    },
    'DELETE /api/user/account' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) UserController::deleteAccount($user, $body);
    },

    // =====================
    // Activity Logs (user-facing)
    // =====================
    'GET /api/user/activity-logs' => function() {
        $user = AuthMiddleware::handle();
        if ($user) ActivityLogController::index($user);
    },
    'GET /api/user/login-history' => function() {
        $user = AuthMiddleware::handle();
        if ($user) ActivityLogController::loginHistory($user);
    },

    // =====================
    // Billing Info
    // =====================
    'GET /api/user/billing' => function() {
        $user = AuthMiddleware::handle();
        if ($user) UserController::getBilling($user);
    },
    'PUT /api/user/billing' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) UserController::updateBilling($user, $body);
    },

    // =====================
    // Notifications
    // =====================
    'GET /api/notifications' => function() {
        $user = AuthMiddleware::handle();
        if ($user) NotificationController::index($user);
    },
    'GET /api/notifications/unread-count' => function() {
        $user = AuthMiddleware::handle();
        if ($user) NotificationController::unreadCount($user);
    },
    'PUT /api/notifications/(\d+)/read' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) NotificationController::markAsRead($user, (int)$id);
    },
    'PUT /api/notifications/read-all' => function() {
        $user = AuthMiddleware::handle();
        if ($user) NotificationController::markAllAsRead($user);
    },
    'DELETE /api/notifications/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) NotificationController::delete($user, (int)$id);
    },

    // =====================
    // Two-Factor Authentication (TOTP)
    // =====================
    'GET /api/user/2fa/status' => function() {
        $user = AuthMiddleware::handle();
        if ($user) TotpController::status($user);
    },
    'POST /api/user/2fa/setup' => function() {
        $user = AuthMiddleware::handle();
        if ($user) TotpController::setup($user);
    },
    'POST /api/user/2fa/enable' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) TotpController::enable($user, $body);
    },
    'POST /api/user/2fa/disable' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) TotpController::disable($user, $body);
    },
    'POST /api/user/2fa/recovery-codes' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) TotpController::regenerateRecoveryCodes($user, $body);
    },

    // =====================
    // Webhooks
    // =====================
    'GET /api/webhooks' => function() {
        $user = AuthMiddleware::handle();
        if ($user) WebhookController::index($user);
    },
    'POST /api/webhooks' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) WebhookController::store($user, $body);
    },
    'PUT /api/webhooks/(\d+)' => function($id) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) WebhookController::update($user, (int)$id, $body);
    },
    'DELETE /api/webhooks/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) WebhookController::delete($user, (int)$id);
    },
    'POST /api/webhooks/(\d+)/regenerate-secret' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) WebhookController::regenerateSecret($user, (int)$id);
    },
    'GET /api/webhooks/(\d+)/logs' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) WebhookController::logs($user, (int)$id);
    },
    'POST /api/webhooks/(\d+)/test' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) WebhookController::test($user, (int)$id);
    },

    // =====================
    // Favorite Collections
    // =====================
    'GET /api/favorites/collections' => function() {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteCollectionController::index($user);
    },
    'POST /api/favorites/collections' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteCollectionController::store($user, $body);
    },
    'PUT /api/favorites/collections/(\d+)' => function($id) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteCollectionController::update($user, (int)$id, $body);
    },
    'DELETE /api/favorites/collections/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteCollectionController::delete($user, (int)$id);
    },
    'GET /api/favorites/collections/(\d+)/items' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteCollectionController::items($user, (int)$id);
    },
    'PUT /api/favorites/(\d+)/collection' => function($moduleId) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) FavoriteCollectionController::moveToCollection($user, (int)$moduleId, $body);
    },

    // =====================
    // User Data Export (GDPR)
    // =====================
    'GET /api/user/export' => function() {
        $user = AuthMiddleware::handle();
        if ($user) ExportController::exportData($user);
    },
    'GET /api/consent' => function() {
        $user = AuthMiddleware::optional();
        CookieConsentController::current($user);
    },
    'POST /api/consent' => function() use ($body) {
        $user = AuthMiddleware::optional();
        CookieConsentController::store($user, $body);
    },

    // =====================
    // Invoices
    // =====================
    'GET /api/orders/(\d+)/invoice' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) InvoiceController::show($user, (int)$id);
    },

    // =====================
    // Redeem Codes
    // =====================
    'POST /api/redeem/validate' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) RedeemController::validate($user, $body);
    },
    'POST /api/redeem/apply' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) RedeemController::redeem($user, $body);
    },

    // =====================
    // Coupons
    // =====================
    'POST /api/coupons/validate' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) CouponController::validate($user, $body);
    },
    'POST /api/coupons/apply' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) CouponController::apply($user, $body);
    },
    'GET /api/coupons/history' => function() {
        $user = AuthMiddleware::handle();
        if ($user) CouponController::history($user);
    },

    // =====================
    // Updates
    // =====================
    'GET /api/updates' => function() {
        $user = AuthMiddleware::handle();
        if ($user) UpdateController::list($user, $_GET);
    },
    'GET /api/updates/unread-count' => function() {
        $user = AuthMiddleware::handle();
        if ($user) UpdateController::unreadCount($user);
    },
    'PUT /api/updates/(\d+)/read' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) UpdateController::markAsRead($user, (int)$id);
    },
    'PUT /api/updates/read-all' => function() {
        $user = AuthMiddleware::handle();
        if ($user) UpdateController::markAllAsRead($user);
    },
    'GET /api/releases/recent' => fn() => UpdateController::recentReleases($_GET),

    // =====================
    // Documents
    // =====================
    'GET /api/docs/categories' => fn() => DocumentController::categories(),
    'GET /api/docs' => fn() => DocumentController::index(),
    'GET /api/docs/search' => fn() => DocumentController::search(),
    'GET /api/docs/category/([a-z0-9-]+)' => fn($slug) => DocumentController::getByCategory($slug),
    // Document feedback (must be before slug route)
    'GET /api/docs/(\d+)/feedback' => function($id) {
        $user = AuthMiddleware::optional();
        DocumentFeedbackController::status($user, (int)$id);
    },
    'POST /api/docs/(\d+)/feedback' => function($id) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) DocumentFeedbackController::submit($user, (int)$id, $body);
    },
    'DELETE /api/docs/(\d+)/feedback' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) DocumentFeedbackController::remove($user, (int)$id);
    },
    'GET /api/docs/([a-z0-9-]+)' => fn($slug) => DocumentController::show($slug),

    // =====================
    // Announcements
    // =====================
    'GET /api/announcements/categories' => fn() => AnnouncementController::categories(),
    'GET /api/announcements' => fn() => AnnouncementController::index(),
    'GET /api/announcements/([a-z0-9-]+)' => fn($slug) => AnnouncementController::show($slug),

    // =====================
    // Public config (turnstile key etc.)
    // =====================
    'GET /api/config/public' => fn() => Response::success([
        'turnstile_site_key' => \App\Models\Setting::get('turnstile_site_key', ''),
        'enable_turnstile' => \App\Models\Setting::getBool('enable_turnstile', false),
        'enable_passkey' => \App\Models\Setting::getBool('enable_passkey', true),
        'cookie_consent_required' => \App\Models\Setting::getBool('cookie_consent_required', true),
    ]),

    // =====================
    // Legal pages
    // =====================
    'GET /api/legal' => fn() => LegalController::list(),
    'GET /api/legal/([a-z-]+)' => fn($slug) => LegalController::show($slug),

    // =====================
    // WHMCS Deploy
    // =====================
    'GET /api/deploy/instances' => function() {
        $user = AuthMiddleware::handle();
        if ($user) DeployController::listInstances($user);
    },
    'POST /api/deploy/instances' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) DeployController::createInstance($user, $body);
    },
    'PUT /api/deploy/instances/(\d+)' => function($id) use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) DeployController::updateInstance($user, (int)$id, $body);
    },
    'DELETE /api/deploy/instances/(\d+)' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) DeployController::deleteInstance($user, (int)$id);
    },
    'POST /api/deploy/instances/(\d+)/regenerate-key' => function($id) {
        $user = AuthMiddleware::handle();
        if ($user) DeployController::regenerateKey($user, (int)$id);
    },
    'POST /api/deploy/module' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) DeployController::deployModule($user, $body);
    },
    'GET /api/deploy/logs' => function() {
        $user = AuthMiddleware::handle();
        if ($user) DeployController::deploymentLogs($user);
    },

    // WHMCS Client Plugin API (used by WHMCS side)
    'POST /api/deploy/api/modules' => fn() => DeployController::apiCheckModules($body),
    'GET /api/deploy/download/(\d+)' => fn($id) => DeployController::apiDownloadModule((int)$id),

    // =====================
    // Affiliate / Referral Program
    // =====================
    'GET /api/affiliate/dashboard' => function() {
        $user = AuthMiddleware::handle();
        if ($user) AffiliateController::dashboard($user);
    },
    'GET /api/affiliate/referrals' => function() {
        $user = AuthMiddleware::handle();
        if ($user) AffiliateController::referrals($user);
    },
    'GET /api/affiliate/commissions' => function() {
        $user = AuthMiddleware::handle();
        if ($user) AffiliateController::commissions($user);
    },
    'POST /api/affiliate/payouts' => function() use ($body) {
        $user = AuthMiddleware::handle();
        if ($user) AffiliateController::requestPayout($user, $body);
    },
    'GET /api/affiliate/payouts' => function() {
        $user = AuthMiddleware::handle();
        if ($user) AffiliateController::payouts($user);
    },

    // =====================
    // Admin routes
    // =====================
    'GET /api/admin/dashboard' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminDashboardController::index();
    },

    // Admin - Modules
    'GET /api/admin/modules' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::index();
    },
    'POST /api/admin/modules' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::store($body, $user);
    },
    // Batch operations
    'POST /api/admin/modules/batch' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::batchCreate($body, $user);
    },
    'PUT /api/admin/modules/batch' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::batchUpdate($body, $user);
    },
    'DELETE /api/admin/modules/batch' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::batchDelete($body, $user);
    },
    'POST /api/admin/modules/import' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::import($user);
    },
    'GET /api/admin/modules/export' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::export();
    },
    'GET /api/admin/modules/import-template' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::importTemplate();
    },
    'PUT /api/admin/modules/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::update((int)$id, $body, $user);
    },
    'DELETE /api/admin/modules/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::delete((int)$id, $user);
    },
    'POST /api/admin/modules/(\d+)/upload' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::upload((int)$id);
    },
    'POST /api/admin/modules/(\d+)/icon' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminModuleController::uploadIcon((int)$id);
    },

    // Admin - Module Screenshots
    'GET /api/admin/modules/(\d+)/screenshots' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminScreenshotController::index((int)$id);
    },
    'POST /api/admin/modules/(\d+)/screenshots' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminScreenshotController::upload((int)$id);
    },
    'PUT /api/admin/screenshots/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminScreenshotController::update((int)$id, $body);
    },
    'DELETE /api/admin/screenshots/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminScreenshotController::delete((int)$id);
    },
    'POST /api/admin/modules/(\d+)/screenshots/reorder' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminScreenshotController::reorder((int)$id, $body);
    },

    // Admin - Users
    'GET /api/admin/users' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminUserController::index();
    },
    'GET /api/admin/users/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminUserController::show((int)$id);
    },
    'PUT /api/admin/users/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminUserController::update((int)$id, $body, $user);
    },
    'DELETE /api/admin/users/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminUserController::delete((int)$id, $user);
    },
    'POST /api/admin/users/(\d+)/ban' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) {
            \App\Models\User::ban((int)$id, $body['reason'] ?? null);
            \App\Models\AdminAuditLog::log($user['id'], 'user.ban', 'user', (int)$id, 'Banned user', null, ['reason' => $body['reason'] ?? null]);
            Response::success(null, 'User banned');
        }
    },
    'POST /api/admin/users/(\d+)/unban' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) {
            \App\Models\User::unban((int)$id);
            \App\Models\AdminAuditLog::log($user['id'], 'user.unban', 'user', (int)$id, 'Unbanned user');
            Response::success(null, 'User unbanned');
        }
    },

    // Admin - Licenses
    'GET /api/admin/licenses' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminLicenseController::index();
    },
    'POST /api/admin/licenses' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLicenseController::store($body, $user);
    },
    'PUT /api/admin/licenses/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLicenseController::update((int)$id, $body, $user);
    },
    'DELETE /api/admin/licenses/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLicenseController::delete((int)$id, $user);
    },
    'GET /api/admin/licenses/(\d+)/checks' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLicenseController::checks((int)$id);
    },

    // Admin - Payments
    'GET /api/admin/payments' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminDashboardController::payments();
    },
    'PUT /api/admin/payments/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDashboardController::updatePayment((int)$id, $body, $user);
    },

    // Admin - Crypto Addresses
    'GET /api/admin/crypto-addresses' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminCryptoAddressController::index();
    },
    'POST /api/admin/crypto-addresses' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCryptoAddressController::store($body, $user);
    },
    'PUT /api/admin/crypto-addresses/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCryptoAddressController::update((int)$id, $body, $user);
    },
    'DELETE /api/admin/crypto-addresses/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCryptoAddressController::delete((int)$id, $user);
    },

    // Admin - Orders
    'GET /api/admin/orders' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminOrderController::index();
    },
    'GET /api/admin/orders/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminOrderController::show((int)$id);
    },
    'PUT /api/admin/orders/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminOrderController::update((int)$id, $body, $user);
    },

    // Admin - Tickets
    'GET /api/admin/tickets' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminTicketController::index();
    },
    'GET /api/admin/tickets/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminTicketController::show((int)$id);
    },
    'POST /api/admin/tickets/(\d+)/reply' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminTicketController::reply((int)$id, $body, $user);
    },
    'PUT /api/admin/tickets/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminTicketController::update((int)$id, $body, $user);
    },
    'POST /api/admin/tickets/(\d+)/close' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminTicketController::close((int)$id, $user);
    },
    'GET /api/admin/tickets/stats' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminTicketController::stats();
    },

    // Admin - Reviews
    'GET /api/admin/reviews' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminReviewController::index();
    },
    'POST /api/admin/reviews/(\d+)/approve' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminReviewController::approve((int)$id, $user);
    },
    'POST /api/admin/reviews/(\d+)/reject' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminReviewController::reject((int)$id, $user);
    },
    'POST /api/admin/reviews/(\d+)/reply' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminReviewController::reply((int)$id, $body, $user);
    },
    'DELETE /api/admin/reviews/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminReviewController::delete((int)$id, $user);
    },

    // Admin - Feature Requests
    'GET /api/admin/feature-requests' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminFeedbackController::listFeatureRequests();
    },
    'PUT /api/admin/feature-requests/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminFeedbackController::updateFeatureRequest((int)$id, $body);
    },
    'DELETE /api/admin/feature-requests/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminFeedbackController::deleteFeatureRequest((int)$id);
    },

    // Admin - Bug Reports
    'GET /api/admin/bug-reports' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminFeedbackController::listBugReports();
    },
    'PUT /api/admin/bug-reports/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminFeedbackController::updateBugReport((int)$id, $body);
    },
    'DELETE /api/admin/bug-reports/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminFeedbackController::deleteBugReport((int)$id);
    },

    // Admin - Coupons
    'GET /api/admin/coupons' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminCouponController::index();
    },
    'GET /api/admin/coupons/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCouponController::show((int)$id);
    },
    'POST /api/admin/coupons' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCouponController::store($body, $user);
    },
    'PUT /api/admin/coupons/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCouponController::update((int)$id, $body, $user);
    },
    'DELETE /api/admin/coupons/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCouponController::delete((int)$id, $user);
    },
    'GET /api/admin/coupons/(\d+)/usages' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminCouponController::usages((int)$id);
    },

    // Admin - Redeem Codes
    'GET /api/admin/redeem-codes' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminRedeemCodeController::index();
    },
    'GET /api/admin/redeem-codes/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminRedeemCodeController::show((int)$id);
    },
    'POST /api/admin/redeem-codes' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminRedeemCodeController::store($body, $user);
    },
    'POST /api/admin/redeem-codes/batch' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminRedeemCodeController::batchCreate($body, $user);
    },
    'PUT /api/admin/redeem-codes/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminRedeemCodeController::update((int)$id, $body);
    },
    'DELETE /api/admin/redeem-codes/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminRedeemCodeController::delete((int)$id);
    },

    // Admin - Announcements
    'GET /api/admin/announcements' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::index();
    },
    'GET /api/admin/announcements/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::show((int)$id);
    },
    'POST /api/admin/announcements' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::store($body);
    },
    'PUT /api/admin/announcements/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::update((int)$id, $body);
    },
    'DELETE /api/admin/announcements/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::delete((int)$id);
    },
    'GET /api/admin/announcement-categories' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::listCategories();
    },
    'POST /api/admin/announcement-categories' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::storeCategory($body);
    },
    'PUT /api/admin/announcement-categories/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::updateCategory((int)$id, $body);
    },
    'DELETE /api/admin/announcement-categories/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::deleteCategory((int)$id);
    },

    // Admin - Documents
    'GET /api/admin/docs' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::index();
    },
    'GET /api/admin/docs/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::show((int)$id);
    },
    'POST /api/admin/docs' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::store($body);
    },
    'PUT /api/admin/docs/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::update((int)$id, $body);
    },
    'DELETE /api/admin/docs/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::delete((int)$id);
    },
    'GET /api/admin/doc-categories' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::listCategories();
    },
    'POST /api/admin/doc-categories' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::storeCategory($body);
    },
    'PUT /api/admin/doc-categories/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::updateCategory((int)$id, $body);
    },
    'DELETE /api/admin/doc-categories/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminDocumentController::deleteCategory((int)$id);
    },

    // Admin - Legal Pages
    'GET /api/admin/legal' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminLegalController::index();
    },
    'GET /api/admin/legal/([a-z-]+)' => function($slug) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLegalController::show($slug);
    },
    'POST /api/admin/legal' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLegalController::store($body);
    },
    'PUT /api/admin/legal/([a-z-]+)' => function($slug) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLegalController::update($slug, $body, $user);
    },
    'GET /api/admin/legal/([a-z-]+)/versions' => function($slug) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLegalController::versions($slug);
    },
    'DELETE /api/admin/legal/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminLegalController::delete((int)$id);
    },

    // Admin - Module Categories
    'GET /api/admin/module-categories' => function() {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\ModuleCategoryController::index();
    },
    'GET /api/admin/module-categories/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\ModuleCategoryController::show((int)$id);
    },
    'POST /api/admin/module-categories' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\ModuleCategoryController::store($body);
    },
    'PUT /api/admin/module-categories/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\ModuleCategoryController::update((int)$id, $body);
    },
    'DELETE /api/admin/module-categories/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\ModuleCategoryController::delete((int)$id);
    },

    // Admin - Module Versions
    'GET /api/admin/modules/(\d+)/versions' => function($moduleId) {
        $user = AdminMiddleware::handle();
        if ($user) AdminVersionController::index((int)$moduleId);
    },
    'POST /api/admin/modules/(\d+)/versions' => function($moduleId) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminVersionController::store((int)$moduleId, $body);
    },
    'GET /api/admin/versions/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminVersionController::show((int)$id);
    },
    'PUT /api/admin/versions/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminVersionController::update((int)$id, $body);
    },
    'DELETE /api/admin/versions/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminVersionController::delete((int)$id);
    },
    'POST /api/admin/versions/(\d+)/upload' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminVersionController::upload((int)$id);
    },

    // Admin - User Balance
    'GET /api/admin/users/(\d+)/balance' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminBalanceController::getUserBalance((int)$id);
    },
    'POST /api/admin/users/(\d+)/balance/credit' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminBalanceController::creditUser((int)$id, $body, $user);
    },
    'POST /api/admin/users/(\d+)/balance/debit' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminBalanceController::debitUser((int)$id, $body, $user);
    },
    'GET /api/admin/users/(\d+)/balance/transactions' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminBalanceController::getTransactions((int)$id);
    },

    // Admin - Activity Logs
    'GET /api/admin/activity-logs' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminActivityLogController::index();
    },
    'GET /api/admin/activity-logs/stats' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminActivityLogController::stats();
    },
    'GET /api/admin/users/(\d+)/activity-logs' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminActivityLogController::userLogs((int)$id);
    },

    // Admin - Announcement Attachments
    'GET /api/admin/announcements/(\d+)/attachments' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::listAttachments((int)$id);
    },
    'POST /api/admin/announcements/(\d+)/attachments' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::uploadAttachment((int)$id);
    },
    'DELETE /api/admin/attachments/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAnnouncementController::deleteAttachment((int)$id);
    },

    // Admin - Image Upload (for content editors)
    'POST /api/admin/upload/image' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminUploadController::uploadImage();
    },

    // Admin - Audit Logs
    'GET /api/admin/audit-logs' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminAuditLogController::index();
    },

    // Admin - AI Assistant
    'POST /api/admin/ai/ticket-reply' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAiController::ticketReply($body);
    },
    'POST /api/admin/ai/announcement' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAiController::announcement($body);
    },
    'POST /api/admin/ai/translate' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAiController::translate($body);
    },
    'POST /api/admin/ai/help-doc' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAiController::helpDoc($body);
    },
    'POST /api/admin/ai/review' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAiController::review($body);
    },
    'POST /api/admin/ai/polish' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAiController::polish($body);
    },
    'POST /api/admin/ai/chat' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAiController::chat($body);
    },

    // Admin - Affiliates
    'GET /api/admin/affiliates' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminAffiliateController::index();
    },
    'GET /api/admin/affiliates/stats' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminAffiliateController::stats();
    },
    'GET /api/admin/affiliates/commissions' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminAffiliateController::commissions();
    },
    'PUT /api/admin/affiliates/commissions/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAffiliateController::updateCommission((int)$id, $body, $user);
    },
    'GET /api/admin/affiliates/payouts' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminAffiliateController::payouts();
    },
    'PUT /api/admin/affiliates/payouts/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminAffiliateController::updatePayout((int)$id, $body, $user);
    },

    // Admin - Settings
    'GET /api/admin/settings' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminSettingController::index();
    },
    'GET /api/admin/settings/group/([a-z]+)' => function($group) {
        $user = AdminMiddleware::handle();
        if ($user) AdminSettingController::getGroup($group);
    },
    'PUT /api/admin/settings' => function() use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) AdminSettingController::update($body, $user);
    },
    'GET /api/admin/data-classifications' => function() {
        $user = AdminMiddleware::handle();
        if ($user) AdminDataClassificationController::index();
    },

    // Admin - Email Templates
    'GET /api/admin/email-templates' => function() {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\EmailTemplateController::index();
    },
    'GET /api/admin/email-templates/(\d+)' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\EmailTemplateController::show((int)$id);
    },
    'PUT /api/admin/email-templates/(\d+)' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\EmailTemplateController::update((int)$id, $body);
    },
    'POST /api/admin/email-templates/(\d+)/preview' => function($id) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\EmailTemplateController::preview((int)$id);
    },
    'POST /api/admin/email-templates/(\d+)/test' => function($id) use ($body) {
        $user = AdminMiddleware::handle();
        if ($user) \App\Controllers\Admin\EmailTemplateController::sendTest((int)$id, $body);
    },

    // =====================
    // Cron / Scheduled Tasks
    // =====================
    'GET /api/cron/run-all' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::runAll();
    },
    'GET /api/cron/expire-subscriptions' => function() use ($verifyCronKey) {
        $verifyCronKey();
        SubscriptionController::handleExpired();
    },
    'GET /api/cron/subscription-reminders' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::subscriptionReminders();
    },
    'GET /api/cron/cancel-expired-payments' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::cancelExpiredPayments();
    },
    'GET /api/cron/verify-crypto-payments' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::verifyCryptoPayments();
    },
    'GET /api/cron/expire-licenses' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::expireLicenses();
    },
    'GET /api/cron/retry-webhooks' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::retryFailedWebhooks();
    },
    'GET /api/cron/clean-rate-limits' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::cleanRateLimits();
    },
    'GET /api/cron/clean-notifications' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::cleanOldNotifications();
    },
    'GET /api/cron/clean-webhook-logs' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::cleanOldWebhookLogs();
    },
    'GET /api/cron/clean-activity-logs' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::cleanOldActivityLogs();
    },
    'GET /api/cron/archive-audit-logs' => function() use ($verifyCronKey) {
        $verifyCronKey();
        CronController::archiveAdminAuditLogs();
    },
];

// Match route
$matched = false;
foreach ($routes as $route => $handler) {
    [$routeMethod, $routePattern] = explode(' ', $route, 2);

    if ($method !== $routeMethod) {
        continue;
    }

    $pattern = '#^' . $routePattern . '$#';

    if (preg_match($pattern, $uri, $matches)) {
        array_shift($matches);
        $handler(...$matches);
        $matched = true;
        break;
    }
}

if (!$matched) {
    Response::notFound('Endpoint not found');
}
