/*
 * Copyright OpenSearch Contributors
 * SPDX-License-Identifier: Apache-2.0
 */
import { debug as centralDebug } from '../../../lib/debug.js';
import { trace, context as otelContext, propagation } from '@opentelemetry/api';
/**
 * Abstract base class for connectors
 * Provides common functionality like auth header building and error handling
 */
export class BaseConnector {
    /**
     * Build HTTP headers from auth configuration
     * @param auth Authentication configuration
     * @returns Headers object ready for fetch/axios
     */
    buildAuthHeaders(auth) {
        const headers = {};
        switch (auth.type) {
            case 'basic':
                if (auth.username && auth.password) {
                    const credentials = Buffer.from(`${auth.username}:${auth.password}`).toString('base64');
                    headers['Authorization'] = `Basic ${credentials}`;
                }
                break;
            case 'bearer':
                if (auth.token) {
                    headers['Authorization'] = `Bearer ${auth.token}`;
                }
                break;
            case 'api-key':
                if (auth.token) {
                    // Common API key header patterns
                    headers['X-API-Key'] = auth.token;
                    headers['x-api-key'] = auth.token; // Some APIs use lowercase
                }
                break;
            case 'aws-sigv4':
                // AWS SigV4 signing would be handled separately
                // This is a placeholder - actual implementation would use aws4 or @aws-sdk/signature-v4
                console.warn('[BaseConnector] AWS SigV4 auth requires runtime signing');
                break;
            case 'none':
            default:
                // No auth headers needed
                break;
        }
        // Always apply custom headers (can override auth headers if needed)
        if (auth.headers) {
            Object.assign(headers, auth.headers);
        }
        return headers;
    }
    /**
     * Build environment variables from auth configuration
     * Used by subprocess connectors
     */
    buildAuthEnv(auth) {
        const env = {};
        if (auth.type === 'aws-sigv4') {
            if (auth.awsRegion)
                env['AWS_REGION'] = auth.awsRegion;
            if (auth.awsAccessKeyId)
                env['AWS_ACCESS_KEY_ID'] = auth.awsAccessKeyId;
            if (auth.awsSecretAccessKey)
                env['AWS_SECRET_ACCESS_KEY'] = auth.awsSecretAccessKey;
            if (auth.awsSessionToken)
                env['AWS_SESSION_TOKEN'] = auth.awsSessionToken;
        }
        return env;
    }
    /**
     * Generate a unique ID for trajectory steps
     */
    generateId() {
        return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
    }
    /**
     * Create a trajectory step with common fields
     */
    createStep(type, content, extra) {
        return {
            id: this.generateId(),
            timestamp: Date.now(),
            type,
            content,
            ...extra,
        };
    }
    /**
     * Default health check implementation
     * Subclasses can override for protocol-specific checks
     */
    async healthCheck(endpoint, auth) {
        try {
            // Default: try a simple fetch with HEAD method
            const headers = this.buildAuthHeaders(auth);
            const response = await fetch(endpoint, {
                method: 'HEAD',
                headers,
            });
            return response.ok;
        }
        catch (error) {
            console.error(`[${this.type}] Health check failed:`, error);
            return false;
        }
    }
    /**
     * Log debug message with connector type prefix
     */
    debug(message, ...args) {
        centralDebug(this.type, message, ...args);
    }
    /**
     * Log error message with connector type prefix
     */
    error(message, ...args) {
        console.error(`[${this.type}] ${message}`, ...args);
    }
    /**
     * Build a W3C `TRACEPARENT` env var string from the active OTel span,
     * if any. Returns an env-fragment object (empty if no active span or
     * propagation is disabled for this connector).
     *
     * Used by subprocess connectors to make the child's OTel SDK adopt the
     * eval `test_case` span as parent context (Strategy A).
     */
    buildTraceparentEnv() {
        if (!this.traceContext?.propagateEnv)
            return {};
        const span = trace.getSpan(otelContext.active());
        if (!span)
            return {};
        const ctx = span.spanContext();
        if (!ctx.traceId || !ctx.spanId)
            return {};
        // Both trace-id and parent-id must be non-zero per W3C trace context spec
        // (https://www.w3.org/TR/trace-context/#trace-id). Emitting an all-zero
        // value would produce an invalid traceparent that downstream SDKs
        // typically reject silently — the agent's root span won't adopt our
        // context as parent and we'd get back to two unrelated trace trees.
        if (ctx.traceId === '0'.repeat(32) || ctx.spanId === '0'.repeat(16))
            return {};
        // 00 = W3C version; flags=01 means SAMPLED so the agent's exporter forwards.
        const flags = (ctx.traceFlags ?? 1).toString(16).padStart(2, '0');
        const env = {
            TRACEPARENT: `00-${ctx.traceId}-${ctx.spanId}-${flags}`,
        };
        if (ctx.traceState) {
            const ts = ctx.traceState.serialize();
            if (ts)
                env.TRACESTATE = ts;
        }
        return env;
    }
    /**
     * Inject W3C `traceparent` (and `tracestate`) headers into an outgoing
     * HTTP request, if a span is active and propagation is enabled.
     *
     * Used by REST/SSE connectors so the remote agent's OTel SDK adopts the
     * eval `test_case` span as parent context (Strategy A).
     */
    injectTraceparentHeaders(headers) {
        if (!this.traceContext?.propagateHeader)
            return;
        propagation.inject(otelContext.active(), headers);
    }
}
//# sourceMappingURL=BaseConnector.js.map