import { createRequire } from 'node:module';
import { SessionLogSpanProcessor } from './sessionLogSpanProcessor.js';
import { MonitorJsonMetricExporter } from './monitorJsonMetricExporter.js';
const require = createRequire(import.meta.url);
const { version: TAKT_VERSION } = require('../../../package.json');
let activeSdk;
let startingSdk;
let stoppingSdk;
export async function initializeOtelFoundation(config, options = undefined) {
    if (!config.enabled) {
        return createNoopHandle();
    }
    const shared = await acquireSdk();
    const registrations = registerRunExporters(shared, options);
    let released = false;
    return {
        async shutdown() {
            if (released) {
                return;
            }
            released = true;
            try {
                if (shared.metricReaders.length > 0) {
                    await forceFlushMetricReaders(shared.metricReaders);
                }
            }
            finally {
                for (const unregister of registrations.splice(0).reverse()) {
                    unregister();
                }
                await releaseSdk(shared);
            }
        },
    };
}
async function acquireSdk() {
    if (stoppingSdk) {
        await stoppingSdk;
    }
    if (activeSdk) {
        activeSdk.refCount += 1;
        return activeSdk;
    }
    const shared = await getOrStartSdk();
    shared.refCount += 1;
    return shared;
}
function createNoopHandle() {
    return {
        async shutdown() { },
    };
}
async function getOrStartSdk() {
    if (activeSdk) {
        return activeSdk;
    }
    if (!startingSdk) {
        startingSdk = startSdk().then((started) => {
            const shared = { ...started, refCount: 0 };
            activeSdk = shared;
            startingSdk = undefined;
            return shared;
        }, (error) => {
            startingSdk = undefined;
            throw error;
        });
    }
    return startingSdk;
}
function registerRunExporters(shared, options) {
    const registrations = [];
    if (options?.sessionLogExporter && shared.sessionLogSpanProcessor) {
        registrations.push(shared.sessionLogSpanProcessor.register(options.sessionLogExporter));
    }
    if (options?.monitorJsonExporter && shared.monitorJsonMetricExporter) {
        registrations.push(shared.monitorJsonMetricExporter.register(options.monitorJsonExporter));
    }
    return registrations;
}
function createSpanProcessorState() {
    const sessionLogSpanProcessor = new SessionLogSpanProcessor();
    return { spanProcessors: [sessionLogSpanProcessor], sessionLogSpanProcessor };
}
async function createMetricReaders() {
    const { PeriodicExportingMetricReader } = await import('@opentelemetry/sdk-metrics');
    const monitorJsonMetricExporter = new MonitorJsonMetricExporter();
    return {
        metricReaders: [
            new PeriodicExportingMetricReader({
                exporter: monitorJsonMetricExporter,
                exportIntervalMillis: 1000,
            }),
        ],
        monitorJsonMetricExporter,
    };
}
async function startSdk() {
    const { spanProcessors, sessionLogSpanProcessor } = createSpanProcessorState();
    const { metricReaders, monitorJsonMetricExporter } = await createMetricReaders();
    const { NodeSDK, resources } = await import('@opentelemetry/sdk-node');
    const sdk = new NodeSDK({
        autoDetectResources: false,
        instrumentations: [],
        logRecordProcessors: [],
        metricReaders,
        resource: resources.resourceFromAttributes({
            'service.name': 'takt',
            'service.version': TAKT_VERSION,
        }),
        spanProcessors,
    });
    sdk.start();
    return {
        sdk,
        metricReaders,
        sessionLogSpanProcessor,
        monitorJsonMetricExporter,
    };
}
async function forceFlushMetricReaders(metricReaders) {
    await Promise.all(metricReaders.map((reader) => reader.forceFlush()));
}
async function releaseSdk(shared) {
    shared.refCount -= 1;
    if (shared.refCount > 0) {
        return;
    }
    const shutdownPromise = shared.sdk.shutdown().finally(() => {
        if (activeSdk === shared) {
            activeSdk = undefined;
        }
        if (stoppingSdk === shutdownPromise) {
            stoppingSdk = undefined;
        }
    });
    stoppingSdk = shutdownPromise;
    await shutdownPromise;
}
//# sourceMappingURL=otelFoundation.js.map