/**
 * @fileoverview MCP GraphQL Resolver
 *
 * Provides GraphQL mutations for MCP (Model Context Protocol) operations
 * including tool synchronization with progress streaming and OAuth management.
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { Resolver, Mutation, Query, Subscription, Arg, Ctx, Root, Field, ObjectType, InputType, PubSub, registerEnumType } from 'type-graphql';
import { PubSubEngine } from 'type-graphql';
import { LogError, LogStatus, RunView } from '@memberjunction/core';
import { MCPClientManager, OAuthAuthorizationRequiredError, OAuthReauthorizationRequiredError, OAuthManager, TokenManager } from '@memberjunction/ai-mcp-client';
import { ResolverBase } from '../generic/ResolverBase.js';
import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
import { GraphQLJSONObject } from 'graphql-type-json';
import { configInfo } from '../config.js';
/**
 * Input type for syncing MCP tools
 */
let SyncMCPToolsInput = class SyncMCPToolsInput {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], SyncMCPToolsInput.prototype, "ConnectionID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], SyncMCPToolsInput.prototype, "ForceSync", void 0);
SyncMCPToolsInput = __decorate([
    InputType()
], SyncMCPToolsInput);
export { SyncMCPToolsInput };
/**
 * Output type for MCP tool sync results
 */
let SyncMCPToolsResult = class SyncMCPToolsResult {
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], SyncMCPToolsResult.prototype, "Success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SyncMCPToolsResult.prototype, "ErrorMessage", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], SyncMCPToolsResult.prototype, "Added", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], SyncMCPToolsResult.prototype, "Updated", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], SyncMCPToolsResult.prototype, "Deprecated", void 0);
__decorate([
    Field(),
    __metadata("design:type", Number)
], SyncMCPToolsResult.prototype, "Total", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SyncMCPToolsResult.prototype, "ServerName", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SyncMCPToolsResult.prototype, "ConnectionName", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], SyncMCPToolsResult.prototype, "RequiresOAuth", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SyncMCPToolsResult.prototype, "AuthorizationUrl", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SyncMCPToolsResult.prototype, "StateParameter", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], SyncMCPToolsResult.prototype, "RequiresReauthorization", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], SyncMCPToolsResult.prototype, "ReauthorizationReason", void 0);
SyncMCPToolsResult = __decorate([
    ObjectType()
], SyncMCPToolsResult);
export { SyncMCPToolsResult };
/**
 * Input type for executing an MCP tool
 */
let ExecuteMCPToolInput = class ExecuteMCPToolInput {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], ExecuteMCPToolInput.prototype, "ConnectionID", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], ExecuteMCPToolInput.prototype, "ToolID", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], ExecuteMCPToolInput.prototype, "ToolName", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ExecuteMCPToolInput.prototype, "InputArgs", void 0);
ExecuteMCPToolInput = __decorate([
    InputType()
], ExecuteMCPToolInput);
export { ExecuteMCPToolInput };
/**
 * Output type for MCP tool execution results
 */
let ExecuteMCPToolResult = class ExecuteMCPToolResult {
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], ExecuteMCPToolResult.prototype, "Success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], ExecuteMCPToolResult.prototype, "ErrorMessage", void 0);
__decorate([
    Field(() => GraphQLJSONObject, { nullable: true }),
    __metadata("design:type", Object)
], ExecuteMCPToolResult.prototype, "Result", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Number)
], ExecuteMCPToolResult.prototype, "DurationMs", void 0);
ExecuteMCPToolResult = __decorate([
    ObjectType()
], ExecuteMCPToolResult);
export { ExecuteMCPToolResult };
// ============================================================================
// OAuth GraphQL Types
// ============================================================================
/**
 * OAuth authorization status enum
 */
var MCPOAuthStatus;
(function (MCPOAuthStatus) {
    MCPOAuthStatus["PENDING"] = "PENDING";
    MCPOAuthStatus["COMPLETED"] = "COMPLETED";
    MCPOAuthStatus["FAILED"] = "FAILED";
    MCPOAuthStatus["EXPIRED"] = "EXPIRED";
})(MCPOAuthStatus || (MCPOAuthStatus = {}));
// Register the enum with TypeGraphQL
registerEnumType(MCPOAuthStatus, {
    name: 'MCPOAuthStatus',
    description: 'Status of an OAuth authorization flow'
});
/**
 * Input for initiating OAuth authorization
 */
let InitiateMCPOAuthInput = class InitiateMCPOAuthInput {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], InitiateMCPOAuthInput.prototype, "ConnectionID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], InitiateMCPOAuthInput.prototype, "AdditionalScopes", void 0);
__decorate([
    Field({ nullable: true, description: 'Frontend URL to use as redirect_uri. When provided, the frontend handles the OAuth callback instead of the API server.' }),
    __metadata("design:type", String)
], InitiateMCPOAuthInput.prototype, "FrontendCallbackUrl", void 0);
InitiateMCPOAuthInput = __decorate([
    InputType()
], InitiateMCPOAuthInput);
export { InitiateMCPOAuthInput };
/**
 * Input for checking OAuth status
 */
