import { Attributes } from '@opentelemetry/api';
import { Context } from '@opentelemetry/api';
import { EvaluationSeriesContext } from '@launchdarkly/js-client-sdk';
import { EvaluationSeriesData } from '@launchdarkly/js-client-sdk';
import { Hook as Hook_2 } from '@launchdarkly/js-client-sdk';
import { LDEvaluationReason } from '@launchdarkly/js-client-sdk';
import { LDFlagValue } from '@launchdarkly/js-client-sdk';
import { LDPluginEnvironmentMetadata } from '@launchdarkly/js-client-sdk';
import { Span } from '@opentelemetry/api';
import { SpanOptions } from '@opentelemetry/api';

declare const ALL_CONSOLE_METHODS: readonly ["assert", "count", "countReset", "debug", "dir", "dirxml", "error", "group", "groupCollapsed", "groupEnd", "info", "log", "table", "time", "timeEnd", "timeLog", "trace", "warn"];

declare class BufferedClass<T extends object> {
    protected _sdk: T;
    protected _isLoaded: boolean;
    protected _callBuffer: Array<Event_2>;
    protected _capacity: number;
    protected _droppedEvents: number;
    protected _exceededCapacity: boolean;
    protected _logger: Logger;
    protected _bufferCall(method: string, args: any[]): any;
    protected _enqueue(event: Event_2): void;
    load(sdk: T): void;
}

declare type ConsoleMethods = ConsoleMethodsTuple[number];

declare type ConsoleMethodsTuple = typeof ALL_CONSOLE_METHODS;

declare type ErrorMessageType = 'console.error' | 'window.onerror' | 'window.onunhandledrejection' | 'custom' | 'React.ErrorBoundary';

declare type Event_2 = {
    method: string;
    args: any[];
};

/**
 * Interface for extending SDK functionality via hooks.
 */
declare type Hook = Omit<Hook_2, 'afterEvaluation'> & {
    /**
     * This method is called during the execution of the variation method
     * after the flag value has been determined. The method is executed synchronously.
     *
     * @param hookContext Contains read-only information about the evaluation
     * being performed.
     * @param data A record associated with each stage of hook invocations. Each
     *  stage is called with the data of the previous stage for a series.
     * @param detail The result of the evaluation. This value should not be
     * modified.
     * @returns Data to use when executing the next state of the hook in the evaluation series. It is
     * recommended to expand the previous input into the return. This helps ensure your stage remains
     * compatible moving forward as more stages are added.
     * ```js
     * return {...data, "my-new-field": /*my data/*}
     * ```
     */
    afterEvaluation?(hookContext: EvaluationSeriesContext, data: EvaluationSeriesData, detail: {
        /**
         * The result of the flag evaluation. This will be either one of the flag's variations or
         * the default value that was passed to `LDClient.variationDetail`.
         */
        value: LDFlagValue;
        /**
         * The index of the returned value within the flag's list of variations, e.g. 0 for the
         * first variation-- or `null` if the default value was returned.
         */
        variationIndex?: number | null;
        /**
         * An object describing the main factor that influenced the flag evaluation value.
         */
        reason?: LDEvaluationReason | null;
    }): EvaluationSeriesData;
};

declare interface LDClientMin {
    track(key: string, data?: any, metricValue?: number): void;
    identify(ctx: any): void;
    addHook(hook: Hook): void;
}

export declare let LDObserve: _LDObserve;

declare class _LDObserve extends BufferedClass<Observe> implements Observe {
    start(): Promise<void>;
    stop(): Promise<void>;
    recordGauge(metric: OTelMetric): any;
    recordCount(metric: OTelMetric): any;
    recordIncr(metric: Omit<OTelMetric, 'value'>): any;
    recordHistogram(metric: OTelMetric): any;
    recordUpDownCounter(metric: OTelMetric): any;
    startSpan(name: string, options: SpanOptions | ((span?: Span) => any), context?: Context | ((span?: Span) => any), fn?: (span?: Span) => any): any;
    startManualSpan(name: string, options: SpanOptions | ((span: Span) => any), context?: Context | ((span: Span) => any), fn?: (span: Span) => any): any;
    register(client: LDClientMin, environmentMetadata: LDPluginEnvironmentMetadata): any;
    recordLog(message: any, level: ConsoleMethods, metadata?: Attributes): any;
    recordError(error: Error, message?: string, payload?: {
        [key: string]: string;
    }, source?: string, type?: ErrorMessageType): any;
    setLDContextKeyAttributes(contextKeys: Attributes): any;
    getLDContextKeyAttributes(): Attributes | undefined;
}

declare class Logger {
    debug: boolean | undefined;
    name: string | undefined;
    constructor(debug?: boolean, name?: string);
    log(...data: any[]): void;
    warn(...data: any[]): void;
}

