"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TUNNEL_MINIMAL_TOOLS = void 0;
exports.extractTunnelDomain = extractTunnelDomain;
exports.initTunnelHandler = initTunnelHandler;
exports.resolveTunnelConfig = resolveTunnelConfig;
exports.connectTunnelWebSocket = connectTunnelWebSocket;
const ws_1 = require("ws");
const knowhow_tunnel_1 = require("@tyvm/knowhow-tunnel");
const KnowhowClient_1 = require("./services/KnowhowClient");
const modules_1 = require("./services/modules");
const WsMiddleware_1 = require("./workers/auth/WsMiddleware");
const authMiddleware_1 = require("./workers/auth/authMiddleware");
function extractTunnelDomain(apiUrl) {
    try {
        const url = new URL(apiUrl);
        const useHttps = url.protocol === "https:";
        if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
            return {
                domain: `worker.${url.hostname}:${url.port || "80"}`,
                useHttps,
            };
        }
        return { domain: `worker.${url.hostname}`, useHttps };
    }
    catch (err) {
        console.error("Failed to parse API_URL for tunnel domain:", err);
        return { domain: "worker.localhost:4000", useHttps: false };
    }
}
async function initTunnelHandler(tunnelConnection, tunnelConfig) {
    const handler = (0, knowhow_tunnel_1.createTunnelHandler)(tunnelConnection, tunnelConfig);
    console.log("🌐 Tunnel handler initialized");
    console.log(tunnelConfig);
    const tunnelModuleService = new modules_1.ModulesService();
    const tunnelContext = await tunnelModuleService.overrideDefaultContext({
        Tunnel: handler,
    });
    tunnelModuleService.loadModulesFromConfig(tunnelContext).catch((err) => {
        console.error("Failed to load tunnel modules:", err);
    });
    return handler;
}
function resolveTunnelConfig(config, isInsideDocker) {
    let tunnelLocalHost = config.worker?.tunnel?.localHost;
    if (!tunnelLocalHost) {
        if (isInsideDocker) {
            tunnelLocalHost = "host.docker.internal";
            console.log("🐳 Docker detected: tunnel will use host.docker.internal to reach host services");
        }
        else {
            tunnelLocalHost = "127.0.0.1";
        }
    }
    const portMapping = (config.worker?.tunnel?.portMapping || {});
    if (Object.keys(portMapping).length > 0) {
        console.log("🔀 Port mapping configured:");
        for (const [containerPort, hostPort] of Object.entries(portMapping)) {
            console.log(`   Container port ${containerPort} → Host port ${hostPort}`);
        }
    }
    return { tunnelLocalHost, portMapping };
}
function connectTunnelWebSocket(options) {
    const { tunnelDomain, tunnelUseHttps, tunnelLocalHost, portMapping, config, headers, onOpen, onClose, onError, authService, } = options;
    const tunnelConnection = new ws_1.WebSocket(`${KnowhowClient_1.KNOWHOW_API_URL}/ws/tunnel`, { headers });
    tunnelConnection.on("open", async () => {
        console.log("Tunnel WebSocket connected");
        if (authService) {
            const stack = new WsMiddleware_1.WsMiddlewareStack();
            stack.use((0, authMiddleware_1.makeAuthMiddleware)(authService));
            stack.wrapSocket(tunnelConnection);
        }
        const allowedPorts = config.worker?.tunnel?.allowedPorts || [];
        const urlRewriter = (port, metadata) => {
            const workerId = metadata?.workerId;
            const secret = metadata?.secret;
            const subdomain = secret
                ? `${secret}-p${port}`
                : `${workerId}-p${port}`;
            return `${subdomain}.${tunnelDomain}`;
        };
        const tunnelConfig = {
            allowedPorts,
            maxConcurrentStreams: config.worker?.tunnel?.maxConcurrentStreams || 50,
            tunnelUseHttps,
            localHost: tunnelLocalHost,
            urlRewriter,
            enableUrlRewriting: config.worker?.tunnel?.enableUrlRewriting !== false,
            portMapping,
            logLevel: "debug",
        };
        const handler = await initTunnelHandler(tunnelConnection, tunnelConfig);
        onOpen?.(handler);
    });
    tunnelConnection.on("close", (code, reason) => {
        console.log(`Tunnel WebSocket closed. Code: ${code}, Reason: ${reason.toString()}`);
        onClose?.(code, reason.toString());
    });
    tunnelConnection.on("error", (error) => {
        console.error("Tunnel WebSocket error:", error);
        onError?.(error);
    });
    return tunnelConnection;
}
exports.TUNNEL_MINIMAL_TOOLS = [
    "listAllowedPorts",
    "unlock",
    "lock",
    "reloadConfig",
];
//# sourceMappingURL=tunnel.js.map