import { getLogger } from "./logger.js";
import "./index.js";
import { SpanStatusCode, trace } from "@opentelemetry/api";

//#region src/utils/tracer-factory.ts
const logger = getLogger("tracer");
const createNoOpSpan = () => ({
	setAttributes: () => ({}),
	recordException: () => ({}),
	setStatus: () => ({}),
	addEvent: () => ({}),
	end: () => {},
	isRecording: () => false,
	setAttribute: () => ({}),
	updateName: () => ({}),
	spanContext: () => ({
		traceId: "00000000000000000000000000000000",
		spanId: "0000000000000000",
		traceFlags: 0
	}),
	addLink: () => ({}),
	addLinks: () => ({})
});
const noopTracer = {
	startActiveSpan(_name, arg1, arg2, arg3) {
		const fn = typeof arg1 === "function" ? arg1 : typeof arg2 === "function" ? arg2 : arg3;
		if (!fn) throw new Error("No callback function provided");
		return fn(createNoOpSpan());
	},
	startSpan(_name, _options) {
		return createNoOpSpan();
	}
};
/**
* Unwraps nested error `.cause` chains to find the root cause error.
* Node.js `fetch()` wraps undici errors (e.g. HeadersTimeoutError) into
* a generic `TypeError: fetch failed` with the real error in `.cause`.
* This utility traverses the cause chain to surface the original error.
*/
function unwrapError(error) {
	if (!(error instanceof Error)) return new Error(String(error));
	let current = error;
	const seen = /* @__PURE__ */ new Set();
	while (current.cause instanceof Error && !seen.has(current.cause)) {
		seen.add(current);
		current = current.cause;
	}
	return current;
}
/**
* Helper function to handle span errors consistently
* Records the exception, sets error status, and optionally logs.
* Automatically unwraps `.cause` chains so spans show root cause errors
* instead of generic wrappers like "fetch failed".
*/
function setSpanWithError(span, error, logger$1, logMessage) {
	const rootCause = unwrapError(error);
	span.recordException(rootCause);
	span.setStatus({
		code: SpanStatusCode.ERROR,
		message: rootCause.message
	});
	if (logger$1 && logMessage) logger$1.error({ error: rootCause.message }, logMessage);
}
/**
* Get a tracer instance for the specified service
* Returns a no-op tracer if OpenTelemetry is not available
*/
function getTracer(serviceName, serviceVersion) {
	try {
		return trace.getTracer(serviceName, serviceVersion);
	} catch (_error) {
		logger.debug("OpenTelemetry tracer not available, using no-op tracer");
		return noopTracer;
	}
}
/**
* Force-flush all pending trace spans to the configured exporter.
*
* Uses the global TracerProvider registered by the OpenTelemetry SDK.
* This is safe to call from any package — it accesses the same provider
* that was set up in the host application's instrumentation.
*
* Use this in fire-and-forget handlers (e.g. Slack webhooks) where the
* HTTP response is sent before background work completes, so the
* per-request flush middleware runs too early to capture those spans.
*/
async function flushTraces() {
	try {
		const provider = trace.getTracerProvider();
		const delegate = typeof provider.getDelegate === "function" ? provider.getDelegate() : provider;
		if (typeof delegate.forceFlush === "function") await delegate.forceFlush();
	} catch (error) {
		logger.warn({ error }, "Failed to flush traces");
	}
}

//#endregion
export { flushTraces, getTracer, setSpanWithError, unwrapError };