import { GatewayPlugin, GatewayConfigContext } 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 | TracesConfig;
};
type TracesConfig = {
    /**
     * 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?: SpansConfig;
    events?: {
        /**
         * Enable/Disable cache related span events (default: true).
         */
        cache?: BooleanOrPredicate<{
            key: string;
            action: 'read' | 'write';
        }>;
    };
};
type SpansConfig = {
    /**
     * Enable/disable HTTP request spans (default: true).
     *
     * Disabling the HTTP span will also disable all other child spans.
     */
    http?: BooleanOrPredicate<{
        request: Request;
        ignoredRequests: WeakSet<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;
};
type ContextMatcher = {
    request?: Request;
    context?: any;
    executionRequest?: ExecutionRequest;
};
type OpenTelemetryPluginUtils = {
    tracer: Tracer;
    /**
     * Returns the current active OTEL context.
     *
     * Note: Defaults to `otel.context.active()` if no plugin is registered.
     */
    getActiveContext: (payload: ContextMatcher) => Context;
    /**
     * Returns the http request root span context.
     * Returns `undefined` if the current request is not being traced.
     *
     * Note: Defaults to `otel.context.active()` if no plugin is registered.
     */
    getHttpContext: (request: Request) => Context | undefined;
    /**
     * Returns the current GraphQL operation root span context.
     * Returns `undefined` if the current GraphQL operation is not being traced.
     *
     * Note: Defaults to `otel.context.active()` if no plugin is registered.
     */
    getOperationContext: (context: any) => Context | undefined;
    /**
     * Returns the current subgraph Execution Request root span context.
     * Returns `undefined` if the current subgraph Execution Request is not being traced.
     *
     * Note: Defaults to `otel.context.active()` if no plugin is registered.
     */
    getExecutionRequestContext: (ExecutionRequest: ExecutionRequest) => Context | undefined;
    ignoreRequest: (request: Request) => void;
};
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 };
