import { EventEmitter } from 'node:events';
import process from 'node:process';
import { randomUUID } from 'node:crypto';
import { Readable } from 'node:stream';
import { ReadableStream, TransformStream } from 'node:stream/web';
import { AsyncLocalStorage } from 'node:async_hooks';
import { setTimeout as nodeSetTimeout, clearTimeout as nodeClearTimeout } from 'node:timers';
import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { ListToolsResultSchema, CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
class NodeMCPServerStdio {
    constructor(options) {
        Object.defineProperty(this, "session", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "transport", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "tools", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "cacheDirty", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: true
        });
        Object.defineProperty(this, "timeout", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "nameValue", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "params", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        const normalized = normalizeStdioOptions(options);
        this.params = normalized.params;
        this.timeout = normalized.timeout;
        this.nameValue = normalized.name;
    }
    get name() {
        return this.nameValue;
    }
    async connect() {
        if (this.session) {
            return;
        }
        this.transport = new StdioClientTransport({
            command: this.params.command,
            args: this.params.args,
            env: this.params.env,
            cwd: this.params.cwd,
        });
        this.session = new Client({
            name: this.nameValue,
            version: '1.0.0',
        });
        try {
            await this.session.connect(this.transport);
        }
        catch (error) {
            await this.close();
            throw error;
        }
    }
    async listTools() {
        if (!this.session) {
            throw new Error('Server not initialized. Call connect() first.');
        }
        if (!this.cacheDirty && this.tools) {
            return this.tools;
        }
        const response = await this.session.listTools();
        const parsed = ListToolsResultSchema.parse(response);
        this.tools = parsed.tools;
        this.cacheDirty = false;
        return parsed.tools;
    }
    async callTool(toolName, args, timeoutMs) {
        if (!this.session) {
            throw new Error('Server not initialized. Call connect() first.');
        }
        const response = await this.session.callTool({
            name: toolName,
            arguments: args ?? {},
        }, undefined, {
            timeout: timeoutMs ?? this.timeout,
        });
        return CallToolResultSchema.parse(response).content;
    }
    async invalidateToolsCache() {
        this.cacheDirty = true;
        this.tools = null;
    }
    async close() {
        if (this.transport) {
            await this.transport.close();
            this.transport = null;
        }
        if (this.session) {
            await this.session.close();
            this.session = null;
        }
    }
}
class NodeMCPServerSSE {
    constructor(options) {
        Object.defineProperty(this, "session", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "transport", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "tools", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "cacheDirty", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: true
        });
        Object.defineProperty(this, "timeout", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "nameValue", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "params", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        const normalized = normalizeSseOptions(options);
        this.params = normalized.params;
        this.timeout = normalized.timeout;
        this.nameValue = normalized.name;
    }
    get name() {
        return this.nameValue;
    }
    async connect() {
        if (this.session) {
            return;
        }
        const transportOptions = {
            authProvider: this.params.authProvider,
            requestInit: this.params.requestInit,
            eventSourceInit: this.params.eventSourceInit,
        };
        this.transport = new SSEClientTransport(new URL(this.params.url), transportOptions);
        this.session = new Client({
            name: this.nameValue,
            version: '1.0.0',
        });
        try {
            await this.session.connect(this.transport);
        }
        catch (error) {
            await this.close();
            throw error;
        }
    }
    async listTools() {
        if (!this.session) {
            throw new Error('Server not initialized. Call connect() first.');
        }
        if (!this.cacheDirty && this.tools) {
            return this.tools;
        }
        const response = await this.session.listTools();
        const parsed = ListToolsResultSchema.parse(response);
        this.tools = parsed.tools;
        this.cacheDirty = false;
        return parsed.tools;
    }
    async callTool(toolName, args, timeoutMs) {
        if (!this.session) {
            throw new Error('Server not initialized. Call connect() first.');
        }
        const response = await this.session.callTool({
            name: toolName,
            arguments: args ?? {},
        }, undefined, {
            timeout: timeoutMs ?? this.timeout,
        });
        return CallToolResultSchema.parse(response).content;
    }
    async invalidateToolsCache() {
        this.cacheDirty = true;
        this.tools = null;
    }
    async close() {
        if (this.transport) {
            await this.transport.close();
            this.transport = null;
        }
        if (this.session) {
            await this.session.close();
            this.session = null;
        }
    }
}
class NodeMCPServerStreamableHttp {
    constructor(options) {
        Object.defineProperty(this, "session", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "transport", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "tools", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        Object.defineProperty(this, "cacheDirty", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: true
        });
        Object.defineProperty(this, "timeout", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "nameValue", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "params", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        const normalized = normalizeStreamableHttpOptions(options);
        this.params = normalized.params;
        this.timeout = normalized.timeout;
        this.nameValue = normalized.name;
    }
    get name() {
        return this.nameValue;
    }
    async connect() {
        if (this.session) {
            return;
        }
        const transportOptions = {
            authProvider: this.params.authProvider,
            requestInit: this.params.requestInit,
            fetch: this.params.fetch,
            reconnectionOptions: this.params.reconnectionOptions,
            sessionId: this.params.sessionId,
        };
        this.transport = new StreamableHTTPClientTransport(new URL(this.params.url), transportOptions);
        this.session = new Client({
            name: this.nameValue,
            version: '1.0.0',
        });
        try {
            await this.session.connect(this.transport);
        }
        catch (error) {
            await this.close();
            throw error;
        }
    }
    async listTools() {
        if (!this.session) {
            throw new Error('Server not initialized. Call connect() first.');
        }
        if (!this.cacheDirty && this.tools) {
            return this.tools;
        }
        const response = await this.session.listTools();
        const parsed = ListToolsResultSchema.parse(response);
        this.tools = parsed.tools;
        this.cacheDirty = false;
        return parsed.tools;
    }
    async callTool(toolName, args, timeoutMs) {
        if (!this.session) {
            throw new Error('Server not initialized. Call connect() first.');
        }
        const response = await this.session.callTool({
            name: toolName,
            arguments: args ?? {},
        }, undefined, {
            timeout: timeoutMs ?? this.timeout,
        });
        return CallToolResultSchema.parse(response).content;
    }
    async invalidateToolsCache() {
        this.cacheDirty = true;
        this.tools = null;
    }
    async close() {
        if (this.transport) {
            await this.transport.close();
            this.transport = null;
        }
        if (this.session) {
            await this.session.close();
            this.session = null;
        }
    }
}
const normalizeStdioOptions = (options) => {
    const rawCommand = typeof options.command === 'string' ? options.command : '';
    const args = Array.isArray(options.args) ? options.args.map(String) : [];
    const envOverrides = (options.env && typeof options.env === 'object' ? options.env : {});
    // Inherit specific environment variables from the process
    const inheritKeys = ['PATH', 'HOME', 'SHELL', 'USER', 'TMPDIR', 'LANG'];
    const inheritedEnvEntries = [];
    console.log('[STDIO Shim] process.env.PATH:', process.env?.PATH);
    console.log('[STDIO Shim] All process.env keys:', Object.keys(process.env || {}));
    for (const key of inheritKeys) {
        const value = typeof process.env?.[key] === 'string' ? process.env[key] : undefined;
        if (value) {
            inheritedEnvEntries.push([key, value]);
            console.log(`[STDIO Shim] Inherited ${key}:`, value.substring(0, 100));
        }
        else {
            console.log(`[STDIO Shim] Could not inherit ${key}`);
        }
    }
    const env = Object.fromEntries([...inheritedEnvEntries, ...Object.entries(envOverrides)]);
    console.log('[STDIO Shim] Final env:', env);
    const normalizedEnv = Object.keys(env).length > 0 ? env : undefined;
    const cwd = typeof options.cwd === 'string' ? options.cwd : undefined;
    let command = rawCommand;
    let normalizedArgs = args;
    if ((!command || normalizedArgs.length === 0) && typeof options.fullCommand === 'string') {
        const segments = options.fullCommand.split(/\s+/).filter((segment) => segment.length > 0);
        const extractedCommand = segments.shift();
        if (extractedCommand) {
            command = command || extractedCommand;
            normalizedArgs = normalizedArgs.length > 0 ? normalizedArgs : segments;
        }
    }
    if (!command) {
        throw new Error('MCP stdio server requires a command to execute.');
    }
    const timeout = typeof options.timeout === 'number' ? options.timeout : DEFAULT_REQUEST_TIMEOUT_MSEC;
    const name = typeof options.name === 'string' && options.name.length > 0 ? options.name : `stdio: ${command}`;
    return {
        params: {
            command,
            args: normalizedArgs.length > 0 ? normalizedArgs : undefined,
            env: normalizedEnv,
            cwd,
        },
        timeout,
        name,
    };
};
const normalizeSseOptions = (options) => {
    const url = typeof options.url === 'string' ? options.url : '';
    if (!url) {
        throw new Error('MCP SSE server requires a URL.');
    }
    const timeout = typeof options.timeout === 'number' ? options.timeout : DEFAULT_REQUEST_TIMEOUT_MSEC;
    const name = typeof options.name === 'string' && options.name.length > 0 ? options.name : `sse: ${url}`;
    return {
        params: {
            url,
            authProvider: options.authProvider,
            requestInit: options.requestInit,
            eventSourceInit: options.eventSourceInit,
        },
        timeout,
        name,
    };
};
const normalizeStreamableHttpOptions = (options) => {
    const url = typeof options.url === 'string' ? options.url : '';
    if (!url) {
        throw new Error('MCP streamable HTTP server requires a URL.');
    }
    const timeout = typeof options.timeout === 'number' ? options.timeout : DEFAULT_REQUEST_TIMEOUT_MSEC;
    const name = typeof options.name === 'string' && options.name.length > 0 ? options.name : `streamable-http: ${url}`;
    return {
        params: {
            url,
            authProvider: options.authProvider,
            requestInit: options.requestInit,
            fetch: options.fetch,
            reconnectionOptions: options.reconnectionOptions,
            sessionId: typeof options.sessionId === 'string' ? options.sessionId : undefined,
        },
        timeout,
        name,
    };
};
const isPlainObject = (value) => {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
};
const shimTimer = {
    setTimeout: (callback, ms) => nodeSetTimeout(callback, ms),
    clearTimeout: (timeoutId) => nodeClearTimeout(timeoutId),
};
const getEnv = () => {
    if (typeof process !== 'undefined' && typeof process.env === 'object') {
        return process.env;
    }
    try {
        // eslint-disable-next-line no-new-func
        const importMeta = new Function('return import.meta')();
        if (importMeta && typeof importMeta.env === 'object') {
            return importMeta.env;
        }
    }
    catch {
        // ignore unavailability
    }
    return {};
};
const tracingLoopDefault = () => true;
const browserEnvFlag = () => false;
export const RuntimeEventEmitter = EventEmitter;
export { randomUUID, Readable, ReadableStream, TransformStream, AsyncLocalStorage };
export const MCPServerStdio = NodeMCPServerStdio;
export const MCPServerStreamableHttp = NodeMCPServerStreamableHttp;
export const MCPServerSSE = NodeMCPServerSSE;
export const timer = shimTimer;
export const loadEnv = getEnv;
export const isTracingLoopRunningByDefault = tracingLoopDefault;
export const isBrowserEnvironment = browserEnvFlag;
export const clearTimeout = nodeClearTimeout;
const shimModule = {
    RuntimeEventEmitter,
    randomUUID,
    Readable,
    ReadableStream,
    TransformStream,
    AsyncLocalStorage,
    MCPServerStdio,
    MCPServerStreamableHttp,
    MCPServerSSE,
    timer: shimTimer,
    loadEnv: getEnv,
    isTracingLoopRunningByDefault: tracingLoopDefault,
    isBrowserEnvironment: browserEnvFlag,
    clearTimeout: nodeClearTimeout,
};
if (typeof window !== 'undefined' && typeof window.require === 'function') {
    const existingRequire = window.require;
    if (!existingRequire.__mcpShimPatched) {
        const patchedRequire = function patchedRequire(specifier) {
            if (specifier === '@openai/agents-core/_shims') {
                return shimModule;
            }
            return existingRequire(specifier);
        };
        Object.assign(patchedRequire, existingRequire);
        patchedRequire.__mcpShimPatched = true;
        window.require = patchedRequire;
    }
}
export default shimModule;