declare interface Observe {
    /**
     * Start the observability data capture when running in `manualStart` mode.
     */
    start: () => Promise<void>;
    /**
     * Stop the observability data capture.
     */
    stop: () => Promise<void>;
    /**
     * Record arbitrary metric values via as a Gauge.
     * A Gauge records any point-in-time measurement, such as the current CPU utilization %.
     * Values with the same metric name and attributes are aggregated via the OTel SDK.
     * See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
     */
    recordGauge: (metric: OTelMetric) => void;
    /**
     * Record arbitrary metric values via as a Counter.
     * A Counter efficiently records an increment in a metric, such as number of cache hits.
     * Values with the same metric name and attributes are aggregated via the OTel SDK.
     * See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
     */
    recordCount: (metric: OTelMetric) => void;
    /**
     * Record arbitrary metric values via as a Counter.
     * A Counter efficiently records an increment in a metric, such as number of cache hits.
     * Values with the same metric name and attributes are aggregated via the OTel SDK.
     * See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
     */
    recordIncr: (metric: Omit<OTelMetric, 'value'>) => void;
    /**
     * Record arbitrary metric values via as a Histogram.
     * A Histogram efficiently records near-by point-in-time measurement into a bucketed aggregate.
     * Values with the same metric name and attributes are aggregated via the OTel SDK.
     * See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
     */
    recordHistogram: (metric: OTelMetric) => void;
    /**
     * Record arbitrary metric values via as a UpDownCounter.
     * A UpDownCounter efficiently records an increment or decrement in a metric, such as number of paying customers.
     * Values with the same metric name and attributes are aggregated via the OTel SDK.
     * See https://opentelemetry.io/docs/specs/otel/metrics/data-model/ for more details.
     */
    recordUpDownCounter: (metric: OTelMetric) => void;
    /**
     * Starts a new span for tracing in Highlight. The span will be ended when the
     * callback function returns.
     *
     * @example
     * ```typescript
     * H.startSpan('span-name', callbackFn)
     * ```
     * @example
     * ```typescript
     * H.startSpan('span-name', options, callbackFn)
     * ```
     * @example
     * ```typescript
     * H.startSpan('span-name', options, context, callbackFn)
     * ```
     * @example
     * ```typescript
     * H.startSpan('span-name', async (span) => {
     *   span.setAttribute('key', 'value')
     *   await someAsyncFunction()
     * })
     * ```
     *
     * @param name The name of the span.
     * @param options Options for the span.
     * @param context The context for the span.
     * @param callbackFn The function to run in the span.
     */
    startSpan: {
        <F extends (span?: Span) => ReturnType<F>>(name: string, fn: F): ReturnType<F>;
        <F extends (span?: Span) => ReturnType<F>>(name: string, options: SpanOptions, fn: F): ReturnType<F>;
        <F extends (span?: Span) => ReturnType<F>>(name: string, options: SpanOptions, context: Context, fn: F): ReturnType<F>;
    };
    /**
     * Starts a new span for tracing in Highlight. The span will be ended when the
     * `end()` is called on the span. It returns whatever is returned from the
     * callback function.
     *
     * @example
     * ```typescript
     * H.startManualSpan('span-name', options, (span) => {
     *   span.addEvent('event-name', { key: 'value' })
     *   span.setAttribute('key', 'value')
     *   await someAsyncFunction()
     *   span.end()
     * })
     * ```
     *
     * @example
     * ```typescript
     * const span = H.startManualSpan('span-name', (s) => s)
     * span.addEvent('event-name', { key: 'value' })
     * await someAsyncFunction()
     * span.end()
     * ```
     *
     * @param name The name of the span.
     * @param options Options for the span.
     * @param context The context for the span.
     * @param fn The function to run in the span.
     */
    startManualSpan: {
        <F extends (span: Span) => ReturnType<F>>(name: string, fn: F): ReturnType<F>;
        <F extends (span: Span) => ReturnType<F>>(name: string, options: SpanOptions, fn: F): ReturnType<F>;
        <F extends (span: Span) => ReturnType<F>>(name: string, options: SpanOptions, context: Context, fn: F): ReturnType<F>;
    };
    /**
     * Calling this method will report an error in Highlight and map it to the current session being recorded.
     * A common use case for `H.error` is calling it right outside of an error boundary.
     * @see {@link https://docs.highlight.run/grouping-errors} for more information.
     */
    recordError: (error: any, message?: string, payload?: {
        [key: string]: string;
    }, source?: string, type?: ErrorMessageType) => void;
    /**
     * Record arbitrary logs from your own integrations or manual.
     * Useful when you don't want to emit a console log to the browser dev tools but still want to report a custom log.
     */
    recordLog: (message: any, level: ConsoleMethods, metadata?: Attributes) => void;
    register(client: LDClientMin, environmentMetadata: LDPluginEnvironmentMetadata): void;
    getHooks?(metadata: LDPluginEnvironmentMetadata): Hook[];
    setLDContextKeyAttributes(contextKeys: Attributes): void;
    getLDContextKeyAttributes(): Attributes | undefined;
}

declare interface OTelMetric {
    name: string;
    value: number;
    attributes?: Attributes;
}

export { }
