import { SpanStatusCode, TimeInput, Link, BaggageEntry } from '@opentelemetry/api';

/**
 * Trace context types and utilities
 */

/**
 * Base trace context containing trace identifiers
 */
interface TraceContextBase {
    traceId: string;
    spanId: string;
    correlationId: string;
}
/**
 * Attribute value types following OpenTelemetry specification.
 * Supports primitive values and arrays of homogeneous primitives.
 */
type AttributeValue = string | number | boolean | string[] | number[] | boolean[];
/**
 * Span methods available on trace context
 */
interface SpanMethods {
    /** Set a single attribute on the span */
    setAttribute(key: string, value: AttributeValue): void;
    /** Set multiple attributes on the span */
    setAttributes(attrs: Record<string, AttributeValue>): void;
    /** Set the status of the span */
    setStatus(status: {
        code: SpanStatusCode;
        message?: string;
    }): void;
    /** Record an exception on the span */
    recordException(exception: Error, time?: TimeInput): void;
    /** Add an event to the span (for logging milestones/checkpoints) */
    addEvent(name: string, attributesOrStartTime?: Record<string, AttributeValue> | TimeInput, startTime?: TimeInput): void;
    /** Add a link to another span */
    addLink(link: Link): void;
    /** Add multiple links to other spans */
    addLinks(links: Link[]): void;
    /** Update the span name dynamically */
    updateName(name: string): void;
    /** Check if the span is recording */
    isRecording(): boolean;
}
/**
 * Baggage methods available on trace context
 *
 * @template TBaggage - Optional type for typed baggage (defaults to undefined for untyped)
 */
interface BaggageMethods<TBaggage extends Record<string, unknown> | undefined = undefined> {
    /**
     * Get a baggage entry by key
     * @param key - Baggage key
     * @returns Baggage entry value or undefined
     */
    getBaggage(key: string): string | undefined;
    /**
     * Set a baggage entry
     *
     * Note: OpenTelemetry contexts are immutable. For proper scoping across async
     * boundaries, use withBaggage() instead. This method updates baggage in the
     * current context which may not propagate to all child operations.
     *
     * @param key - Baggage key
     * @param value - Baggage value
     * @returns The baggage value that was set (for chaining)
     *
     * @example Using withBaggage() (recommended)
     * ```typescript
     * await withBaggage({ baggage: { 'key': 'value' }, fn: async () => {
     *   // Baggage is available here and in child spans
     * });
     * ```
     */
    setBaggage(key: string, value: string): string;
    /**
     * Delete a baggage entry
     *
     * Note: OpenTelemetry contexts are immutable. For proper scoping across async
     * boundaries, use withBaggage() with only the entries you want instead.
     *
     * @param key - Baggage key
     */
    deleteBaggage(key: string): void;
    /**
     * Get all baggage entries
     * @returns Map of all baggage entries
     */
    getAllBaggage(): Map<string, BaggageEntry>;
    /**
     * Get typed baggage (only available when TBaggage is defined)
     * This is used internally by defineBaggageSchema()
     *
     * @internal
     */
    getTypedBaggage?: TBaggage extends Record<string, unknown> ? <T extends TBaggage>(namespace?: string) => Partial<T> | undefined : never;
    /**
     * Set typed baggage (only available when TBaggage is defined)
     * This is used internally by defineBaggageSchema()
     *
     * @internal
     */
    setTypedBaggage?: TBaggage extends Record<string, unknown> ? <T extends TBaggage>(namespace: string | undefined, value: Partial<T>) => void : never;
}
/**
 * Complete trace context that merges base context, span methods, and baggage methods
 *
 * This is the ctx parameter passed to factory functions in trace().
 * It provides access to trace IDs, span manipulation methods, and baggage operations.
 *
 * @template TBaggage - Optional type for typed baggage support
 *
 * @example Untyped (default)
 * ```typescript
 * export const handler = trace((ctx) => async () => {
 *   ctx.getBaggage('key'); // returns string | undefined
 * });
 * ```
 *
 * @example Typed baggage
 * ```typescript
 * type TenantBaggage = { tenantId: string; region?: string };
 *
 * export const handler = trace<TenantBaggage>((ctx) => async () => {
 *   // Use typed schema helper for type-safe access
 *   const schema = defineBaggageSchema<TenantBaggage>('tenant');
 *   const tenant = schema.get(ctx); // Partial<TenantBaggage> | undefined
 * });
 * ```
 */
type TraceContext<TBaggage extends Record<string, unknown> | undefined = undefined> = TraceContextBase & SpanMethods & BaggageMethods<TBaggage>;
/**
 * Define a typed baggage schema for type-safe baggage operations
 *
 * This helper provides a type-safe API for working with baggage entries.
 * The namespace parameter is optional and prefixes all keys to avoid collisions.
 *
 * @template T - The baggage schema type (all fields are treated as optional)
 * @param namespace - Optional namespace to prefix baggage keys
 *
 * @example Basic usage
 * ```typescript
 * type TenantBaggage = { tenantId: string; region?: string };
 * const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
 *
 * export const handler = trace<TenantBaggage>((ctx) => async () => {
 *   // Get typed baggage
 *   const tenant = tenantBaggage.get(ctx);
 *   if (tenant?.tenantId) {
 *     console.log('Tenant:', tenant.tenantId);
 *   }
 *
 *   // Set typed baggage
 *   tenantBaggage.set(ctx, { tenantId: 't1', region: 'us-east-1' });
 * });
 * ```
 *
 * @example With withBaggage helper
 * ```typescript
 * const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
 *
 * export const handler = trace<TenantBaggage>((ctx) => async () => {
 *   return await tenantBaggage.with(ctx, { tenantId: 't1' }, async () => {
 *     // Baggage is available here and in child spans
 *     const tenant = tenantBaggage.get(ctx);
 *   });
 * });
 * ```
 */
declare function defineBaggageSchema<T extends Record<string, unknown>>(namespace?: string): {
    /**
     * Get typed baggage from context
     * @param ctx - Trace context
     * @returns Partial baggage object or undefined if no baggage is set
     */
    get: (ctx: TraceContext<T>) => Partial<T> | undefined;
    /**
     * Set typed baggage in context
     *
     * Note: For proper scoping across async boundaries, use the `with` method instead
     *
     * @param ctx - Trace context
     * @param value - Partial baggage object to set
     */
    set: (ctx: TraceContext<T>, value: Partial<T>) => void;
    /**
     * Run a function with typed baggage properly scoped
     *
     * This is the recommended way to set baggage as it ensures proper
     * scoping across async boundaries.
     *
     * @param ctx - Trace context (can be omitted, will use active context)
     * @param value - Partial baggage object to set
     * @param fn - Function to execute with the baggage
     */
    with: <R>(ctxOrValue: TraceContext<T> | Partial<T>, valueOrFn: Partial<T> | (() => R | Promise<R>), maybeFn?: () => R | Promise<R>) => R | Promise<R>;
};

export { type AttributeValue as A, type TraceContext as T, defineBaggageSchema as d };
