import { env } from "./env.js";
import { getLogger } from "./logger.js";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { ALLOW_ALL_BAGGAGE_KEYS, BaggageSpanProcessor } from "@opentelemetry/baggage-span-processor";
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from "@opentelemetry/core";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { resourceFromAttributes } from "@opentelemetry/resources";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { BatchSpanProcessor, NoopSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";

//#region src/instrumentation.ts
const otlpExporter = new OTLPTraceExporter();
const logger = getLogger("instrumentation");
/**
* Creates a safe batch processor that falls back to no-op when SignOz is not configured
*/
function createSafeBatchProcessor() {
	try {
		return new BatchSpanProcessor(otlpExporter, {
			scheduledDelayMillis: env.OTEL_BSP_SCHEDULE_DELAY,
			maxExportBatchSize: env.OTEL_BSP_MAX_EXPORT_BATCH_SIZE
		});
	} catch (error) {
		logger.warn({ error }, "Failed to create batch processor");
		return new NoopSpanProcessor();
	}
}
const defaultBatchProcessor = createSafeBatchProcessor();
const defaultResource = resourceFromAttributes({ [ATTR_SERVICE_NAME]: "inkeep-agents-api" });
const defaultInstrumentations = [getNodeAutoInstrumentations({
	"@opentelemetry/instrumentation-http": {
		enabled: true,
		requestHook: (span, request) => {
			const url = request?.url ?? request?.path;
			if (!url) return;
			const u = new URL(url, "http://localhost");
			span.updateName(`${request?.method || "UNKNOWN"} ${u.pathname}`);
		}
	},
	"@opentelemetry/instrumentation-undici": { requestHook: (span) => {
		const method = span.attributes?.["http.request.method"];
		const host = span.attributes?.["server.address"];
		const path = span.attributes?.["url.path"];
		if (method && path) span.updateName(host ? `${method} ${host}${path}` : `${method} ${path}`);
	} },
	"@opentelemetry/instrumentation-fs": { enabled: false },
	"@opentelemetry/instrumentation-dns": { enabled: false },
	"@opentelemetry/instrumentation-net": { enabled: false }
})];
const defaultSpanProcessors = [new BaggageSpanProcessor(ALLOW_ALL_BAGGAGE_KEYS), defaultBatchProcessor];
const defaultContextManager = new AsyncLocalStorageContextManager();
const defaultTextMapPropagator = new CompositePropagator({ propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()] });
const defaultSDK = new NodeSDK({
	resource: defaultResource,
	contextManager: defaultContextManager,
	textMapPropagator: defaultTextMapPropagator,
	spanProcessors: defaultSpanProcessors,
	instrumentations: defaultInstrumentations
});
function startOpenTelemetrySDK() {
	try {
		defaultSDK.start();
	} catch (error) {
		const msg = error instanceof Error ? error.message : String(error);
		if ((env.ENVIRONMENT === "development" || env.NODE_ENV === "development") && (msg.includes("MetricReader") && msg.includes("can not be bound") || msg.includes("Attempted duplicate registration of API"))) {
			logger.debug({}, "OpenTelemetry SDK already started");
			return;
		}
		throw error;
	}
}
async function flushBatchProcessor() {
	try {
		await defaultBatchProcessor.forceFlush();
	} catch (error) {
		logger.warn({ error }, "Failed to flush batch processor");
	}
}

//#endregion
export { defaultBatchProcessor, defaultContextManager, defaultInstrumentations, defaultResource, defaultSDK, defaultSpanProcessors, defaultTextMapPropagator, flushBatchProcessor, startOpenTelemetrySDK };