import { Logger } from '@graphql-hive/logger';
import { DisposableSymbols } from '@whatwg-node/disposablestack';
import { MaybePromise } from '@whatwg-node/promise-helpers';
import { UnifiedGraphPlugin, Instrumentation as Instrumentation$2 } from '@graphql-mesh/fusion-runtime';
import { Plugin, YogaInitialContext, Instrumentation as Instrumentation$1 } from 'graphql-yoga';
import { MeshFetch, KeyValueCache, MeshFetchRequestInit, Logger as Logger$1 } from '@graphql-mesh/types';
import { FetchInstrumentation } from '@graphql-mesh/utils';
import { ExecutionRequest, MaybePromise as MaybePromise$1 } from '@graphql-tools/utils';
import { GraphQLResolveInfo } from 'graphql/type';
import { Langfuse, LangfuseOptions } from 'langfuse';

type TopicDataMap = {
    [topic: string]: any;
};
type PubSubListener<Data extends TopicDataMap, Topic extends keyof Data> = (data: Data[Topic]) => void;
interface PubSub<M extends TopicDataMap = TopicDataMap> {
    /**
     * Publish {@link data} for a {@link topic}.
     * @returns `void` or a `Promise` that resolves when the data has been successfully published
     */
    publish<Topic extends keyof M>(topic: Topic, data: M[Topic]): MaybePromise<void>;
    /**
     * A distinct list of all topics that are currently subscribed to.
     * Can be a promise to accomodate distributed systems where subscribers exist on other
     * locations and we need to know about all of them.
     */
    subscribedTopics(): MaybePromise<Iterable<keyof M>>;
    /**
     * Subscribe and listen to a {@link topic} receiving its data.
     *
     * If the {@link listener} is provided, it will be called whenever data is emitted for the {@link topic},
     *
     * @returns an unsubscribe function or a `Promise<unsubscribe function>` that resolves when the subscription is successfully established. the unsubscribe function returns `void` or a `Promise` that resolves on successful unsubscribe and subscription cleanup
     *
     * If the {@link listener} is not provided,
     *
     * @returns an `AsyncIterable` that yields data for the given {@link topic}
     */
    subscribe<Topic extends keyof M>(topic: Topic): AsyncIterable<M[Topic]>;
    subscribe<Topic extends keyof M>(topic: Topic, listener: PubSubListener<M, Topic>): MaybePromise<() => MaybePromise<void>>;
    /**
     * Closes active subscriptions and disposes of all resources. Publishing and subscribing after disposal
     * is not possible and will throw an error if attempted.
     */
    dispose(): MaybePromise<void>;
    /** @see {@link dispose} */
    [DisposableSymbols.asyncDispose](): Promise<void>;
}

interface GatewayConfigContext {
    /**
     * WHATWG compatible Fetch implementation.
     */
    fetch: MeshFetch;
    /**
     * The logger to use throught Hive and its plugins.
     */
    log: Logger;
    /**
     * Current working directory.
     * Note that working directory does not exist in serverless environments and will therefore be empty.
     */
    cwd: string;
    /**
     * Event bus for pub/sub.
     */
    pubsub?: PubSub;
    /**
     * Cache Storage
     */
    cache?: KeyValueCache;
}
interface GatewayContext extends GatewayConfigContext, YogaInitialContext {
    /**
     * Environment agnostic HTTP headers provided with the request.
     */
    headers: Record<string, string>;
    /**
     * Runtime context available within WebSocket connections.
     */
    connectionParams?: Record<string, string>;
}
type GatewayPlugin<TPluginContext extends Record<string, any> = Record<string, any>, TContext extends Record<string, any> = Record<string, any>> = Plugin<Partial<TPluginContext> & GatewayContext & TContext, GatewayConfigContext> & UnifiedGraphPlugin<Partial<TPluginContext> & GatewayContext & TContext> & {
    onFetch?: OnFetchHook<Partial<TPluginContext> & TContext>;
    onCacheGet?: OnCacheGetHook;
    onCacheSet?: OnCacheSetHook;
    onCacheDelete?: OnCacheDeleteHook;
    /**
     * An Instrumentation instance that will wrap each phases of the request pipeline.
     * This should be used primarily as an observability tool (for monitoring, tracing, etc...).
     *
     * Note: The wrapped functions in instrumentation should always be called. Use hooks to
     *       conditionally skip a phase.
     */
    instrumentation?: Instrumentation<TPluginContext & TContext & GatewayContext>;
};
interface OnFetchHookPayload<TContext> {
    url: string;
    setURL(url: URL | string): void;
    options: MeshFetchRequestInit;
    setOptions(options: MeshFetchRequestInit): void;
    /**
     * The context is not available in cases where "fetch" is done in
     * order to pull a supergraph or do some internal work.
     *
     * The logger will be available in all cases.
     */
    context: (GatewayContext & TContext) | {
        log: Logger;
    };
    /** @deprecated Please use `log` from the {@link context} instead. */
    logger: Logger$1;
    info: GraphQLResolveInfo;
    fetchFn: MeshFetch;
    setFetchFn: (fetchFn: MeshFetch) => void;
    executionRequest?: ExecutionRequest;
    endResponse: (response$: MaybePromise$1<Response>) => void;
}
interface OnFetchHookDonePayload {
    response: Response;
    setResponse: (response: Response) => void;
}
type OnFetchHookDone = (payload: OnFetchHookDonePayload) => MaybePromise$1<void>;
type OnFetchHook<TContext> = (payload: OnFetchHookPayload<TContext>) => MaybePromise$1<void | OnFetchHookDone>;
type OnCacheGetHook = (payload: OnCacheGetHookEventPayload) => MaybePromise$1<OnCacheGetHookResult | void>;
interface OnCacheGetHookEventPayload {
    cache: KeyValueCache;
    key: string;
    ttl?: number;
}
interface OnCacheGetHookResult {
    onCacheHit?: OnCacheHitHook;
    onCacheMiss?: OnCacheMissHook;
    onCacheGetError?: OnCacheErrorHook;
}
type OnCacheErrorHook = (payload: OnCacheErrorHookPayload) => void;
interface OnCacheErrorHookPayload {
    error: Error;
}
type OnCacheHitHook = (payload: OnCacheHitHookEventPayload) => void;
interface OnCacheHitHookEventPayload {
    value: any;
}
type OnCacheMissHook = () => void;
type OnCacheSetHook = (payload: OnCacheSetHookEventPayload) => MaybePromise$1<OnCacheSetHookResult | void>;
interface OnCacheSetHookResult {
    onCacheSetDone?: () => void;
    onCacheSetError?: OnCacheErrorHook;
}
interface OnCacheSetHookEventPayload {
    cache: KeyValueCache;
    key: string;
    value: any;
    ttl?: number;
}
type OnCacheDeleteHook = (payload: OnCacheDeleteHookEventPayload) => MaybePromise$1<OnCacheDeleteHookResult | void>;
interface OnCacheDeleteHookResult {
    onCacheDeleteDone?: () => void;
    onCacheDeleteError?: OnCacheErrorHook;
}
interface OnCacheDeleteHookEventPayload {
    cache: KeyValueCache;
    key: string;
}
type Instrumentation<TContext extends Record<string, any>> = Instrumentation$1<TContext> & Instrumentation$2 & FetchInstrumentation;

