import * as _opentelemetry_sdk_trace_base from '@opentelemetry/sdk-trace-base';
import { SpanProcessor, SpanExporter } from '@opentelemetry/sdk-trace-base';
import { NodeSDKConfiguration, NodeSDK } from '@opentelemetry/sdk-node';
import { Resource } from '@opentelemetry/resources';
import { Sampler, SamplingPreset } from './sampling.js';
import { EventSubscriber } from './event-subscriber.js';
import { Logger } from './logger.js';
import { Attributes } from '@opentelemetry/api';
import { MetricReader } from '@opentelemetry/sdk-metrics';
import { LogRecordProcessor } from '@opentelemetry/sdk-logs';
import { SpanFilterPredicate } from './filtering-span-processor.js';
import { SpanNameNormalizerConfig } from './span-name-normalizer.js';
import { AttributeRedactorConfig, AttributeRedactorPreset } from './attribute-redacting-processor.js';
import { CanonicalLogLineOptions } from './processors.js';

/**
 * Input validation for events events and attributes
 *
 * Prevents:
 * - Invalid event names
 * - Oversized payloads
 * - Circular references
 * - Sensitive data leaks
 */

interface ValidationConfig {
    /** Max event name length (default: 100) */
    maxEventNameLength: number;
    /** Max attribute key length (default: 100) */
    maxAttributeKeyLength: number;
    /** Max attribute value length for strings (default: 1000) */
    maxAttributeValueLength: number;
    /** Max total attributes per event (default: 50) */
    maxAttributeCount: number;
    /** Max nesting depth for objects (default: 3) */
    maxNestingDepth: number;
    /** Sensitive field patterns to redact */
    sensitivePatterns: RegExp[];
}

/**
 * Events configuration types for trace context, correlation IDs, and enrichment
 *
 * @example Basic usage
 * ```typescript
 * import { init } from 'autotel';
 *
 * init({
 *   service: 'my-app',
 *   events: {
 *     includeTraceContext: true,
 *     traceUrl: (ctx) => `https://grafana.internal/explore?traceId=${ctx.traceId}`
 *   }
 * });
 * ```
 */
/**
 * Context passed to the traceUrl function for generating clickable trace URLs
 */
interface TraceUrlContext {
    /** Trace ID (32 hex chars) - may be undefined outside a trace */
    traceId?: string;
    /** Span ID (16 hex chars) - may be undefined outside a trace */
    spanId?: string;
    /** Correlation ID (always present, 16 hex chars) */
    correlationId: string;
    /** Service name from init config */
    serviceName: string;
    /** Environment from init config */
    environment?: string;
}
/**
 * Per-key transform options for baggage enrichment
 */
type BaggageTransform = 'plain' | 'hash' | ((value: string) => string);
/**
 * Baggage enrichment configuration with guardrails
 */
interface EnrichFromBaggageConfig {
    /**
     * Allowlist of baggage keys to include in events
     * Supports exact matches and patterns (e.g., 'tenant.*')
     */
    allow: string[];
    /**
     * Optional denylist of baggage keys to exclude
     * Takes precedence over allow list
     */
    deny?: string[];
    /**
     * Optional prefix to add to all enriched keys
     * @example 'ctx.' results in 'ctx.tenant.id'
     */
    prefix?: string;
    /**
     * Maximum number of keys to include (default: 10)
     * Prevents payload bloat from excessive baggage
     */
    maxKeys?: number;
    /**
     * Maximum total bytes for enriched values (default: 1024)
     * Prevents payload bloat from large baggage values
     */
    maxBytes?: number;
    /**
     * Per-key transform options
     * - 'plain': Include value as-is
     * - 'hash': Hash the value (for PII protection)
     * - function: Custom transform function
     *
     * @example
     * ```typescript
     * transform: {
     *   'user.id': 'hash',      // Hash user ID for privacy
     *   'tenant.id': 'plain',   // Include tenant ID as-is
     *   'session.id': (v) => v.slice(0, 8) // Custom truncation
     * }
     * ```
     */
    transform?: Record<string, BaggageTransform>;
}
/**
 * Events configuration for trace context and enrichment
 */
