import { createHash } from 'crypto';
import { homedir } from 'os';
import { join, resolve, isAbsolute } from 'path';
import { mkdir, access, constants, stat } from 'fs/promises';
import { ClientError } from './errors.js';
export function expandHome(filepath) {
    if (filepath.startsWith('~/') || filepath === '~') {
        return join(homedir(), filepath.slice(1));
    }
    return filepath;
}
export function resolvePath(filepath, basePath) {
    const expanded = expandHome(filepath);
    if (isAbsolute(expanded)) {
        return resolve(expanded);
    }
    return resolve(basePath || process.cwd(), expanded);
}
export function getMcpcHome() {
    const envHome = process.env.MCPC_HOME_DIR;
    if (envHome) {
        return resolvePath(envHome);
    }
    return expandHome('~/.mcpc');
}
export function getSessionsFilePath() {
    return join(getMcpcHome(), 'sessions.json');
}
export function getBridgesDir() {
    return join(getMcpcHome(), 'bridges');
}
export function getSocketPath(sessionName) {
    if (process.platform === 'win32') {
        const homeHash = createHash('sha256').update(getMcpcHome()).digest('hex').slice(0, 8);
        return `\\\\.\\pipe\\mcpc-${homeHash}-${sessionName}`;
    }
    return join(getBridgesDir(), `${sessionName}.sock`);
}
export function getLogsDir() {
    return join(getMcpcHome(), 'logs');
}
export function getAuthProfilesFilePath() {
    return join(getMcpcHome(), 'profiles.json');
}
export async function ensureDir(dirPath) {
    try {
        await mkdir(dirPath, { recursive: true });
    }
    catch (error) {
        if (error.code !== 'EEXIST') {
            throw error;
        }
    }
}
export async function fileExists(filepath) {
    try {
        await access(filepath, constants.F_OK);
        return true;
    }
    catch {
        return false;
    }
}
export async function isFile(filepath) {
    try {
        const stats = await stat(filepath);
        return stats.isFile();
    }
    catch {
        return false;
    }
}
export async function isDirectory(filepath) {
    try {
        const stats = await stat(filepath);
        return stats.isDirectory();
    }
    catch {
        return false;
    }
}
export function isValidHttpUrl(str) {
    try {
        const url = new URL(str);
        return url.protocol === 'http:' || url.protocol === 'https:';
    }
    catch {
        return false;
    }
}
export function normalizeServerUrl(str) {
    let urlString = str;
    if (!str.includes('://')) {
        const hostPart = (str.split(/[:/]/)[0] || '').toLowerCase();
        const isLocalhost = hostPart === 'localhost' || hostPart === '127.0.0.1';
        urlString = isLocalhost ? `http://${str}` : `https://${str}`;
    }
    if (!isValidHttpUrl(urlString)) {
        throw new Error(`Invalid MCP server URL: ${str}`);
    }
    const url = new URL(urlString);
    url.hostname = url.hostname.toLowerCase();
    url.username = '';
    url.password = '';
    url.hash = '';
    let result = url.toString();
    if (url.pathname === '/' && !url.search) {
        result = result.slice(0, -1);
    }
    return result;
}
export function getServerHost(urlString) {
    const url = new URL(normalizeServerUrl(urlString));
    const hostname = url.hostname.toLowerCase();
    const port = url.port;
    if (port && port !== '443' && port !== '80') {
        return `${hostname}:${port}`;
    }
    return hostname;
}
export function isValidSessionName(name) {
    return /^@[a-zA-Z0-9_-]{1,64}$/.test(name);
}
export function isValidProfileName(name) {
    return /^[a-zA-Z0-9_-]{1,64}$/.test(name);
}
export function validateProfileName(profileName) {
    if (!isValidProfileName(profileName)) {
        throw new ClientError(`Invalid profile name: ${profileName}\n` +
            `Profile names must be 1-64 alphanumeric characters with hyphens or underscores only (e.g., personal, work-account).`);
    }
}
export function isValidResourceUri(uri) {
    try {
        new URL(uri);
        return true;
    }
    catch {
        return false;
    }
}
export function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}
export async function waitForFile(filepath, options = {}) {
    const { timeoutMs = 10000, interval = 100 } = options;
    const startTime = Date.now();
    while (true) {
        if (await fileExists(filepath)) {
            return;
        }
        if (Date.now() - startTime >= timeoutMs) {
            throw new Error(`Timeout waiting for file: ${filepath}`);
        }
        await sleep(interval);
    }
}
export function parseJson(json) {
    try {
        return JSON.parse(json);
    }
    catch (error) {
        throw new Error(`Invalid JSON: ${error.message}`);
    }
}
export function stringifyJson(obj, pretty = false) {
    return JSON.stringify(obj, null, pretty ? 2 : 0);
}
export function truncate(str, maxLength) {
    if (str.length <= maxLength) {
        return str;
    }
    return str.slice(0, maxLength - 3) + '...';
}
export function isProcessAlive(pid) {
    try {
        process.kill(pid, 0);
        return true;
    }
    catch {
        return false;
    }
}
let requestIdCounter = 0;
export function generateRequestId() {
    return `req_${Date.now()}_${++requestIdCounter}`;
}
export const REDACTED_HEADER_VALUE = '<redacted>';
export function redactHeaders(headers) {
    if (Object.keys(headers).length === 0)
        return headers;
    const redacted = {};
    for (const key of Object.keys(headers)) {
        redacted[key] = REDACTED_HEADER_VALUE;
    }
    return redacted;
}
export function isSessionExpiredError(errorMessage) {
    const msg = errorMessage.toLowerCase();
    return ((msg.includes('404') && !msg.includes('tool')) ||
        msg.includes('session expired') ||
        /session(\s+id)?\s+\S+\s+not\s+found/.test(msg) ||
        msg.includes('session not found') ||
        msg.includes('invalid session') ||
        msg.includes('session is no longer valid'));
}
//# sourceMappingURL=utils.js.map