import { NodeTracerProvider, Sampler } from '@opentelemetry/sdk-trace-node';
import { Attributes, Span, SpanAttributes } from '@opentelemetry/api';
import { ResourceAttributes, DetectorSync, Resource } from '@opentelemetry/resources';
import { InstrumentationOption, InstrumentationConfig, InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
import * as http from 'http';
import { IncomingMessage, ClientRequest, ServerResponse, RequestOptions } from 'http';
import * as url from 'url';
import * as https from 'https';

type BaselimeSDKOpts = {
    instrumentations?: InstrumentationOption[];
    collectorUrl?: string;
    baselimeKey?: string;
    service?: string;
    log?: boolean;
    namespace?: string;
    serverless?: boolean;
    sampler?: Sampler;
    resourceDetectors?: DetectorSync[];
    resourceAttributes?: Resource | Attributes;
};
declare class BaselimeSDK {
    options: BaselimeSDKOpts;
    attributes: ResourceAttributes;
    constructor(options: BaselimeSDKOpts);
    start(): NodeTracerProvider;
}

declare class HttpPlugin {
    parseIncommingMessage?(request: IncomingMessage): Record<string, unknown>;
    parseClientRequest?(request: ClientRequest): Record<string, unknown>;
    captureBody: boolean;
    name: string;
    constructor();
    shouldParseRequest(request: ClientRequest | IncomingMessage): boolean;
    shouldParseResponse(response: IncomingMessage | ServerResponse<IncomingMessage>): boolean;
}

type IgnoreMatcher = string | RegExp | ((url: string) => boolean);
type HttpCallback = (res: IncomingMessage) => void;
type HttpCallbackOptional = HttpCallback | undefined;
type RequestSignature = [http.RequestOptions, HttpCallbackOptional] & HttpCallback;
type HttpRequestArgs = Array<HttpCallbackOptional | RequestSignature>;
type Http = typeof http;
type Https = typeof https;
type Func<T> = (...args: any[]) => T;
interface HttpCustomAttributeFunction {
    (span: Span, request: ClientRequest | IncomingMessage, response: IncomingMessage | ServerResponse): void;
}
interface IgnoreIncomingRequestFunction {
    (request: IncomingMessage): boolean;
}
interface IgnoreOutgoingRequestFunction {
    (request: RequestOptions): boolean;
}
interface HttpRequestCustomAttributeFunction {
    (span: Span, request: ClientRequest | IncomingMessage): void;
}
interface HttpResponseCustomAttributeFunction {
    (span: Span, response: IncomingMessage | ServerResponse, cb: () => void): void;
}
interface StartIncomingSpanCustomAttributeFunction {
    (request: IncomingMessage): SpanAttributes;
}
interface StartOutgoingSpanCustomAttributeFunction {
    (request: RequestOptions): SpanAttributes;
}
interface HttpInstrumentationConfig extends InstrumentationConfig {
    ignoreIncomingPaths?: IgnoreMatcher[];
    ignoreIncomingRequestHook?: IgnoreIncomingRequestFunction;
    ignoreOutgoingUrls?: IgnoreMatcher[];
    ignoreOutgoingRequestHook?: IgnoreOutgoingRequestFunction;
    applyCustomAttributesOnSpan?: HttpCustomAttributeFunction;
    requestHook?: HttpRequestCustomAttributeFunction;
    responseHook?: HttpResponseCustomAttributeFunction;
    startIncomingSpanHook?: StartIncomingSpanCustomAttributeFunction;
    startOutgoingSpanHook?: StartOutgoingSpanCustomAttributeFunction;
    serverName?: string;
    requireParentforOutgoingSpans?: boolean;
    requireParentforIncomingSpans?: boolean;
    headersToSpanAttributes?: {
        client?: {
            requestHeaders?: string[];
            responseHeaders?: string[];
        };
        server?: {
            requestHeaders?: string[];
            responseHeaders?: string[];
        };
    };
}

declare class HttpInstrumentation extends InstrumentationBase<Http> {
    private readonly _spanNotEnded;
    private _headerCapture;
    private _httpServerDurationHistogram;
    private _httpClientDurationHistogram;
    constructor(config?: HttpInstrumentationConfig);
    protected _updateMetricInstruments(): void;
    private _getConfig;
    setConfig(config?: HttpInstrumentationConfig): void;
    init(): [
        InstrumentationNodeModuleDefinition<Https>,
        InstrumentationNodeModuleDefinition<Http>
    ];
    private _getHttpInstrumentation;
    private _getHttpsInstrumentation;
    protected _getPatchIncomingRequestFunction(component: 'http' | 'https'): (original: (event: string, ...args: unknown[]) => boolean) => (this: unknown, event: string, ...args: unknown[]) => boolean;
    protected _getPatchOutgoingRequestFunction(component: 'http' | 'https'): (original: Func<http.ClientRequest>) => Func<http.ClientRequest>;
    protected _getPatchOutgoingGetFunction(clientRequest: (options: http.RequestOptions | string | url.URL, ...args: HttpRequestArgs) => http.ClientRequest): (_original: Func<http.ClientRequest>) => Func<http.ClientRequest>;
    private _getPatchHttpsOutgoingRequestFunction;
    private _setDefaultOptions;
    private _getPatchHttpsOutgoingGetFunction;
    private _traceClientRequest;
    private _incomingRequestFunction;
    private _outgoingRequestFunction;
    private _onServerResponseFinish;
    private _onServerResponseError;
    private _startHttpSpan;
    private _closeHttpSpan;
    private _callResponseHook;
    private _callRequestHook;
    private _callStartSpanHook;
    private _createHeaderCapture;
}

type BetterHttpInstrumentationOptions = {
    plugins?: HttpPlugin[];
    captureBody?: boolean;
    captureHeaders?: boolean;
    requestHook?: HttpInstrumentationConfig['requestHook'];
    responseHook?: HttpInstrumentationConfig['responseHook'];
    ignoreIncomingRequestHook?: HttpInstrumentationConfig['ignoreIncomingRequestHook'];
    ignoreOutgoingRequestHook?: HttpInstrumentationConfig['ignoreOutgoingRequestHook'];
    startIncomingSpanHook?: HttpInstrumentationConfig['startIncomingSpanHook'];
    startOutgoingSpanHook?: HttpInstrumentationConfig['startOutgoingSpanHook'];
};
declare class BetterHttpInstrumentation extends HttpInstrumentation {
    constructor(options?: BetterHttpInstrumentationOptions);
}

declare class StripePlugin extends HttpPlugin implements HttpPlugin {
    captureBody: boolean;
    name: string;
    shouldParseRequest(request: ClientRequest | IncomingMessage): boolean;
    parseClientRequest(request: ClientRequest): {
        stripe: {
            version: string;
            method: string;
            entity: string;
            entityIdOrOperation: string;
            operation: string;
        };
    };
}

declare class VercelPlugin extends HttpPlugin implements HttpPlugin {
    name: string;
    shouldParseRequest(request: ClientRequest | IncomingMessage): boolean;
    parseIncommingMessage(request: IncomingMessage): {
        requestId: string;
        faas: {
            execution: string;
        };
        user: {
            ip: string | string[];
            country: string | string[];
            region: string | string[];
            city: string | string[];
            latitude: string | string[];
            longitude: string | string[];
            timezone: string | string[];
        };
    };
}

export { BaselimeSDK, BetterHttpInstrumentation, HttpPlugin, StripePlugin, VercelPlugin };