interface EventsConfig {
    /**
     * Include trace context in events (default: false)
     *
     * When enabled, events automatically include:
     * - autotel.trace_id (32 hex chars)
     * - autotel.span_id (16 hex chars)
     * - autotel.trace_flags (2 hex chars)
     * - autotel.trace_state (raw tracestate string, if present)
     * - autotel.correlation_id (always present, 16 hex chars)
     *
     * Subscribers map these to platform-specific names:
     * - PostHog: $trace_id, $span_id
     * - Mixpanel: trace_id, span_id
     */
    includeTraceContext?: boolean;
    /**
     * Include full array of linked trace IDs for batch/fan-in scenarios (default: false)
     *
     * When false (default), batch/fan-in events include:
     * - autotel.linked_trace_id_count: Number of linked parents
     * - autotel.linked_trace_id_hash: Stable hash of sorted IDs (keeps payload lean)
     *
     * When true, events also include:
     * - autotel.linked_trace_ids: Full array of linked trace IDs
     */
    includeLinkedTraceIds?: boolean;
    /**
     * Generate clickable trace URL from context
     *
     * @param ctx - Trace context with traceId, spanId, correlationId, serviceName, environment
     * @returns URL string or undefined to skip
     *
     * @example Grafana Tempo
     * ```typescript
     * traceUrl: (ctx) => ctx.traceId
     *   ? `https://grafana.internal/explore?traceId=${ctx.traceId}`
     *   : undefined
     * ```
     *
     * @example Datadog
     * ```typescript
     * traceUrl: (ctx) => ctx.traceId
     *   ? `https://app.datadoghq.com/apm/traces?traceId=${ctx.traceId}`
     *   : undefined
     * ```
     *
     * @example Jaeger
     * ```typescript
     * traceUrl: (ctx) => ctx.traceId
     *   ? `https://jaeger.internal/trace/${ctx.traceId}`
     *   : undefined
     * ```
     */
    traceUrl?: (ctx: TraceUrlContext) => string | undefined;
    /**
     * Auto-enrich events from baggage with guardrails
     *
     * Automatically includes baggage entries in events without manual code.
     * Apply allow/deny lists and per-key transforms for PII protection.
     *
     * @example Basic allowlist
     * ```typescript
     * enrichFromBaggage: {
     *   allow: ['tenant.id', 'user.id', 'request.id']
     * }
     * // Events include: tenant.id, user.id, request.id from baggage
     * ```
     *
     * @example With prefix and transforms
     * ```typescript
     * enrichFromBaggage: {
     *   allow: ['tenant.id', 'user.id', 'user.email'],
     *   deny: ['user.ssn'],
     *   prefix: 'ctx.',
     *   transform: {
     *     'user.id': 'hash',
     *     'user.email': 'hash'
     *   }
     * }
     * // Events include: ctx.tenant.id, ctx.user.id (hashed), ctx.user.email (hashed)
     * ```
     */
    enrichFromBaggage?: EnrichFromBaggageConfig;
}

interface AutotelDevtoolsConfig {
    enabled?: boolean;
    endpoint?: string;
    embedded?: boolean;
    host?: string;
    port?: number;
    verbose?: boolean;
}