interface DescriptionProviderConfig {
    type: string & {};
    [key: string]: unknown;
}
interface DescriptionProviderContext {
    label?: string;
}
interface DescriptionProvider {
    fetchDescription(toolName: string, config: DescriptionProviderConfig, context?: DescriptionProviderContext): Promise<string>;
}

type LangfuseGetPromptOptions = NonNullable<Parameters<Langfuse['getPrompt']>[2]>;
declare function createLangfuseProvider(client: Langfuse, defaults?: Partial<LangfuseGetPromptOptions>): DescriptionProvider;

declare module '@graphql-hive/gateway-runtime' {
    interface GatewayConfigContext {
        dispatchRequest?: (req: Request) => Response | Promise<Response>;
    }
}
type MCPToolSource = {
    type: 'inline';
    query: string;
} | {
    type: 'graphql';
    operationName: string;
    operationType: 'query' | 'mutation';
    file?: string;
};
interface MCPToolOverrides {
    title?: string;
    description?: string;
    descriptionProvider?: {
        type: 'langfuse';
        prompt: string;
        version?: number;
        options?: LangfuseGetPromptOptions;
    } | DescriptionProviderConfig;
}
interface MCPInputOverrides {
    schema?: {
        properties?: Record<string, {
            description?: string;
            examples?: unknown[];
            default?: unknown;
            alias?: string;
            descriptionProvider?: DescriptionProviderConfig;
        }>;
    };
}
interface MCPOutputOverrides {
    /** Dot-notation path to extract from the GraphQL response data, e.g. "search.items" */
    path: string;
}
interface ToolHookContext {
    toolName: string;
    headers: Record<string, string>;
    query: string;
}
interface MCPToolHooks {
    /**
     * Called before GraphQL execution. Receives de-aliased arguments
     * (original GraphQL variable names, not MCP alias names).
     * Return a non-undefined value to short-circuit execution and use that value as the tool result.
     * Return undefined (or void) to continue with normal GraphQL execution.
     * When preprocess short-circuits, postprocess is NOT called.
     */
    preprocess?: (args: Record<string, unknown>, context: ToolHookContext) => unknown | Promise<unknown>;
    /**
     * Called after GraphQL execution (and output.path extraction) to transform the result.
     * Not called when preprocess short-circuits.
     * When a postprocess hook is registered, the response uses text content
     * instead of structuredContent since the hook may change the result shape.
     */
    postprocess?: (result: unknown, args: Record<string, unknown>, context: ToolHookContext) => unknown | Promise<unknown>;
}
interface MCPToolConfig {
    name: string;
    source: MCPToolSource;
    tool?: MCPToolOverrides;
    input?: MCPInputOverrides;
    output?: MCPOutputOverrides;
    hooks?: MCPToolHooks;
}
interface MCPConfig {
    name: string;
    version?: string;
    path?: string;
    graphqlPath?: string;
    operationsPath?: string;
    operationsStr?: string;
    tools: MCPToolConfig[];
    providers?: {
        langfuse?: LangfuseOptions & {
            defaults?: Partial<LangfuseGetPromptOptions>;
        };
        [key: string]: DescriptionProvider | Record<string, unknown> | undefined;
    };
    disableGraphQLEndpoint?: boolean;
}
interface ResolvedToolConfig {
    name: string;
    query: string;
    tool?: MCPToolOverrides;
    input?: MCPInputOverrides;
    output?: MCPOutputOverrides;
    hooks?: MCPToolHooks;
    directiveDescription?: string;
    providerDescription?: string;
}
declare function useMCP(config: MCPConfig): GatewayPlugin;

export { type DescriptionProvider, type DescriptionProviderConfig, type DescriptionProviderContext, type MCPConfig, type MCPInputOverrides, type MCPOutputOverrides, type MCPToolConfig, type MCPToolHooks, type MCPToolOverrides, type MCPToolSource, type ResolvedToolConfig, type ToolHookContext, createLangfuseProvider, useMCP };