let GetMCPOAuthStatusInput = class GetMCPOAuthStatusInput {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], GetMCPOAuthStatusInput.prototype, "StateParameter", void 0);
GetMCPOAuthStatusInput = __decorate([
    InputType()
], GetMCPOAuthStatusInput);
export { GetMCPOAuthStatusInput };
/**
 * Input for revoking OAuth credentials
 */
let RevokeMCPOAuthInput = class RevokeMCPOAuthInput {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], RevokeMCPOAuthInput.prototype, "ConnectionID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], RevokeMCPOAuthInput.prototype, "Reason", void 0);
RevokeMCPOAuthInput = __decorate([
    InputType()
], RevokeMCPOAuthInput);
export { RevokeMCPOAuthInput };
/**
 * Input for refreshing OAuth tokens
 */
let RefreshMCPOAuthTokenInput = class RefreshMCPOAuthTokenInput {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], RefreshMCPOAuthTokenInput.prototype, "ConnectionID", void 0);
RefreshMCPOAuthTokenInput = __decorate([
    InputType()
], RefreshMCPOAuthTokenInput);
export { RefreshMCPOAuthTokenInput };
/**
 * Result from initiating OAuth authorization
 */
let InitiateMCPOAuthResult = class InitiateMCPOAuthResult {
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], InitiateMCPOAuthResult.prototype, "Success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], InitiateMCPOAuthResult.prototype, "ErrorMessage", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], InitiateMCPOAuthResult.prototype, "AuthorizationUrl", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], InitiateMCPOAuthResult.prototype, "StateParameter", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Date)
], InitiateMCPOAuthResult.prototype, "ExpiresAt", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], InitiateMCPOAuthResult.prototype, "UsedDynamicRegistration", void 0);
InitiateMCPOAuthResult = __decorate([
    ObjectType()
], InitiateMCPOAuthResult);
export { InitiateMCPOAuthResult };
/**
 * Result from checking OAuth status
 */
let MCPOAuthStatusResult = class MCPOAuthStatusResult {
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], MCPOAuthStatusResult.prototype, "Success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthStatusResult.prototype, "ErrorMessage", void 0);
__decorate([
    Field(() => MCPOAuthStatus, { nullable: true }),
    __metadata("design:type", String)
], MCPOAuthStatusResult.prototype, "Status", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthStatusResult.prototype, "ConnectionID", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Date)
], MCPOAuthStatusResult.prototype, "InitiatedAt", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Date)
], MCPOAuthStatusResult.prototype, "CompletedAt", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthStatusResult.prototype, "AuthErrorCode", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthStatusResult.prototype, "AuthErrorDescription", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], MCPOAuthStatusResult.prototype, "IsRetryable", void 0);
MCPOAuthStatusResult = __decorate([
    ObjectType()
], MCPOAuthStatusResult);
export { MCPOAuthStatusResult };
/**
 * Result from revoking OAuth credentials
 */
let RevokeMCPOAuthResult = class RevokeMCPOAuthResult {
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], RevokeMCPOAuthResult.prototype, "Success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], RevokeMCPOAuthResult.prototype, "ErrorMessage", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], RevokeMCPOAuthResult.prototype, "ConnectionID", void 0);
RevokeMCPOAuthResult = __decorate([
    ObjectType()
], RevokeMCPOAuthResult);
export { RevokeMCPOAuthResult };
/**
 * Result from refreshing OAuth tokens
 */
let RefreshMCPOAuthTokenResult = class RefreshMCPOAuthTokenResult {
};
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], RefreshMCPOAuthTokenResult.prototype, "Success", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], RefreshMCPOAuthTokenResult.prototype, "ErrorMessage", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Date)
], RefreshMCPOAuthTokenResult.prototype, "ExpiresAt", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], RefreshMCPOAuthTokenResult.prototype, "RequiresReauthorization", void 0);
RefreshMCPOAuthTokenResult = __decorate([
    ObjectType()
], RefreshMCPOAuthTokenResult);
export { RefreshMCPOAuthTokenResult };
/**
 * OAuth connection status information
 */
let MCPOAuthConnectionStatus = class MCPOAuthConnectionStatus {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], MCPOAuthConnectionStatus.prototype, "ConnectionID", void 0);
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], MCPOAuthConnectionStatus.prototype, "IsOAuthEnabled", void 0);
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], MCPOAuthConnectionStatus.prototype, "HasValidTokens", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], MCPOAuthConnectionStatus.prototype, "IsAccessTokenExpired", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Date)
], MCPOAuthConnectionStatus.prototype, "TokenExpiresAt", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], MCPOAuthConnectionStatus.prototype, "HasRefreshToken", void 0);
__decorate([
    Field(),
    __metadata("design:type", Boolean)
], MCPOAuthConnectionStatus.prototype, "RequiresReauthorization", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthConnectionStatus.prototype, "ReauthorizationReason", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthConnectionStatus.prototype, "IssuerUrl", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthConnectionStatus.prototype, "GrantedScopes", void 0);
MCPOAuthConnectionStatus = __decorate([
    ObjectType()
], MCPOAuthConnectionStatus);
export { MCPOAuthConnectionStatus };
// ========================================
// Subscription Topics and Types
// ========================================
/** PubSub topic for MCP OAuth events */
export const MCP_OAUTH_EVENTS_TOPIC = 'MCP_OAUTH_EVENTS';
/**
 * Notification type for OAuth events
 */