interface AutotelConfig {
    /** Service name (required) */
    service: string;
    /**
     * Local developer UX for autotel-devtools.
     *
     * - `true`: send traces, metrics, and logs to `http://127.0.0.1:4318`
     * - `{ embedded: true }`: attempt to start `autotel-devtools` automatically
     *
     * When enabled:
     * - `endpoint` defaults to the local devtools URL
     * - `logs` default to `true` unless explicitly set
     *
     * This keeps production config unchanged while making local debugging
     * effectively zero-config.
     */
    devtools?: boolean | AutotelDevtoolsConfig;
    /** Event subscribers - bring your own (PostHog, Mixpanel, etc.) */
    subscribers?: EventSubscriber[];
    /**
     * Additional OpenTelemetry instrumentations to register (raw OTel classes).
     * Useful when you need custom instrumentation configs or instrumentations
     * not covered by autoInstrumentations.
     *
     * **Important:** If you need custom instrumentation configs (like `requireParentSpan: false`),
     * use EITHER manual instrumentations OR autoInstrumentations, not both for the same library.
     * Manual instrumentations always take precedence over auto-instrumentations.
     *
     * @example Manual instrumentations with custom config
     * ```typescript
     * import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'
     *
     * init({
     *   service: 'my-app',
     *   autoInstrumentations: false,  // Disable auto-instrumentations
     *   instrumentations: [
     *     new MongoDBInstrumentation({
     *       requireParentSpan: false  // Custom config
     *     })
     *   ]
     * })
     * ```
     *
     * @example Mix auto + manual (auto for most, manual for specific configs)
     * ```typescript
     * import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'
     *
     * init({
     *   service: 'my-app',
     *   autoInstrumentations: ['http', 'express'],  // Auto for these
     *   instrumentations: [
     *     new MongoDBInstrumentation({
     *       requireParentSpan: false  // Manual config for MongoDB
     *     })
     *   ]
     * })
     * ```
     */
    instrumentations?: NodeSDKConfiguration['instrumentations'];
    /**
     * Simple names for auto-instrumentation.
     * Uses @opentelemetry/auto-instrumentations-node (peer dependency).
     *
     * **Important:** If you provide manual instrumentations for the same library,
     * the manual config takes precedence and auto-instrumentation for that library is disabled.
     *
     * @example Enable all auto-instrumentations (simple approach)
     * ```typescript
     * init({
     *   service: 'my-app',
     *   autoInstrumentations: true  // Enable all with defaults
     * })
     * ```
     *
     * @example Enable specific auto-instrumentations
     * ```typescript
     * init({
     *   service: 'my-app',
     *   autoInstrumentations: ['express', 'pino', 'http']
     * })
     * ```
     *
     * @example Configure specific auto-instrumentations
     * ```typescript
     * init({
     *   service: 'my-app',
     *   autoInstrumentations: {
     *     express: { enabled: true },
     *     pino: { enabled: true },
     *     http: { enabled: false }
     *   }
     * })
     * ```
     *
     * @example Manual config when you need custom settings
     * ```typescript
     * import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb'
     *
     * init({
     *   service: 'my-app',
     *   autoInstrumentations: false,  // Use manual control
     *   instrumentations: [
     *     new MongoDBInstrumentation({
     *       requireParentSpan: false  // Custom config not available with auto
     *     })
     *   ]
     * })
     * ```
     */
    autoInstrumentations?: string[] | boolean | Record<string, {
        enabled?: boolean;
    }>;
    /**
     * OTLP endpoint for traces/metrics/logs
     * Only used if you don't provide custom exporters/processors
     * @default process.env.OTLP_ENDPOINT || 'http://localhost:4318'
     */
    endpoint?: string;
    /**
     * Custom span processors for traces (supports multiple processors)
     * Allows you to use any backend: Jaeger, Zipkin, Datadog, New Relic, etc.
     * If not provided, defaults to OTLP with tail sampling
     *
     * @example Multiple processors
     * ```typescript
     * import { JaegerExporter } from '@opentelemetry/exporter-jaeger'
     * import { BatchSpanProcessor, SimpleSpanProcessor, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base'
     *
     * init({
     *   service: 'my-app',
     *   spanProcessors: [
     *     new BatchSpanProcessor(new JaegerExporter()),
     *     new SimpleSpanProcessor(new ConsoleSpanExporter())  // Debug alongside production
     *   ]
     * })
     * ```
     *
     * @example Single processor
     * ```typescript
     * import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
     *
     * init({
     *   service: 'my-app',
     *   spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())]
     * })
     * ```
     */
    spanProcessors?: SpanProcessor[];
    /**
     * Custom span exporters for traces (alternative to spanProcessors, supports multiple exporters)
     * Provide either spanProcessors OR spanExporters, not both
     * Each exporter will be wrapped in TailSamplingSpanProcessor + BatchSpanProcessor
     *
     * @example Multiple exporters
     * ```typescript
     * import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'
     * import { JaegerExporter } from '@opentelemetry/exporter-jaeger'
     *
     * init({
     *   service: 'my-app',
     *   spanExporters: [
     *     new ZipkinExporter({ url: 'http://localhost:9411/api/v2/spans' }),
     *     new JaegerExporter()  // Send to multiple backends simultaneously
     *   ]
     * })
     * ```
     *
     * @example Single exporter
     * ```typescript
     * import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'
     *
     * init({
     *   service: 'my-app',
     *   spanExporters: [new ZipkinExporter({ url: 'http://localhost:9411/api/v2/spans' })]
     * })
     * ```
     */
    spanExporters?: SpanExporter[];
    /**
     * Custom metric readers (supports multiple readers)
     * Allows sending metrics to multiple backends: OTLP, Prometheus, custom readers
     * Defaults to OTLP metrics exporter when metrics are enabled.
     *
     * @example Multiple metric readers
     * ```typescript
     * import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
     * import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
     * import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'
     *
     * init({
     *   service: 'my-app',
     *   metricReaders: [
     *     new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter() }),
     *     new PrometheusExporter()  // Export to multiple backends
     *   ]
     * })
     * ```
     */
    metricReaders?: MetricReader[];
    /**
     * Custom log record processors. When omitted, logs are not configured.
     */
    logRecordProcessors?: LogRecordProcessor[];
    /**
     * PostHog integration - auto-configures OTLP log exporter.
     *
     * @example
     * ```typescript
     * init({
     *   service: 'my-app',
     *   posthog: { url: 'https://us.i.posthog.com/i/v1/logs?token=phc_xxx' }
     * });
     * ```
     *
     * Also reads from POSTHOG_LOGS_URL environment variable as fallback.
     */
    posthog?: {
        url: string;
    };
    /** Additional resource attributes to merge with defaults. */
    resourceAttributes?: Attributes;
    /** Provide a fully custom Resource to merge (advanced use case). */
    resource?: Resource;
    /**
     * Headers for OTLP exporters. Accepts either an object map or
     * a "key=value" comma separated string.
     *
     * @example
     * ```typescript
     * init({
     *   service: 'my-app',
     *   endpoint: 'https://api.honeycomb.io',
     *   headers: { 'x-honeycomb-team': 'YOUR_API_KEY' }
     * })
     * ```
     */
    headers?: Record<string, string> | string;
    /**
     * OTLP protocol to use for traces, metrics, and logs
     * - 'http': HTTP/protobuf (default, uses port 4318)
     * - 'grpc': gRPC (uses port 4317)
     *
     * Can be overridden with OTEL_EXPORTER_OTLP_PROTOCOL env var.
     *
     * Note: gRPC exporters are optional peer dependencies. Install them with:
     * ```bash
     * pnpm add @opentelemetry/exporter-trace-otlp-grpc @opentelemetry/exporter-metrics-otlp-grpc
     * ```
     *
     * @example HTTP (default)
     * ```typescript
     * init({
     *   service: 'my-app',
     *   protocol: 'http',  // or omit (defaults to http)
     *   endpoint: 'http://localhost:4318'
     * })
     * ```
     *
     * @example gRPC
     * ```typescript
     * init({
     *   service: 'my-app',
     *   protocol: 'grpc',
     *   endpoint: 'grpc://localhost:4317'
     * })
     * ```
     *
     * @default 'http'
     */
    protocol?: 'http' | 'grpc';
    /**
     * Optional factory to build a customised NodeSDK instance from our defaults.
     */
    sdkFactory?: (defaults: Partial<NodeSDKConfiguration>) => NodeSDK;
    /**
     * Infrastructure metrics configuration
     * - true: always enabled (default)
     * - false: always disabled
     * - 'auto': always enabled (same as true)
     *
     * Can be overridden with AUTOTEL_METRICS=on|off env var
     */
    metrics?: boolean | 'auto';
    /**
     * OTLP logs configuration
     * - true: auto-configure OTLP log exporter from endpoint
     * - false: disabled (default)
     * - 'auto': same as false (opt-in only)
     *
     * When enabled and an endpoint is configured, autotel will automatically
     * create a BatchLogRecordProcessor with an OTLPLogExporter - no manual
     * imports needed. Works alongside logRecordProcessors (additive).
     *
     * Requires @opentelemetry/sdk-logs and @opentelemetry/exporter-logs-otlp-http
     * (or -grpc) as peer dependencies.
     *
     * Can be overridden with AUTOTEL_LOGS=on|off env var.
     *
     * @example
     * ```typescript
     * init({
     *   service: 'my-app',
     *   endpoint: 'http://localhost:4318',
     *   logs: true,
     * });
     * ```
     */
    logs?: boolean | 'auto';
    /** Sampling strategy - takes precedence over `sampling` preset */
    sampler?: Sampler;
    /**
     * Sampling preset shorthand — resolves to a pre-configured sampler.
     * If both `sampler` and `sampling` are provided, `sampler` takes precedence.
     *
     * @default 'production'
     */
    sampling?: SamplingPreset;
    /** Service version (default: auto-detect from package.json or '1.0.0') */
    version?: string;
    /** Environment (default: process.env.NODE_ENV || 'development') */
    environment?: string;
    /**
     * Logger instance for internal autotel diagnostic messages
     *
     * This logger is used by autotel internally to log initialization, warnings,
     * and debug information. Any logger with info/warn/error/debug methods works.
     *
     * **For OTel instrumentation of your application logs**, use the `autoInstrumentations` option:
     * - `autoInstrumentations: ['pino']` - Injects traceId/spanId into Pino logs
     * - `autoInstrumentations: ['winston']` - Injects traceId/spanId into Winston logs
     *
     * Default: silent logger (no-op)
     *
     * @example Pino with OTel instrumentation
     * ```typescript
     * import pino from 'pino'
     * import { init } from 'autotel'
     *
     * const logger = pino({ level: 'info' })
     * init({
     *   service: 'my-app',
     *   logger,                       // For autotel's internal logs
     *   autoInstrumentations: ['pino'] // For OTel trace context in YOUR logs
     * })
     * ```
     *
     * @example Custom logger for autotel diagnostics
     * ```typescript
     * const logger = {
     *   info: (msg, extra) => console.log(msg, extra),
     *   warn: (msg, extra) => console.warn(msg, extra),
     *   error: (msg, err, extra) => console.error(msg, err, extra),
     *   debug: (msg, extra) => console.debug(msg, extra),
     * }
     * init({ service: 'my-app', logger })
     * ```
     */
    logger?: Logger;
    /**
     * Flush events queue when root spans end
     * - true: Flush on root span completion (default)
     * - false: Use batching (events flush every 10 seconds automatically)
     *
     * Only flushes on root spans to avoid excessive network calls.
     * Default is true for serverless/short-lived processes. Set to false
     * for long-running services where batching is more efficient.
     */
    flushOnRootSpanEnd?: boolean;
    /**
     * Force-flush OpenTelemetry spans on shutdown (default: false)
     *
     * When enabled, spans are force-flushed along with events on root
     * span completion. This is useful for serverless/short-lived processes where
     * spans may not export before the process ends.
     *
     * - true: Force-flush spans on root span completion (~50-200ms latency)
     * - false: Spans export via normal batch processor (default behavior)
     *
     * Only applies when flushOnRootSpanEnd is also enabled.
     *
     * Note: For edge runtimes (Cloudflare Workers, Vercel Edge), use the
     * 'autotel-edge' package instead, which handles this automatically.
     *
     * @example Serverless with force-flush
     * ```typescript
     * init({
     *   service: 'my-lambda',
     *   flushOnRootSpanEnd: true,
     *   forceFlushOnShutdown: true, // Force-flush spans
     * });
     * ```
     */
    forceFlushOnShutdown?: boolean;
    /**
     * Automatically copy baggage entries to span attributes
     *
     * When enabled, all baggage entries are automatically added as span attributes,
     * making them visible in trace UIs (Jaeger, Grafana, DataDog, etc.) without
     * manually calling ctx.setAttribute() for each entry.
     *
     * - `true`: adds baggage with 'baggage.' prefix (e.g. baggage.tenant.id)
     * - `string`: uses custom prefix (e.g. 'ctx' → ctx.tenant.id, '' → tenant.id)
     * - `false` or omit: disabled (default)
     *
     * @default false
     *
     * @example Enable with default prefix
     * ```typescript
     * init({
     *   service: 'my-app',
     *   baggage: true
     * });
     *
     * // Now baggage automatically appears as span attributes
     * await withBaggage({
     *   baggage: { 'tenant.id': 't1', 'user.id': 'u1' },
     *   fn: async () => {
     *     // Span has baggage.tenant.id and baggage.user.id attributes!
     *   }
     * });
     * ```
     *
     * @example Custom prefix
     * ```typescript
     * init({
     *   service: 'my-app',
     *   baggage: 'ctx' // Uses 'ctx.' prefix
     * });
     * // Creates attributes: ctx.tenant.id, ctx.user.id
     * ```
     *
     * @example No prefix
     * ```typescript
     * init({
     *   service: 'my-app',
     *   baggage: '' // No prefix
     * });
     * // Creates attributes: tenant.id, user.id
     * ```
     */
    baggage?: boolean | string;
    /**
     * Validation configuration for events events
     * - Override default sensitive field patterns for redaction
     * - Customize max lengths, nesting depth, etc.
     *
     * @example Disable redaction for development
     * ```typescript
     * init({
     *   service: 'my-app',
     *   validation: {
     *     sensitivePatterns: [] // Disable all redaction
     *   }
     * })
     * ```
     *
     * @example Add custom patterns
     * ```typescript
     * init({
     *   service: 'my-app',
     *   validation: {
     *     sensitivePatterns: [
     *       /password/i,
     *       /apiKey/i,
     *       /customSecret/i  // Your custom pattern
     *     ]
     *   }
     * })
     * ```
     */
    validation?: Partial<ValidationConfig>;
    /**
     * Events configuration for trace context, correlation IDs, and enrichment
     *
     * Controls how product events integrate with distributed tracing:
     * - `includeTraceContext`: Automatically include trace context in events
     * - `includeLinkedTraceIds`: Include full array of linked trace IDs (for batch/fan-in)
     * - `traceUrl`: Generate clickable trace URLs in events
     * - `enrichFromBaggage`: Auto-enrich events from baggage with guardrails
     *
     * @example Basic trace context
     * ```typescript
     * init({
     *   service: 'my-app',
     *   events: {
     *     includeTraceContext: true
     *   }
     * });
     * // Events now include autotel.trace_id, autotel.span_id, autotel.correlation_id
     * ```
     *
     * @example With clickable trace URLs
     * ```typescript
     * init({
     *   service: 'my-app',
     *   events: {
     *     includeTraceContext: true,
     *     traceUrl: (ctx) => `https://grafana.internal/explore?traceId=${ctx.traceId}`
     *   }
     * });
     * ```
     *
     * @example With baggage enrichment
     * ```typescript
     * init({
     *   service: 'my-app',
     *   events: {
     *     includeTraceContext: true,
     *     enrichFromBaggage: {
     *       allow: ['tenant.id', 'user.id'],
     *       prefix: 'ctx.',
     *       maxKeys: 10,
     *       maxBytes: 1024
     *     }
     *   }
     * });
     * ```
     */
    events?: EventsConfig;
    /**
     * Debug mode for local span inspection.
     * Enables console output to help you see spans as they're created.
     *
     * - `true`: Raw JSON output (ConsoleSpanExporter)
     * - `'pretty'`: Colorized, hierarchical output (PrettyConsoleExporter)
     * - `false`/undefined: No console output (default)
     *
     * When enabled: Outputs spans to console AND sends to backend (if endpoint/exporter configured)
     *
     * Perfect for progressive development:
     * - Start with debug: 'pretty' (no endpoint) → see traces immediately with nice formatting
     * - Add endpoint later → console + backend, verify before choosing provider
     * - Remove debug in production → backend only, clean production config
     *
     * Can be overridden with AUTOTEL_DEBUG environment variable.
     *
     * @example Pretty debug output (recommended for development)
     * ```typescript
     * init({
     *   service: 'my-app',
     *   debug: 'pretty'  // Colorized, hierarchical output
     * })
     * ```
     *
     * @example Raw JSON output (verbose)
     * ```typescript
     * init({
     *   service: 'my-app',
     *   debug: true  // Raw ConsoleSpanExporter output
     * })
     * ```
     *
     * @example Environment variable
     * ```bash
     * AUTOTEL_DEBUG=pretty node server.js
     * AUTOTEL_DEBUG=true node server.js
     * ```
     */
    debug?: boolean | 'pretty';
    /**
     * Filter predicate to drop unwanted spans before processing.
     *
     * Useful for filtering out noisy spans from specific instrumentations
     * (e.g., Next.js internal spans, health check endpoints).
     *
     * The filter runs on completed spans (onEnd), so you have access to:
     * - `span.name` - Span name
     * - `span.attributes` - All span attributes
     * - `span.instrumentationScope` - `{ name, version }` of the instrumentation
     * - `span.status` - Span status code and message
     * - `span.duration` - Span duration as `[seconds, nanoseconds]`
     *
     * Return `true` to keep the span, `false` to drop it.
     *
     * @example Filter out Next.js instrumentation spans
     * ```typescript
     * init({
     *   service: 'my-app',
     *   spanFilter: (span) => span.instrumentationScope.name !== 'next.js'
     * })
     * ```
     *
     * @example Filter out health check spans
     * ```typescript
     * init({
     *   service: 'my-app',
     *   spanFilter: (span) => !span.name.includes('/health')
     * })
     * ```
     *
     * @example Complex filtering (multiple conditions)
     * ```typescript
     * init({
     *   service: 'my-app',
     *   spanFilter: (span) => {
     *     // Drop Next.js internal spans
     *     if (span.instrumentationScope.name === 'next.js') return false;
     *     // Drop health checks
     *     if (span.name.includes('/health')) return false;
     *     // Drop very short spans (less than 1ms)
     *     const [secs, nanos] = span.duration;
     *     if (secs === 0 && nanos < 1_000_000) return false;
     *     return true;
     *   }
     * })
     * ```
     */
    spanFilter?: SpanFilterPredicate;
    /**
     * Normalize span names to reduce cardinality from dynamic path segments.
     *
     * High-cardinality span names (e.g., `/users/123/posts/456`) cause issues:
     * - Cost explosions in observability backends
     * - Cardinality limits exceeded
     * - Poor UX when searching/filtering traces
     *
     * The normalizer transforms dynamic segments into placeholders:
     * - `/users/123` → `/users/:id`
     * - `/items/550e8400-e29b-...` → `/items/:uuid`
     *
     * Provide either a custom function or use a built-in preset:
     * - `'rest-api'` - Numeric IDs, UUIDs, ObjectIds, dates, timestamps, emails
     * - `'graphql'` - GraphQL operation name normalization
     * - `'minimal'` - Only numeric IDs and UUIDs
     *
     * @example Custom normalizer function
     * ```typescript
     * init({
     *   service: 'my-app',
     *   spanNameNormalizer: (name) => {
     *     return name
     *       .replace(/\/[0-9]+/g, '/:id')
     *       .replace(/\/[a-f0-9-]{36}/gi, '/:uuid');
     *   }
     * })
     * ```
     *
     * @example Using built-in preset
     * ```typescript
     * init({
     *   service: 'my-app',
     *   spanNameNormalizer: 'rest-api'
     * })
     * ```
     *
     * @example Combining with spanFilter
     * ```typescript
     * init({
     *   service: 'my-app',
     *   spanNameNormalizer: 'rest-api',
     *   spanFilter: (span) => span.instrumentationScope.name !== 'next.js'
     * })
     * ```
     */
    spanNameNormalizer?: SpanNameNormalizerConfig;
    /**
     * Automatically redact PII and sensitive data from span attributes before export.
     * Critical for compliance (GDPR, PCI-DSS, HIPAA) and data security.
     *
     * Can be a preset name or custom configuration:
     * - `'default'`: Emails, phones, SSNs, credit cards, sensitive keys (password, secret, token)
     * - `'strict'`: Default + Bearer tokens, JWTs, API keys in values
     * - `'pci-dss'`: Payment card industry focus (credit cards, CVV, card-related keys)
     *
     * @example Use default preset
     * ```typescript
     * init({
     *   service: 'my-app',
     *   attributeRedactor: 'default'
     * })
     * ```
     *
     * @example Custom patterns
     * ```typescript
     * init({
     *   service: 'my-app',
     *   attributeRedactor: {
     *     keyPatterns: [/password/i, /secret/i],
     *     valuePatterns: [
     *       { name: 'customerId', pattern: /CUST-\d{8}/g, replacement: 'CUST-***' }
     *     ]
     *   }
     * })
     * ```
     *
     * @example Custom redactor function
     * ```typescript
     * init({
     *   service: 'my-app',
     *   attributeRedactor: {
     *     redactor: (key, value) => {
     *       if (key === 'user.email' && typeof value === 'string') {
     *         return value.replace(/@.+/, '@[REDACTED]');
     *       }
     *       return value;
     *     }
     *   }
     * })
     * ```
     */
    attributeRedactor?: AttributeRedactorConfig | AttributeRedactorPreset;
    /**
     * OpenLLMetry integration for LLM observability.
     * Requires @traceloop/node-server-sdk as an optional peer dependency.
     *
     * @example Enable OpenLLMetry with default settings
     * ```typescript
     * init({
     *   service: 'my-app',
     *   openllmetry: { enabled: true }
     * })
     * ```
     *
     * @example Enable with custom options
     * ```typescript
     * init({
     *   service: 'my-app',
     *   openllmetry: {
     *     enabled: true,
     *     options: {
     *       disableBatch: process.env.NODE_ENV !== 'production',
     *       apiKey: process.env.TRACELOOP_API_KEY
     *     }
     *   }
     * })
     * ```
     */
    openllmetry?: {
        enabled: boolean;
        options?: Record<string, unknown>;
    };
    /**
     * Canonical log lines - automatically emit spans as wide events (canonical log lines)
     *
     * When enabled, each span (or root span only) is automatically emitted as a
     * comprehensive log record with ALL span attributes. This implements the
     * "canonical log line" pattern: one comprehensive event per request with all context.
     *
     * **Benefits:**
     * - One log line per request with all context (wide event)
     * - High-cardinality, high-dimensionality data for powerful queries
     * - Automatic - no manual logging needed
     * - Queryable as structured data instead of string search
     *
     * @example Basic usage (one canonical log line per request)
     * ```typescript
     * init({
     *   service: 'checkout-api',
     *   canonicalLogLines: {
     *     enabled: true,
     *     rootSpansOnly: true, // One canonical log line per request
     *   },
     * });
     * ```
     *
     * @example With custom logger
     * ```typescript
     * import pino from 'pino';
     * const logger = pino();
     * init({
     *   service: 'my-app',
     *   logger,
     *   canonicalLogLines: {
     *     enabled: true,
     *     logger, // Use Pino for canonical log lines
     *     rootSpansOnly: true,
     *   },
     * });
     * ```
     *
     * @example Custom message format
     * ```typescript
     * init({
     *   service: 'my-app',
     *   canonicalLogLines: {
     *     enabled: true,
     *     messageFormat: (span) => {
     *       const status = span.status.code === 2 ? 'ERROR' : 'SUCCESS';
     *       return `${span.name} [${status}]`;
     *     },
     *   },
     * });
     * ```
     */
    canonicalLogLines?: {
        enabled: boolean;
        /** Logger to use for emitting canonical log lines (defaults to OTel Logs API) */
        logger?: Logger;
        /** Only emit canonical log lines for root spans (default: false) */
        rootSpansOnly?: boolean;
        /** Minimum log level for canonical log lines (default: 'info') */
        minLevel?: 'debug' | 'info' | 'warn' | 'error';
        /** Custom message format (default: uses span name) */
        messageFormat?: (span: _opentelemetry_sdk_trace_base.ReadableSpan) => string;
        /** Whether to include resource attributes (default: true) */
        includeResourceAttributes?: boolean;
        /** Predicate to decide whether to emit (runs after event is built). */
        shouldEmit?: CanonicalLogLineOptions['shouldEmit'];
        /**
         * Declarative tail sampling conditions (OR logic).
         * Ignored when `shouldEmit` is provided.
         * @example keep: [{ status: 500 }, { durationMs: 1000 }]
         */
        keep?: CanonicalLogLineOptions['keep'];
        /** Callback invoked after emit for custom fan-out. */
        drain?: CanonicalLogLineOptions['drain'];
        /** Handler for drain failures. */
        onDrainError?: CanonicalLogLineOptions['onDrainError'];
        /**
         * Pretty-print canonical log lines to console.
         * Defaults to true when NODE_ENV is 'development'.
         */
        pretty?: boolean;
    };
    /**
     * Suppress console output while keeping OTel exporters running.
     * Useful for platforms like GCP Cloud Run / AWS Lambda where stdout
     * is managed externally by the platform's log collector.
     *
     * @default false
     */
    silent?: boolean;
    /**
     * Minimum log level for internal autotel diagnostic messages.
     * Messages below this level are dropped before processing.
     *
     * @default 'info'
     */
    minLevel?: 'debug' | 'info' | 'warn' | 'error';
}
/**
 * Lock the logger to prevent further `init()` calls.
 * Use this when framework plugins set up instrumentation and you want
 * to prevent accidental re-initialization from user code.
 */
