import { Link, SpanContext } from '@opentelemetry/api';
import { T as TraceContext } from './trace-context-DbGKd1Rn.cjs';

/**
 * Webhook and callback tracing with the "Parking Lot" pattern
 *
 * When initiating async operations that return hours/days later (webhooks,
 * payment callbacks, human approvals), you can't keep a span open. This module
 * provides utilities to "park" trace context and retrieve it when callbacks arrive.
 *
 * @example Stripe payment webhook
 * ```typescript
 * import { createParkingLot, InMemoryTraceContextStore } from 'autotel/webhook';
 *
 * const parkingLot = createParkingLot({
 *   store: new InMemoryTraceContextStore(),
 *   defaultTTLMs: 24 * 60 * 60 * 1000, // 24 hours
 * });
 *
 * // When initiating payment
 * export const initiatePayment = trace(ctx => async (orderId: string) => {
 *   await parkingLot.park(`payment:${orderId}`, { orderId });
 *   await stripeClient.createPaymentIntent({ metadata: { orderId } });
 * });
 *
 * // When Stripe webhook arrives (hours later)
 * export const handleStripeWebhook = parkingLot.traceCallback({
 *   name: 'stripe.webhook.payment_intent.succeeded',
 *   correlationKeyFrom: (event) => `payment:${event.data.object.metadata.orderId}`,
 * })(ctx => async (event: Stripe.Event) => {
 *   // ctx.parkedContext contains the original trace context
 *   // ctx.elapsedMs shows time since payment was initiated
 *   await fulfillOrder(event.data.object);
 * });
 * ```
 *
 * @module
 */

/**
 * Stored trace context for parking lot pattern
 */
interface StoredTraceContext {
    /** Trace ID from the original span */
    traceId: string;
    /** Span ID from the original span */
    spanId: string;
    /** Trace flags (sampling decision) */
    traceFlags: number;
    /** When the context was parked */
    parkedAt: number;
    /** Optional TTL in milliseconds */
    ttlMs?: number;
    /** User-provided metadata */
    metadata?: Record<string, string>;
}
/**
 * Interface for trace context storage backends
 *
 * Implement this interface to use different storage backends (Redis, DynamoDB, etc.)
 */
interface TraceContextStore {
    /**
     * Save trace context with a correlation key
     *
     * @param key - Unique correlation key (e.g., "payment:order-123")
     * @param context - The trace context to store
     */
    save(key: string, context: StoredTraceContext): Promise<void>;
    /**
     * Load trace context by correlation key
     *
     * @param key - The correlation key used when parking
     * @returns The stored context, or null if not found/expired
     */
    load(key: string): Promise<StoredTraceContext | null>;
    /**
     * Delete trace context by correlation key
     *
     * @param key - The correlation key to delete
     */
    delete(key: string): Promise<void>;
}
/**
 * Configuration for creating a parking lot
 */
interface ParkingLotConfig {
    /** Storage backend for parked contexts */
    store: TraceContextStore;
    /** Default TTL in milliseconds (default: 24 hours) */
    defaultTTLMs?: number;
    /** Prefix for all correlation keys (default: "parkingLot:") */
    keyPrefix?: string;
    /** Whether to auto-delete after retrieval (default: true) */
    autoDeleteOnRetrieve?: boolean;
    /** Callback when context expires or is not found */
    onMiss?: (correlationKey: string) => void;
}
/**
 * Configuration for traceCallback wrapper
 */
interface CallbackConfig {
    /** Span name for the callback handler */
    name: string;
    /**
     * Extract correlation key from callback arguments
     *
     * @example
     * ```typescript
     * correlationKeyFrom: (event) => `payment:${event.data.orderId}`
     * ```
     */
    correlationKeyFrom: (args: unknown[]) => string;
    /** Additional span attributes */
    attributes?: Record<string, string | number | boolean>;
    /** Whether to fail if parked context is not found (default: false) */
    requireParkedContext?: boolean;
}
/**
 * Extended context for callback handlers
 */
interface CallbackContext extends TraceContext {
    /** The retrieved parked context, if found */
    parkedContext: StoredTraceContext | null;
    /** Time elapsed since context was parked (ms), or null if not found */
    elapsedMs: number | null;
    /** The correlation key used for retrieval */
    correlationKey: string;
}
/**
 * The parking lot instance
 */
