import { readFileSync } from 'fs';
import { resolve } from 'path';
import { ClientError } from './errors.js';
import { createLogger } from './logger.js';
import { normalizeServerUrl } from './utils.js';
const logger = createLogger('config');
export function loadConfig(configPath) {
    const absolutePath = resolve(configPath);
    try {
        logger.debug(`Loading config from: ${absolutePath}`);
        const content = readFileSync(absolutePath, 'utf-8');
        const config = JSON.parse(content);
        if (!config.mcpServers || typeof config.mcpServers !== 'object') {
            throw new ClientError(`Invalid config file format: missing or invalid "mcpServers" field.\n` +
                `Expected: { "mcpServers": { "server-name": {...} } }`);
        }
        logger.debug(`Loaded ${Object.keys(config.mcpServers).length} server(s) from config`);
        return config;
    }
    catch (error) {
        if (error.code === 'ENOENT') {
            throw new ClientError(`Config file not found: ${absolutePath}`);
        }
        if (error instanceof SyntaxError) {
            throw new ClientError(`Invalid JSON in config file: ${absolutePath}\n${error.message}`);
        }
        if (error instanceof ClientError) {
            throw error;
        }
        throw new ClientError(`Failed to load config file: ${absolutePath}\n${error.message}`);
    }
}
export function getServerConfig(config, serverName) {
    const serverConfig = config.mcpServers[serverName];
    if (!serverConfig) {
        const availableServers = Object.keys(config.mcpServers);
        throw new ClientError(`Server "${serverName}" not found in config file.\n` +
            `Available servers: ${availableServers.join(', ')}`);
    }
    const substituted = substituteEnvVars(serverConfig);
    logger.debug(`Retrieved config for server: ${serverName}`, substituted);
    return substituted;
}
function substituteEnvVars(config) {
    const result = {};
    if (config.url !== undefined) {
        const substituted = substituteString(config.url);
        try {
            result.url = normalizeServerUrl(substituted);
        }
        catch (error) {
            throw new ClientError(`Invalid URL in server config: ${substituted}\n${error.message}`);
        }
    }
    if (config.command !== undefined) {
        result.command = substituteString(config.command);
    }
    if (config.args !== undefined) {
        result.args = config.args.map(substituteString);
    }
    if (config.env !== undefined) {
        result.env = substituteEnvObject(config.env);
    }
    if (config.headers !== undefined) {
        result.headers = substituteEnvObject(config.headers);
    }
    if (config.timeout !== undefined) {
        result.timeout = config.timeout;
    }
    return result;
}
function substituteString(str) {
    return str.replace(/\$\{([^}]+)}/g, (_match, varName) => {
        const value = process.env[varName];
        if (value === undefined) {
            logger.warn(`Environment variable not found: ${varName}, using empty string`);
            return '';
        }
        return value;
    });
}
function substituteEnvObject(obj) {
    const result = {};
    for (const [key, value] of Object.entries(obj)) {
        result[key] = substituteString(value);
    }
    return result;
}
export function listServers(config) {
    return Object.keys(config.mcpServers);
}
export function validateServerConfig(config) {
    const hasUrl = config.url !== undefined;
    const hasCommand = config.command !== undefined;
    if (!hasUrl && !hasCommand) {
        throw new ClientError('Invalid server config: must specify either "url" (for HTTP) or "command" (for stdio)');
    }
    if (hasUrl && hasCommand) {
        throw new ClientError('Invalid server config: cannot specify both "url" and "command"');
    }
    if (config.url !== undefined) {
        if (typeof config.url !== 'string' || config.url.trim() === '') {
            throw new ClientError('Invalid server config: "url" must be a non-empty string');
        }
        if (!config.url.startsWith('http://') && !config.url.startsWith('https://')) {
            throw new ClientError(`Invalid server config: "url" must start with http:// or https://, got: ${config.url}`);
        }
    }
    if (config.command !== undefined) {
        if (typeof config.command !== 'string' || config.command.trim() === '') {
            throw new ClientError('Invalid server config: "command" must be a non-empty string');
        }
    }
    return true;
}
//# sourceMappingURL=config.js.map