declare function lockLogger(): void;
/**
 * Check if the logger has been locked.
 */
declare function isLoggerLocked(): boolean;
/**
 * Initialize autotel - Write Once, Observe Everywhere
 *
 * Follows OpenTelemetry standards: opinionated defaults with full flexibility
 * Idempotent: multiple calls are safe, last one wins
 *
 * @example Minimal setup (OTLP default)
 * ```typescript
 * init({ service: 'my-app' })
 * ```
 *
 * @example With events (observe in PostHog, Mixpanel, etc.)
 * ```typescript
 * import { PostHogSubscriber } from 'autotel-subscribers/posthog';
 *
 * init({
 *   service: 'my-app',
 *   subscribers: [new PostHogSubscriber({ apiKey: '...' })]
 * })
 * ```
 *
 * @example Observe in Jaeger
 * ```typescript
 * import { JaegerExporter } from '@opentelemetry/exporter-jaeger'
 *
 * init({
 *   service: 'my-app',
 *   spanExporter: new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces' })
 * })
 * ```
 *
 * @example Observe in Zipkin
 * ```typescript
 * import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'
 *
 * init({
 *   service: 'my-app',
 *   spanExporter: new ZipkinExporter({ url: 'http://localhost:9411/api/v2/spans' })
 * })
 * ```
 *
 * @example Observe in Datadog
 * ```typescript
 * import { DatadogSpanProcessor } from '@opentelemetry/exporter-datadog'
 *
 * init({
 *   service: 'my-app',
 *   spanProcessor: new DatadogSpanProcessor({ ... })
 * })
 * ```
 *
 * @example Console output (dev)
 * ```typescript
 * import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
 *
 * init({
 *   service: 'my-app',
 *   spanProcessor: new SimpleSpanProcessor(new ConsoleSpanExporter())
 * })
 * ```
 */
declare function init(cfg: AutotelConfig): void;

export { type AutotelConfig as A, isLoggerLocked as a, init as i, lockLogger as l };
