/**
 * 配置管理模块
 * 负责读取环境变量配置
 *
 * 注意：Agent 角色配置（roleName, prompt 等）由后端从 runtime-bridge 获取
 * MCP 客户端只需要传递 workspacePath
 */
import { logger } from "./logger.js";
const DEFAULT_SERVER_URL = "ws://localhost:8080/ws/agent";
const DEFAULT_HEARTBEAT_INTERVAL = 3000; // 3秒发送一次心跳
const DEFAULT_HEARTBEAT_TIMEOUT = 9000; // 9秒未收到心跳响应则断开并重连
const DEFAULT_RECONNECT_INTERVAL = 200;
const DEFAULT_MAX_RECONNECT_ATTEMPTS = -1;
const DEFAULT_RUNTIME_TOKEN_REFRESH_INTERVAL_MS = 12 * 60 * 60 * 1000;
const DEFAULT_MCP_HTTP_REQUEST_TIMEOUT_MS = 120_000;
const DEFAULT_RUNTIME_BRIDGE_BASE_URL = `http://127.0.0.1:${process.env.AWS_RUNTIME_BRIDGE_PORT || "18081"}`;
function repairDuplicatePort(raw) {
    return raw.replace(/^((?:https?|wss?):\/\/(?:\[[^\]]+\]|[^/:?#]+):\d+):\d+(?=\/|$)/i, "$1");
}
function canonicalizeSchedulerHostname(hostname) {
    const normalized = hostname.toLowerCase();
    if (normalized === "localhost" || normalized === "::1" || normalized === "[::1]") {
        return "127.0.0.1";
    }
    return normalized;
}
function normalizeSchedulerBaseUrl(value) {
    const raw = String(value || "").trim();
    if (!raw) {
        return undefined;
    }
    const repaired = repairDuplicatePort(raw);
    try {
        const url = new URL(repaired);
        if (url.protocol === "ws:") {
            url.protocol = "http:";
        }
        else if (url.protocol === "wss:") {
            url.protocol = "https:";
        }
        else {
            url.protocol = url.protocol.toLowerCase();
        }
        url.hostname = canonicalizeSchedulerHostname(url.hostname);
        return url.origin;
    }
    catch {
        return repaired.replace(/\/+$/, "");
    }
}
function toAgentWebSocketUrl(baseUrl) {
    const raw = String(baseUrl || "").trim();
    if (!raw) {
        return undefined;
    }
    const repaired = repairDuplicatePort(raw);
    try {
        const url = new URL(repaired);
        if (url.protocol === "http:") {
            url.protocol = "ws:";
        }
        else if (url.protocol === "https:") {
            url.protocol = "wss:";
        }
        else if (url.protocol !== "ws:" && url.protocol !== "wss:") {
            url.protocol = "ws:";
        }
        url.hostname = canonicalizeSchedulerHostname(url.hostname);
        url.pathname = url.pathname.includes("/ws/agent")
            ? url.pathname
            : `${url.pathname.replace(/\/$/, "")}/ws/agent`;
        url.search = "";
        url.hash = "";
        return url.toString();
    }
    catch {
        const normalized = normalizeSchedulerBaseUrl(repaired);
        return normalized
            ? `${normalized}/ws/agent`.replace(/^http:/, "ws:").replace(/^https:/, "wss:")
            : undefined;
    }
}
function toMcpHttpUrl(baseUrl) {
    const raw = String(baseUrl || "").trim();
    if (!raw) {
        return undefined;
    }
    const repaired = repairDuplicatePort(raw);
    try {
        const url = new URL(repaired);
        if (url.protocol === "ws:") {
            url.protocol = "http:";
        }
        else if (url.protocol === "wss:") {
            url.protocol = "https:";
        }
        else if (url.protocol !== "http:" && url.protocol !== "https:") {
            url.protocol = "http:";
        }
        url.hostname = canonicalizeSchedulerHostname(url.hostname);
        url.pathname = url.pathname.includes("/mcp/call")
            ? url.pathname
            : `${url.pathname.replace(/\/$/, "")}/mcp/call`;
        url.search = "";
        url.hash = "";
        return url.toString();
    }
    catch {
        const normalized = normalizeSchedulerBaseUrl(repaired);
        return normalized ? `${normalized}/mcp/call` : undefined;
    }
}
export class ConfigManager {
    agentConfig = null;
    serverConfig = null;
    /**
     * 加载配置
     * MCP 客户端只提供 workspacePath，角色配置由后端从 runtime-bridge 获取
     */
    loadConfig() {
        const workspacePath = process.env.AWS_WORKSPACE_PATH || process.cwd();
        this.agentConfig = {
            roleName: process.env.AWS_ROLE_NAME || "",
            agentId: process.env.AWS_AGENT_ID || undefined,
            projectName: process.env.AWS_PROJECT_NAME || "default",
            workspacePath: workspacePath,
            prompt: process.env.AWS_PROMPT || "",
            describe: "",
        };
        logger.info(`[Config] MCP 客户端配置已加载`);
        logger.info(`[Config] 工作目录: ${this.agentConfig.workspacePath}`);
        logger.info(`[Config] 项目名: ${this.agentConfig.projectName}`);
        if (this.agentConfig.agentId) {
            logger.info(`[Config] 预设 AgentID: ${this.agentConfig.agentId}`);
        }
        this.serverConfig = {
            serverUrl: process.env.AWS_SERVER_URL || DEFAULT_SERVER_URL,
            heartbeatInterval: parseInt(process.env.AWS_HEARTBEAT_INTERVAL ||
                String(DEFAULT_HEARTBEAT_INTERVAL), 10),
            heartbeatTimeout: parseInt(process.env.AWS_HEARTBEAT_TIMEOUT || String(DEFAULT_HEARTBEAT_TIMEOUT), 10),
            reconnectInterval: DEFAULT_RECONNECT_INTERVAL,
            maxReconnectAttempts: DEFAULT_MAX_RECONNECT_ATTEMPTS,
            userId: process.env.AWS_USER_ID || undefined,
            runtimeBridgeBaseUrl: process.env.AWS_RUNTIME_BRIDGE_BASE_URL || DEFAULT_RUNTIME_BRIDGE_BASE_URL,
            mcpHttpUrl: process.env.AWS_MCP_HTTP_URL || undefined,
            runtimeTokenRefreshIntervalMs: this.parseRuntimeTokenRefreshInterval(),
            mcpHttpRequestTimeoutMs: this.parsePositiveIntegerEnv("AWS_MCP_HTTP_REQUEST_TIMEOUT_MS", DEFAULT_MCP_HTTP_REQUEST_TIMEOUT_MS),
        };
        logger.info(`[Config] 服务器地址: ${this.serverConfig.serverUrl}`);
    }
    applyRuntimeLaunchBinding(binding) {
        if (!this.agentConfig || !this.serverConfig) {
            throw new Error("Configuration is not loaded. Call loadConfig() first.");
        }
        const agentId = String(binding.agentId || "").trim();
        if (agentId) {
            this.agentConfig.agentId = agentId;
        }
        const workspacePath = String(binding.workspacePath || "").trim();
        if (workspacePath) {
            this.agentConfig.workspacePath = workspacePath;
        }
        const runtimeAccessToken = String(binding.runtimeAccessToken || "").trim();
        if (runtimeAccessToken) {
            this.serverConfig.runtimeAccessToken = runtimeAccessToken;
        }
        const runtimeAccessTokenExpiresAt = String(binding.runtimeAccessTokenExpiresAt || "").trim();
        if (runtimeAccessTokenExpiresAt) {
            this.serverConfig.runtimeAccessTokenExpiresAt = runtimeAccessTokenExpiresAt;
        }
        const userId = String(binding.userId || "").trim();
        if (userId) {
            this.serverConfig.userId = userId;
        }
        const serverUrl = toAgentWebSocketUrl(binding.serverUrl || binding.schedulerBaseUrl);
        if (serverUrl) {
            this.serverConfig.serverUrl = serverUrl;
        }
        const mcpHttpUrl = toMcpHttpUrl(binding.mcpHttpUrl);
        if (mcpHttpUrl) {
            this.serverConfig.mcpHttpUrl = mcpHttpUrl;
        }
        else if (binding.schedulerBaseUrl) {
            const schedulerMcpHttpUrl = toMcpHttpUrl(binding.schedulerBaseUrl);
            if (schedulerMcpHttpUrl) {
                this.serverConfig.mcpHttpUrl = schedulerMcpHttpUrl;
            }
        }
        logger.info(`[Config] 已应用 runtime-bridge 启动绑定: agentId=${this.agentConfig.agentId || "(空)"}`);
    }
    parseRuntimeTokenRefreshInterval() {
        return this.parsePositiveIntegerEnv("AWS_RUNTIME_TOKEN_REFRESH_INTERVAL_MS", DEFAULT_RUNTIME_TOKEN_REFRESH_INTERVAL_MS);
    }
    /**
     * 解析正整数环境变量。
     * 主流程：读取字符串 -> 转为整数 -> 非法值回退默认值并记录警告。
     */
    parsePositiveIntegerEnv(name, defaultValue) {
        const raw = process.env[name];
        if (!raw || !raw.trim()) {
            return defaultValue;
        }
        const parsed = Number.parseInt(raw, 10);
        if (!Number.isFinite(parsed) || parsed <= 0) {
            logger.warn(`[Config] ${name} 无效，使用默认值 ${defaultValue}ms`);
            return defaultValue;
        }
        return parsed;
    }
    getAgentConfig() {
        if (!this.agentConfig) {
            throw new Error("Configuration is not loaded. Call loadConfig() first.");
        }
        return this.agentConfig;
    }
    getServerConfig() {
        if (!this.serverConfig) {
            throw new Error("Configuration is not loaded. Call loadConfig() first.");
        }
        return this.serverConfig;
    }
}
export const configManager = new ConfigManager();
//# sourceMappingURL=config.js.map