let MCPOAuthEventNotification = class MCPOAuthEventNotification {
};
__decorate([
    Field(),
    __metadata("design:type", String)
], MCPOAuthEventNotification.prototype, "EventType", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], MCPOAuthEventNotification.prototype, "ConnectionID", void 0);
__decorate([
    Field(),
    __metadata("design:type", Date)
], MCPOAuthEventNotification.prototype, "Timestamp", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthEventNotification.prototype, "AuthorizationUrl", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthEventNotification.prototype, "StateParameter", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", String)
], MCPOAuthEventNotification.prototype, "ErrorMessage", void 0);
__decorate([
    Field({ nullable: true }),
    __metadata("design:type", Boolean)
], MCPOAuthEventNotification.prototype, "RequiresReauthorization", void 0);
MCPOAuthEventNotification = __decorate([
    ObjectType()
], MCPOAuthEventNotification);
export { MCPOAuthEventNotification };
/**
 * MCP Resolver for GraphQL operations
 */
let MCPResolver = class MCPResolver extends ResolverBase {
    /**
     * Syncs tools from an MCP server connection to the database.
     * Publishes progress updates via the statusUpdates subscription.
     *
     * @param input The sync input parameters
     * @param ctx The GraphQL context
     * @param pubSub PubSub engine for progress updates
     * @returns The sync result
     */
    async SyncMCPTools(input, ctx, pubSub) {
        const user = ctx.userPayload.userRecord;
        if (!user) {
            return this.createErrorResult('User is not authenticated');
        }
        const { ConnectionID } = input;
        const sessionId = ctx.userPayload.sessionId;
        try {
            // Check API key scope authorization
            await this.CheckAPIKeyScopeAuthorization('mcp:sync', ConnectionID, ctx.userPayload);
            // Get the MCP client manager instance and ensure it's initialized
            const manager = MCPClientManager.Instance;
            const publicUrl = this.getPublicUrl();
            await manager.initialize(user, { publicUrl });
            // Publish initial progress
            this.publishProgress(pubSub, sessionId, ConnectionID, 'connecting', 'Connecting to MCP server...');
            // Connect if not already connected
            const isConnected = manager.isConnected(ConnectionID);
            if (!isConnected) {
                LogStatus(`MCPResolver: Connecting to MCP server for connection ${ConnectionID}`);
                try {
                    await manager.connect(ConnectionID, { contextUser: user });
                }
                catch (connectError) {
                    // Check for OAuth authorization required
                    if (connectError instanceof OAuthAuthorizationRequiredError) {
                        const authError = connectError;
                        this.publishProgress(pubSub, sessionId, ConnectionID, 'error', `OAuth authorization required. Please authorize at: ${authError.authorizationUrl}`);
                        return this.createOAuthRequiredResult(authError.authorizationUrl, authError.stateParameter);
                    }
                    if (connectError instanceof OAuthReauthorizationRequiredError) {
                        const reAuthError = connectError;
                        this.publishProgress(pubSub, sessionId, ConnectionID, 'error', `OAuth re-authorization required: ${reAuthError.reason}`);
                        return this.createOAuthReauthorizationResult(reAuthError.reason, reAuthError.authorizationUrl, reAuthError.stateParameter);
                    }
                    const connectErrorMsg = connectError instanceof Error ? connectError.message : String(connectError);
                    this.publishProgress(pubSub, sessionId, ConnectionID, 'error', `Connection failed: ${connectErrorMsg}`);
                    return this.createErrorResult(`Failed to connect to MCP server: ${connectErrorMsg}`);
                }
            }
            // Get connection info for the result
            const connectionInfo = manager.getConnectionInfo(ConnectionID);
            const serverName = connectionInfo?.serverName || 'Unknown Server';
            const connectionName = connectionInfo?.connectionName || 'Unknown Connection';
            // Publish listing progress
            this.publishProgress(pubSub, sessionId, ConnectionID, 'listing', 'Discovering tools from MCP server...');
            // Perform the sync with event listening for granular progress
            LogStatus(`MCPResolver: Starting tool sync for connection ${ConnectionID}`);
            // Subscribe to manager events for this sync
            const eventHandler = (event) => {
                if (event.type === 'toolsSynced') {
                    const data = event.data;
                    this.publishProgress(pubSub, sessionId, ConnectionID, 'complete', 'Tool sync complete', {
                        added: data?.added || 0,
                        updated: data?.updated || 0,
                        deprecated: data?.deprecated || 0,
                        total: data?.total || 0
                    });
                }
            };
            manager.addEventListener('toolsSynced', eventHandler);
            // Publish syncing progress
            this.publishProgress(pubSub, sessionId, ConnectionID, 'syncing', 'Synchronizing tools to database...');
            // Perform the sync
            const syncResult = await manager.syncTools(ConnectionID, { contextUser: user });
            // Remove event listener
            manager.removeEventListener('toolsSynced', eventHandler);
            if (!syncResult.success) {
                this.publishProgress(pubSub, sessionId, ConnectionID, 'error', `Sync failed: ${syncResult.error}`);
                return this.createErrorResult(syncResult.error || 'Tool sync failed');
            }
            // Publish final completion
            this.publishProgress(pubSub, sessionId, ConnectionID, 'complete', `Sync complete: ${syncResult.added} added, ${syncResult.updated} updated, ${syncResult.deprecated} deprecated`, {
                added: syncResult.added,
                updated: syncResult.updated,
                deprecated: syncResult.deprecated,
                total: syncResult.total
            });
            LogStatus(`MCPResolver: Tool sync complete for ${ConnectionID} - Added: ${syncResult.added}, Updated: ${syncResult.updated}, Deprecated: ${syncResult.deprecated}, Total: ${syncResult.total}`);
            return {
                Success: true,
                Added: syncResult.added,
                Updated: syncResult.updated,
                Deprecated: syncResult.deprecated,
                Total: syncResult.total,
                ServerName: serverName,
                ConnectionName: connectionName
            };
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            LogError(`MCPResolver: Error syncing tools for ${ConnectionID}: ${errorMsg}`);
            this.publishProgress(pubSub, sessionId, ConnectionID, 'error', `Error: ${errorMsg}`);
            return this.createErrorResult(errorMsg);
        }
    }
    /**
     * Executes an MCP tool and returns the result.
     *
     * @param input The execution input parameters
     * @param ctx The GraphQL context
     * @returns The execution result
     */
    async ExecuteMCPTool(input, ctx) {
        const user = ctx.userPayload.userRecord;
        if (!user) {
            return {
                Success: false,
                ErrorMessage: 'User is not authenticated'
            };
        }
        const { ConnectionID, ToolID, ToolName, InputArgs } = input;
        const startTime = Date.now();
        try {
            // Check API key scope authorization
            LogStatus(`MCPResolver: [${ToolName}] Step 1 - Checking API key authorization...`);
            await this.CheckAPIKeyScopeAuthorization('mcp:execute', ConnectionID, ctx.userPayload);
            LogStatus(`MCPResolver: [${ToolName}] Step 1 complete - Authorization passed (${Date.now() - startTime}ms)`);
            // Get the MCP client manager instance and ensure it's initialized
            LogStatus(`MCPResolver: [${ToolName}] Step 2 - Initializing MCP client manager...`);
            const manager = MCPClientManager.Instance;
            const publicUrl = this.getPublicUrl();
            await manager.initialize(user, { publicUrl });
            LogStatus(`MCPResolver: [${ToolName}] Step 2 complete - Manager initialized (${Date.now() - startTime}ms)`);
            // Connect if not already connected
            const isConnected = manager.isConnected(ConnectionID);
            LogStatus(`MCPResolver: [${ToolName}] Step 3 - Connection status: ${isConnected ? 'already connected' : 'needs connection'}`);
            if (!isConnected) {
                LogStatus(`MCPResolver: [${ToolName}] Connecting to MCP server for connection ${ConnectionID}...`);
                try {
                    await manager.connect(ConnectionID, { contextUser: user });
                    LogStatus(`MCPResolver: [${ToolName}] Step 3 complete - Connected (${Date.now() - startTime}ms)`);
                }
                catch (connectError) {
                    // Check for OAuth authorization required
                    if (connectError instanceof OAuthAuthorizationRequiredError) {
                        const authError = connectError;
                        LogError(`MCPResolver: [${ToolName}] OAuth authorization required`);
                        return {
                            Success: false,
                            ErrorMessage: `OAuth authorization required. Please authorize at: ${authError.authorizationUrl}`,
                            Result: {
                                requiresOAuth: true,
                                authorizationUrl: authError.authorizationUrl,
                                stateParameter: authError.stateParameter
                            }
                        };
                    }
                    if (connectError instanceof OAuthReauthorizationRequiredError) {
                        const reAuthError = connectError;
                        LogError(`MCPResolver: [${ToolName}] OAuth re-authorization required: ${reAuthError.reason}`);
                        return {
                            Success: false,
                            ErrorMessage: `OAuth re-authorization required: ${reAuthError.reason}`,
                            Result: {
                                requiresReauthorization: true,
                                reason: reAuthError.reason,
                                authorizationUrl: reAuthError.authorizationUrl,
                                stateParameter: reAuthError.stateParameter
                            }
                        };
                    }
                    const connectErrorMsg = connectError instanceof Error ? connectError.message : String(connectError);
                    LogError(`MCPResolver: [${ToolName}] Connection failed: ${connectErrorMsg}`);
                    return {
                        Success: false,
                        ErrorMessage: `Failed to connect to MCP server: ${connectErrorMsg}`
                    };
                }
            }
            // Parse input arguments
            LogStatus(`MCPResolver: [${ToolName}] Step 4 - Parsing input arguments...`);
            let parsedArgs = {};
            if (InputArgs) {
                try {
                    parsedArgs = JSON.parse(InputArgs);
                    LogStatus(`MCPResolver: [${ToolName}] Parsed args: ${JSON.stringify(parsedArgs).substring(0, 200)}...`);
                }
                catch (parseError) {
                    LogError(`MCPResolver: [${ToolName}] Failed to parse InputArgs: ${parseError}`);
                    return {
                        Success: false,
                        ErrorMessage: 'Invalid JSON in InputArgs'
                    };
                }
            }
            LogStatus(`MCPResolver: [${ToolName}] Step 4 complete - Args parsed (${Date.now() - startTime}ms)`);
            // Call the tool
            LogStatus(`MCPResolver: [${ToolName}] Step 5 - Calling tool on connection ${ConnectionID}...`);
            LogStatus(`MCPResolver: [${ToolName}] Tool ID: ${ToolID}`);
            const result = await manager.callTool(ConnectionID, ToolName, { arguments: parsedArgs }, { contextUser: user });
            LogStatus(`MCPResolver: [${ToolName}] Step 5 complete - Tool call returned (${Date.now() - startTime}ms)`);
            // Format the result for the response - wrap in object for GraphQLJSONObject
            let formattedResult = null;
            if (result.content && result.content.length > 0) {
                // If there's only one text content block, try to parse as JSON object
                if (result.content.length === 1 && result.content[0].type === 'text') {
                    const textContent = result.content[0].text;
                    // Try to parse as JSON object
                    if (textContent && (textContent.startsWith('{') || textContent.startsWith('['))) {
                        try {
                            const parsed = JSON.parse(textContent);
                            // Wrap arrays in an object
                            if (Array.isArray(parsed)) {
                                formattedResult = { items: parsed };
                            }
                            else if (typeof parsed === 'object' && parsed !== null) {
                                formattedResult = parsed;
                            }
                            else {
                                formattedResult = { value: parsed };
                            }
                        }
                        catch {
                            // Keep as wrapped string if not valid JSON
                            formattedResult = { text: textContent };
                        }
                    }
                    else {
                        // Wrap plain text in object
                        formattedResult = { text: textContent };
                    }
                }
                else {
                    // Return all content blocks wrapped in object
                    formattedResult = { content: result.content };
                }
            }
            // Use structuredContent if available (already an object)
            if (result.structuredContent) {
                formattedResult = result.structuredContent;
            }
            LogStatus(`MCPResolver: [${ToolName}] Step 6 complete - Result formatted (${Date.now() - startTime}ms)`);
            LogStatus(`MCPResolver: [${ToolName}] Tool execution complete - Success: ${result.success}, Duration: ${result.durationMs}ms, Total time: ${Date.now() - startTime}ms`);
            return {
                Success: result.success,
                ErrorMessage: result.error,
                Result: formattedResult,
                DurationMs: result.durationMs
            };
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            const stack = error instanceof Error ? error.stack : '';
            LogError(`MCPResolver: [${ToolName}] Error after ${Date.now() - startTime}ms: ${errorMsg}`);
            LogError(`MCPResolver: [${ToolName}] Stack: ${stack}`);
            return {
                Success: false,
                ErrorMessage: errorMsg
            };
        }
    }
    // ========================================================================
    // OAuth Operations
    // ========================================================================
    /**
     * Gets OAuth connection status for an MCP connection.
     *
     * @param connectionId - The MCP Server Connection ID
     * @param ctx - GraphQL context
     * @returns OAuth connection status
     */
    async GetMCPOAuthConnectionStatus(connectionId, ctx) {
        const user = ctx.userPayload.userRecord;
        if (!user) {
            return {
                ConnectionID: connectionId,
                IsOAuthEnabled: false,
                HasValidTokens: false,
                RequiresReauthorization: false,
                ReauthorizationReason: 'User is not authenticated'
            };
        }
        try {
            // Load connection and server config
            const config = await this.loadConnectionOAuthConfig(connectionId, user);
            if (!config) {
                return {
                    ConnectionID: connectionId,
                    IsOAuthEnabled: false,
                    HasValidTokens: false,
                    RequiresReauthorization: false,
                    ReauthorizationReason: 'Connection not found'
                };
            }
            if (!config.OAuthIssuerURL) {
                return {
                    ConnectionID: connectionId,
                    IsOAuthEnabled: false,
                    HasValidTokens: false,
                    RequiresReauthorization: false
                };
            }
            // Get status from OAuthManager
            const oauthManager = new OAuthManager();
            const status = await oauthManager.getConnectionStatus(connectionId, config, user);
            return {
                ConnectionID: status.connectionId,
                IsOAuthEnabled: status.isOAuthEnabled,
                HasValidTokens: status.hasValidTokens,
                IsAccessTokenExpired: status.isAccessTokenExpired,
                TokenExpiresAt: status.tokenExpiresAt,
                HasRefreshToken: status.hasRefreshToken,
                RequiresReauthorization: status.requiresReauthorization,
                ReauthorizationReason: status.reauthorizationReason,
                IssuerUrl: status.issuerUrl,
                GrantedScopes: status.grantedScopes
            };
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            LogError(`MCPResolver: GetMCPOAuthConnectionStatus failed: ${errorMsg}`);
            return {
                ConnectionID: connectionId,
                IsOAuthEnabled: false,
                HasValidTokens: false,
                RequiresReauthorization: true,
                ReauthorizationReason: errorMsg
            };
        }
    }
    /**
     * Gets OAuth authorization flow status by state parameter.
     *
     * @param input - Input containing state parameter
     * @param ctx - GraphQL context
     * @returns OAuth status result
     */
    async GetMCPOAuthStatus(input, ctx) {
        const user = ctx.userPayload.userRecord;
        if (!user) {
            return {
                Success: false,
                ErrorMessage: 'User is not authenticated'
            };
        }
        try {
            const rv = new RunView();
            const result = await rv.RunView({
                EntityName: 'MJ: O Auth Authorization States',
                ExtraFilter: `StateParameter='${input.StateParameter.replace(/'/g, "''")}'`,
                ResultType: 'simple'
            }, user);
            if (!result.Success || !result.Results || result.Results.length === 0) {
                return {
                    Success: false,
                    ErrorMessage: 'Authorization state not found',
                    IsRetryable: true
                };
            }
            const state = result.Results[0];
            const statusMap = {
                'Pending': MCPOAuthStatus.PENDING,
                'Completed': MCPOAuthStatus.COMPLETED,
                'Failed': MCPOAuthStatus.FAILED,
                'Expired': MCPOAuthStatus.EXPIRED
            };
            return {
                Success: true,
                Status: statusMap[state.Status] ?? MCPOAuthStatus.PENDING,
                ConnectionID: state.MCPServerConnectionID,
                InitiatedAt: new Date(state.InitiatedAt),
                CompletedAt: state.CompletedAt ? new Date(state.CompletedAt) : undefined,
                AuthErrorCode: state.ErrorCode ?? undefined,
                AuthErrorDescription: state.ErrorDescription ?? undefined,
                IsRetryable: state.Status === 'Failed' || state.Status === 'Expired'
            };
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            LogError(`MCPResolver: GetMCPOAuthStatus failed: ${errorMsg}`);
            return {
                Success: false,
                ErrorMessage: errorMsg
            };
        }
    }
    /**
     * Initiates an OAuth authorization flow for an MCP connection.
     *
     * @param input - Input containing connection ID and optional scopes
     * @param ctx - GraphQL context
     * @returns Initiation result with authorization URL
     */
    async InitiateMCPOAuth(input, ctx) {
        const user = ctx.userPayload.userRecord;
        if (!user) {
            return {
                Success: false,
                ErrorMessage: 'User is not authenticated'
            };
        }
        try {
            // Check API key scope authorization
            await this.CheckAPIKeyScopeAuthorization('mcp:oauth', input.ConnectionID, ctx.userPayload);
            // Load connection and server config
            const config = await this.loadConnectionOAuthConfig(input.ConnectionID, user);
            if (!config) {
                return {
                    Success: false,
                    ErrorMessage: 'Connection not found'
                };
            }
            if (!config.OAuthIssuerURL) {
                return {
                    Success: false,
                    ErrorMessage: 'OAuth is not configured for this connection'
                };
            }
            // Merge additional scopes if provided
            let scopes = config.OAuthScopes;
            if (input.AdditionalScopes) {
                scopes = scopes
                    ? `${scopes} ${input.AdditionalScopes}`
                    : input.AdditionalScopes;
            }
            const oauthConfig = {
                ...config,
                OAuthScopes: scopes
            };
            // Initiate the OAuth flow
            const oauthManager = new OAuthManager();
            const publicUrl = this.getPublicUrl();
            // Build options for the OAuth flow
            const oauthOptions = {};
            if (input.FrontendCallbackUrl) {
                oauthOptions.frontendCallbackUrl = input.FrontendCallbackUrl;
            }
            const result = await oauthManager.initiateAuthorizationFlow(input.ConnectionID, config.MCPServerID, oauthConfig, publicUrl, user, Object.keys(oauthOptions).length > 0 ? oauthOptions : undefined);
            LogStatus(`MCPResolver: Initiated OAuth flow for connection ${input.ConnectionID}`);
            return {
                Success: result.success,
                ErrorMessage: result.errorMessage,
                AuthorizationUrl: result.authorizationUrl,
                StateParameter: result.stateParameter,
                ExpiresAt: result.expiresAt,
                UsedDynamicRegistration: result.usedDynamicRegistration
            };
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            LogError(`MCPResolver: InitiateMCPOAuth failed: ${errorMsg}`);
            return {
                Success: false,
                ErrorMessage: errorMsg
            };
        }
    }
    /**
     * Revokes OAuth credentials for an MCP connection.
     *
     * @param input - Input containing connection ID and optional reason
     * @param ctx - GraphQL context
     * @returns Revocation result
     */
    async RevokeMCPOAuth(input, ctx) {
        const user = ctx.userPayload.userRecord;
        if (!user) {
            return {
                Success: false,
                ErrorMessage: 'User is not authenticated'
            };
        }
        try {
            // Check API key scope authorization
            await this.CheckAPIKeyScopeAuthorization('mcp:oauth', input.ConnectionID, ctx.userPayload);
            // Revoke the credentials
            const tokenManager = new TokenManager();
            await tokenManager.revokeCredentials(input.ConnectionID, user);
            LogStatus(`MCPResolver: Revoked OAuth credentials for connection ${input.ConnectionID}${input.Reason ? ` (reason: ${input.Reason})` : ''}`);
            return {
                Success: true,
                ConnectionID: input.ConnectionID
            };
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            LogError(`MCPResolver: RevokeMCPOAuth failed: ${errorMsg}`);
            return {
                Success: false,
                ErrorMessage: errorMsg,
                ConnectionID: input.ConnectionID
            };
        }
    }
    /**
     * Manually refreshes OAuth tokens for an MCP connection.
     *
     * @param input - Input containing connection ID
     * @param ctx - GraphQL context
     * @returns Refresh result
     */
    async RefreshMCPOAuthToken(input, ctx) {
        const user = ctx.userPayload.userRecord;
        if (!user) {
            return {
                Success: false,
                ErrorMessage: 'User is not authenticated'
            };
        }
        try {
            // Check API key scope authorization
            await this.CheckAPIKeyScopeAuthorization('mcp:oauth', input.ConnectionID, ctx.userPayload);
            // Load connection config
            const config = await this.loadConnectionOAuthConfig(input.ConnectionID, user);
            if (!config) {
                return {
                    Success: false,
                    ErrorMessage: 'Connection not found'
                };
            }
            if (!config.OAuthIssuerURL) {
                return {
                    Success: false,
                    ErrorMessage: 'OAuth is not configured for this connection'
                };
            }
            // Get the MCP client manager instance
            const manager = MCPClientManager.Instance;
            const publicUrl = this.getPublicUrl();
            await manager.initialize(user, { publicUrl });
            // Try to get access token (will refresh if needed)
            const oauthManager = new OAuthManager();
            try {
                await oauthManager.getAccessToken(input.ConnectionID, config.MCPServerID, config, publicUrl, user);
                // Get updated status
                const status = await oauthManager.getConnectionStatus(input.ConnectionID, config, user);
                LogStatus(`MCPResolver: Refreshed OAuth tokens for connection ${input.ConnectionID}`);
                return {
                    Success: true,
                    ExpiresAt: status.tokenExpiresAt,
                    RequiresReauthorization: false
                };
            }
            catch (error) {
                if (error instanceof OAuthAuthorizationRequiredError ||
                    error instanceof OAuthReauthorizationRequiredError) {
                    return {
                        Success: false,
                        ErrorMessage: error.message,
                        RequiresReauthorization: true
                    };
                }
                throw error;
            }
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            LogError(`MCPResolver: RefreshMCPOAuthToken failed: ${errorMsg}`);
            return {
                Success: false,
                ErrorMessage: errorMsg
            };
        }
    }
    // ========================================================================
    // Subscriptions
    // ========================================================================
    /**
     * Subscribes to OAuth events for MCP connections.
     *
     * Clients can subscribe to receive real-time notifications when:
     * - Authorization is required for a connection
     * - Authorization completes successfully
     * - Token is refreshed
     * - Token refresh fails
     *
     * @param payload - The OAuth event payload
     * @returns OAuth event notification
     */
    onMCPOAuthEvent(payload) {
        return {
            EventType: payload.eventType,
            ConnectionID: payload.connectionId,
            Timestamp: new Date(payload.timestamp),
            AuthorizationUrl: payload.authorizationUrl,
            StateParameter: payload.stateParameter,
            ErrorMessage: payload.errorMessage,
            RequiresReauthorization: payload.requiresReauthorization
        };
    }
    // ========================================================================
    // Private Helper Methods
    // ========================================================================
    /**
     * Loads OAuth configuration for a connection
     */
    async loadConnectionOAuthConfig(connectionId, contextUser) {
        try {
            const rv = new RunView();
            // First get connection to get server ID
            const connResult = await rv.RunView({
                EntityName: 'MJ: MCP Server Connections',
                ExtraFilter: `ID='${connectionId}'`,
                Fields: ['MCPServerID'],
                ResultType: 'simple'
            }, contextUser);
            if (!connResult.Success || !connResult.Results || connResult.Results.length === 0) {
                return null;
            }
            const serverId = connResult.Results[0].MCPServerID;
            // Then get server OAuth config
            const serverResult = await rv.RunView({
                EntityName: 'MJ: MCP Servers',
                ExtraFilter: `ID='${serverId}'`,
                Fields: [
                    'OAuthIssuerURL',
                    'OAuthScopes',
                    'OAuthMetadataCacheTTLMinutes',
                    'OAuthClientID',
                    'OAuthClientSecretEncrypted',
                    'OAuthRequirePKCE'
                ],
                ResultType: 'simple'
            }, contextUser);
            if (!serverResult.Success || !serverResult.Results || serverResult.Results.length === 0) {
                return null;
            }
            const server = serverResult.Results[0];
            return {
                MCPServerID: serverId,
                OAuthIssuerURL: server.OAuthIssuerURL ?? undefined,
                OAuthScopes: server.OAuthScopes ?? undefined,
                OAuthMetadataCacheTTLMinutes: server.OAuthMetadataCacheTTLMinutes ?? undefined,
                OAuthClientID: server.OAuthClientID ?? undefined,
                OAuthClientSecretEncrypted: server.OAuthClientSecretEncrypted ?? undefined,
                OAuthRequirePKCE: server.OAuthRequirePKCE ?? undefined
            };
        }
        catch (error) {
            LogError(`MCPResolver: Failed to load connection OAuth config: ${error}`);
            return null;
        }
    }
    /**
     * Publishes a progress update to the statusUpdates subscription
     */
    publishProgress(pubSub, sessionId, connectionId, phase, message, result) {
        const progressMessage = {
            resolver: 'MCPResolver',
            type: 'MCPToolSyncProgress',
            status: phase === 'error' ? 'error' : 'ok',
            connectionId,
            phase,
            message,
            result
        };
        pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
            message: JSON.stringify(progressMessage),
            sessionId
        });
    }
    /**
     * Creates an error result with default values
     */
    createErrorResult(errorMessage) {
        return {
            Success: false,
            ErrorMessage: errorMessage,
            Added: 0,
            Updated: 0,
            Deprecated: 0,
            Total: 0
        };
    }
    /**
     * Creates a result indicating OAuth authorization is required
     */
    createOAuthRequiredResult(authorizationUrl, stateParameter) {
        return {
            Success: false,
            ErrorMessage: 'OAuth authorization required',
            Added: 0,
            Updated: 0,
            Deprecated: 0,
            Total: 0,
            RequiresOAuth: true,
            AuthorizationUrl: authorizationUrl,
            StateParameter: stateParameter
        };
    }
    /**
     * Creates a result indicating OAuth re-authorization is required
     */
    createOAuthReauthorizationResult(reason, authorizationUrl, stateParameter) {
        return {
            Success: false,
            ErrorMessage: `OAuth re-authorization required: ${reason}`,
            Added: 0,
            Updated: 0,
            Deprecated: 0,
            Total: 0,
            RequiresReauthorization: true,
            ReauthorizationReason: reason,
            AuthorizationUrl: authorizationUrl,
            StateParameter: stateParameter
        };
    }
    /**
     * Gets the public URL for OAuth callbacks
     */
    getPublicUrl() {
        // Use publicUrl from config, falling back to constructed URL
        if (configInfo.publicUrl) {
            return configInfo.publicUrl;
        }
        // Construct from baseUrl and graphqlPort
        const baseUrl = configInfo.baseUrl || 'http://localhost';
        const port = configInfo.graphqlPort || 4000;
        const rootPath = configInfo.graphqlRootPath || '/';
        // Construct full URL
        let url = `${baseUrl}:${port}`;
        if (rootPath && rootPath !== '/') {
            url += rootPath;
        }
        return url;
    }
};
__decorate([
    Mutation(() => SyncMCPToolsResult),
    __param(0, Arg('input')),
    __param(1, Ctx()),
    __param(2, PubSub()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [SyncMCPToolsInput, Object, PubSubEngine]),
    __metadata("design:returntype", Promise)
], MCPResolver.prototype, "SyncMCPTools", null);
__decorate([
    Mutation(() => ExecuteMCPToolResult),
    __param(0, Arg('input')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ExecuteMCPToolInput, Object]),
    __metadata("design:returntype", Promise)
], MCPResolver.prototype, "ExecuteMCPTool", null);
__decorate([
    Query(() => MCPOAuthConnectionStatus),
    __param(0, Arg('ConnectionID')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object]),
    __metadata("design:returntype", Promise)
], MCPResolver.prototype, "GetMCPOAuthConnectionStatus", null);
__decorate([
    Query(() => MCPOAuthStatusResult),
    __param(0, Arg('input')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [GetMCPOAuthStatusInput, Object]),
    __metadata("design:returntype", Promise)
], MCPResolver.prototype, "GetMCPOAuthStatus", null);
__decorate([
    Mutation(() => InitiateMCPOAuthResult),
    __param(0, Arg('input')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [InitiateMCPOAuthInput, Object]),
    __metadata("design:returntype", Promise)
], MCPResolver.prototype, "InitiateMCPOAuth", null);
__decorate([
    Mutation(() => RevokeMCPOAuthResult),
    __param(0, Arg('input')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [RevokeMCPOAuthInput, Object]),
    __metadata("design:returntype", Promise)
], MCPResolver.prototype, "RevokeMCPOAuth", null);
__decorate([
    Mutation(() => RefreshMCPOAuthTokenResult),
    __param(0, Arg('input')),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [RefreshMCPOAuthTokenInput, Object]),
    __metadata("design:returntype", Promise)
], MCPResolver.prototype, "RefreshMCPOAuthToken", null);
__decorate([
    Subscription(() => MCPOAuthEventNotification, { topics: MCP_OAUTH_EVENTS_TOPIC }),
    __param(0, Root()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", MCPOAuthEventNotification)
], MCPResolver.prototype, "onMCPOAuthEvent", null);
MCPResolver = __decorate([
    Resolver()
], MCPResolver);
export { MCPResolver };
/**
 * Publishes an OAuth event to the subscription topic.
 * Can be called from other resolvers or handlers to notify clients of OAuth events.
 *
 * @param pubSub - PubSub engine
 * @param event - OAuth event details
 */
export async function publishMCPOAuthEvent(pubSub, event) {
    const payload = {
        eventType: event.eventType,
        connectionId: event.connectionId,
        timestamp: new Date().toISOString(),
        authorizationUrl: event.authorizationUrl,
        stateParameter: event.stateParameter,
        errorMessage: event.errorMessage,
        requiresReauthorization: event.requiresReauthorization
    };
    await pubSub.publish(MCP_OAUTH_EVENTS_TOPIC, payload);
}
//# sourceMappingURL=MCPResolver.js.map