import { GatewayConfigContext, GatewayPlugin } from '@graphql-hive/gateway-runtime';
import { ExecutionRequest } from '@graphql-tools/utils';
import { Tracer, Context } from '@opentelemetry/api';
import { DocumentNode, GraphQLSchema } from 'graphql';

type OperationHashingFn = (input: {
    document: DocumentNode;
    operationName?: string | null;
    variableValues?: Record<string, unknown> | null;
    schema: GraphQLSchema;
}) => string | null;

type BooleanOrPredicate<TInput = never> = boolean | ((input: TInput) => boolean);
type OpenTelemetryGatewayPluginOptions = {
    /**
     * Whether to rely on OTEL context api for span correlation.
     *  - `true`: the plugin will rely on OTEL context manager for span parenting.
     *  - `false`: the plugin will rely on request context for span parenting,
     *    which implies that parenting with user defined may be broken.
     *
     * By default, it is enabled if the registered Context Manager is compatible with async calls,
     * or if it is possible to register an `AsyncLocalStorageContextManager`.
     *
     * Note: If `true`, an error is thrown if it fails to obtain an async calls compatible Context Manager.
     */
    useContextManager?: boolean;
    /**
     * Whether to inherit the context from the calling service (default: true).
     *
     * This process is done by extracting the context from the incoming request headers. If disabled, a new context and a trace-id will be created.
     *
     * See https://opentelemetry.io/docs/languages/js/propagation/
     */
    inheritContext?: boolean;
    /**
     * Whether to propagate the context to the outgoing requests (default: true).
     *
     * This process is done by injecting the context into the outgoing request headers. If disabled, the context will not be propagated.
     *
     * See https://opentelemetry.io/docs/languages/js/propagation/
     */
    propagateContext?: boolean;
    /**
     * The TraceProvider method to call on Gateway's disposal. By default, it tries to run `forceFlush` method on
     * the registered trace provider if it exists.
     * Set to `false` to disable this behavior.
     * @default 'forceFlush'
     */
    flushOnDispose?: string | false;
    /**
     * Function to be used to compute the hash of each operation (graphql.operation.hash attribute).
     * Note: pass `null` to disable operation hashing
     *
     * @default `hashOperation` from @graphql-hive/core
     */
    hashOperation?: OperationHashingFn | null;
    /**
     * Tracing configuration
     */
    traces?: boolean | {
        /**
         * Tracer instance to use for creating spans (default: a tracer with name 'gateway').
         */
        tracer?: Tracer;
        /**
         * Options to control which spans to create.
         * By default, all spans are enabled.
         *
         * You may specify a boolean value to enable/disable all spans, or a function to dynamically enable/disable spans based on the input.
         */
        spans?: {
            /**
             * Enable/disable HTTP request spans (default: true).
             *
             * Disabling the HTTP span will also disable all other child spans.
             */
            http?: BooleanOrPredicate<{
                request: Request;
            }>;
            /**
             * Enable/disable GraphQL operation spans (default: true).
             *
             * Disabling the GraphQL operation spa will also disable all other child spans.
             */
            graphql?: BooleanOrPredicate<{
                context: unknown;
            }>;
            /**
             * Enable/disable GraphQL context building phase (default: true).
             */
            graphqlContextBuilding?: BooleanOrPredicate<{
                context: unknown;
            }>;
            /**
             * Enable/disable GraphQL parse spans (default: true).
             */
            graphqlParse?: BooleanOrPredicate<{
                context: unknown;
            }>;
            /**
             * Enable/disable GraphQL validate spans (default: true).
             */
            graphqlValidate?: BooleanOrPredicate<{
                context: unknown;
            }>;
            /**
             * Enable/disable GraphQL execute spans (default: true).
             *
             * Disabling the GraphQL execute spans will also disable all other child spans.
             */
            graphqlExecute?: BooleanOrPredicate<{
                context: unknown;
            }>;
            /**
             * Enable/disable subgraph execute spans (default: true).
             *
             * Disabling the subgraph execute spans will also disable all other child spans.
             */
            subgraphExecute?: BooleanOrPredicate<{
                executionRequest: ExecutionRequest;
                subgraphName: string;
            }>;
            /**
             * Enable/disable upstream HTTP fetch calls spans (default: true).
             */
            upstreamFetch?: BooleanOrPredicate<{
                executionRequest: ExecutionRequest | undefined;
            }>;
            /**
             * Enable/disable schema loading spans (default: true if context manager available).
             *
             * Note: This span requires an Async compatible context manager
             */
            schema?: boolean;
            /**
             * Enable/disable initialization span (default: true).
             */
            initialization?: boolean;
        };
        events?: {
            /**
             * Enable/Disable cache related span events (default: true).
             */
            cache?: BooleanOrPredicate<{
                key: string;
                action: 'read' | 'write';
            }>;
        };
    };
};
type ContextMatcher = {
    request?: Request;
    context?: any;
    executionRequest?: ExecutionRequest;
};
type OpenTelemetryPluginUtils = {
    tracer: Tracer;
    getActiveContext: (payload: ContextMatcher) => Context;
    getHttpContext: (request: Request) => Context | undefined;
    getOperationContext: (context: any) => Context | undefined;
    getExecutionRequestContext: (ExecutionRequest: ExecutionRequest) => Context | undefined;
};
type OpenTelemetryContextExtension = {
    openTelemetry: {
        tracer: Tracer;
        getActiveContext: (payload?: ContextMatcher) => Context;
        getHttpContext: (request?: Request) => Context | undefined;
        getOperationContext: (context?: any) => Context | undefined;
        getExecutionRequestContext: (ExecutionRequest: ExecutionRequest) => Context | undefined;
    };
};
type OpenTelemetryPlugin = GatewayPlugin<OpenTelemetryContextExtension> & OpenTelemetryPluginUtils;
declare function useOpenTelemetry(options: OpenTelemetryGatewayPluginOptions & Partial<GatewayConfigContext>): OpenTelemetryPlugin;

export { type OpenTelemetryContextExtension as O, type OpenTelemetryGatewayPluginOptions as a, type OpenTelemetryPlugin as b, type OpenTelemetryPluginUtils as c, useOpenTelemetry as u };