interface ParkingLot {
    /**
     * Park current trace context before initiating async operation
     *
     * Call this before sending a webhook, initiating a payment, or starting
     * any operation that will complete via callback.
     *
     * @param correlationKey - Unique key to retrieve context later (e.g., "payment:order-123")
     * @param metadata - Optional metadata to store with the context
     * @returns The correlation key (with prefix applied)
     *
     * @example
     * ```typescript
     * await parkingLot.park(`payment:${orderId}`, {
     *   customerId: customer.id,
     *   amount: payment.amount.toString(),
     * });
     * ```
     */
    park(correlationKey: string, metadata?: Record<string, string>): Promise<string>;
    /**
     * Retrieve parked context when callback arrives
     *
     * @param correlationKey - The key used when parking
     * @returns The stored context, or null if not found/expired
     */
    retrieve(correlationKey: string): Promise<StoredTraceContext | null>;
    /**
     * Wrap a callback handler with automatic context retrieval and linking
     *
     * Creates a traced function that:
     * 1. Extracts correlation key from arguments
     * 2. Retrieves parked context from storage
     * 3. Creates a span link to the original trace
     * 4. Provides elapsed time since parking
     *
     * @param config - Callback configuration
     * @returns Factory function for the callback handler
     *
     * @example
     * ```typescript
     * export const handleWebhook = parkingLot.traceCallback({
     *   name: 'webhook.payment.completed',
     *   correlationKeyFrom: (args) => `payment:${args[0].orderId}`,
     * })(ctx => async (event) => {
     *   console.log(`Payment completed after ${ctx.elapsedMs}ms`);
     *   await processPayment(event);
     * });
     * ```
     */
    traceCallback<TArgs extends unknown[], TReturn>(config: CallbackConfig): (fnFactory: (ctx: CallbackContext) => (...args: TArgs) => Promise<TReturn>) => (...args: TArgs) => Promise<TReturn>;
    /**
     * Manually create a span link from stored context
     *
     * Useful when you need more control over span creation.
     *
     * @param storedContext - The stored trace context
     * @returns A span link that can be added to a span
     */
    createLink(storedContext: StoredTraceContext): Link;
    /**
     * Check if a parked context exists (without retrieving/deleting it)
     *
     * @param correlationKey - The key to check
     * @returns True if context exists and hasn't expired
     */
    exists(correlationKey: string): Promise<boolean>;
}
/**
 * In-memory trace context store
 *
 * Useful for testing and development. For production, use a persistent
 * store like Redis or DynamoDB.
 *
 * @example
 * ```typescript
 * const store = new InMemoryTraceContextStore();
 * const parkingLot = createParkingLot({ store });
 * ```
 */
declare class InMemoryTraceContextStore implements TraceContextStore {
    private options;
    private store;
    private cleanupInterval;
    constructor(options?: {
        /** Cleanup interval in ms (default: 60000) */
        cleanupIntervalMs?: number;
    });
    save(key: string, context: StoredTraceContext): Promise<void>;
    load(key: string): Promise<StoredTraceContext | null>;
    delete(key: string): Promise<void>;
    /**
     * Get number of stored contexts (for testing)
     */
    get size(): number;
    /**
     * Clear all stored contexts (for testing)
     */
    clear(): void;
    /**
     * Stop the cleanup interval
     */
    destroy(): void;
    private cleanup;
}
/**
 * Create a parking lot for trace context storage and retrieval
 *
 * @param config - Parking lot configuration
 * @returns A parking lot instance
 *
 * @example Basic usage
 * ```typescript
 * const parkingLot = createParkingLot({
 *   store: new InMemoryTraceContextStore(),
 *   defaultTTLMs: 24 * 60 * 60 * 1000, // 24 hours
 * });
 * ```
 *
 * @example With Redis store
 * ```typescript
 * class RedisTraceContextStore implements TraceContextStore {
 *   constructor(private redis: Redis) {}
 *
 *   async save(key: string, context: StoredTraceContext) {
 *     const ttlSeconds = context.ttlMs ? Math.ceil(context.ttlMs / 1000) : 86400;
 *     await this.redis.setex(key, ttlSeconds, JSON.stringify(context));
 *   }
 *
 *   async load(key: string) {
 *     const data = await this.redis.get(key);
 *     return data ? JSON.parse(data) : null;
 *   }
 *
 *   async delete(key: string) {
 *     await this.redis.del(key);
 *   }
 * }
 *
 * const parkingLot = createParkingLot({
 *   store: new RedisTraceContextStore(redis),
 * });
 * ```
 */
declare function createParkingLot(config: ParkingLotConfig): ParkingLot;
/**
 * Create a correlation key from multiple parts
 *
 * @param parts - Key parts to join
 * @returns A correlation key string
 *
 * @example
 * ```typescript
 * const key = createCorrelationKey('payment', orderId, 'stripe');
 * // Returns: "payment:order-123:stripe"
 * ```
 */
declare function createCorrelationKey(...parts: (string | number)[]): string;
/**
 * Extract span context from stored context for manual linking
 *
 * @param storedContext - The stored trace context
 * @returns SpanContext compatible object
 */
declare function toSpanContext(storedContext: StoredTraceContext): SpanContext;

export { type CallbackConfig, type CallbackContext, InMemoryTraceContextStore, type ParkingLot, type ParkingLotConfig, type StoredTraceContext, type TraceContextStore, createCorrelationKey, createParkingLot, toSpanContext };
