"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NatsEventAdapter = void 0;
const crypto_1 = require("crypto");
const nats_1 = require("nats");
const config_1 = require("../../modules/config");
const logger_1 = require("../logger");
const sc = (0, nats_1.StringCodec)();
/**
 * NATS event adapter — publish AND subscribe.
 *
 * Publishes LTEvent payloads as JSON to NATS subjects
 * following the pattern: `{subjectPrefix}.{event.type}`
 *
 * When a CallbackEventAdapter is bridged via `setCallbackBridge()`,
 * this adapter also subscribes to `{subjectPrefix}.>` and forwards
 * events from other containers to the local callback adapter.
 * An `_originId` field prevents the publishing container from
 * re-dispatching its own events.
 *
 * Usage:
 * ```typescript
 * import { eventRegistry, NatsEventAdapter } from '@hotmeshio/long-tail';
 *
 * eventRegistry.register(new NatsEventAdapter());
 * await eventRegistry.connect();
 * ```
 */
class NatsEventAdapter {
    constructor(options) {
        this.nc = null;
        this.sub = null;
        this.originId = (0, crypto_1.randomUUID)();
        this.callbackAdapter = null;
        this.url = options?.url || config_1.config.NATS_URL;
        this.subjectPrefix = options?.subjectPrefix || 'lt.events';
        this.token = options?.token || process.env.NATS_TOKEN || 'dev_api_secret';
    }
    /**
     * Bridge NATS → local callback adapter for cross-container dispatch.
     * Part of the LTEventAdapter contract. Call before `connect()`.
     */
    setCallbackBridge(adapter) {
        this.callbackAdapter = adapter;
    }
    async connect() {
        this.nc = await (0, nats_1.connect)({
            servers: this.url,
            token: this.token,
        });
        logger_1.loggerRegistry.info(`[lt-events:nats] connected to ${this.url}`);
        // Subscribe to all events for cross-container bridging
        if (this.callbackAdapter) {
            const adapter = this.callbackAdapter;
            this.sub = this.nc.subscribe(`${this.subjectPrefix}.>`);
            logger_1.loggerRegistry.info(`[lt-events:nats] subscribed to ${this.subjectPrefix}.> for cross-container bridge`);
            (async () => {
                for await (const msg of this.sub) {
                    try {
                        const event = JSON.parse(sc.decode(msg.data));
                        // Skip events that originated from this container
                        if (event._originId === this.originId)
                            continue;
                        logger_1.loggerRegistry.info(`[lt-events:nats] bridge received: ${event.type} from ${event._originId?.slice(0, 8)}`);
                        adapter.publish(event);
                    }
                    catch {
                        // Malformed message — skip
                    }
                }
            })();
        }
    }
    async publish(event) {
        if (!this.nc)
            return;
        const subject = `${this.subjectPrefix}.${event.type}`;
        const enriched = { ...event, _originId: this.originId };
        this.nc.publish(subject, sc.encode(JSON.stringify(enriched)));
        logger_1.loggerRegistry.info(`[lt-events:nats] published: ${subject} (origin=${this.originId.slice(0, 8)})`);
    }
    async disconnect() {
        if (this.sub) {
            this.sub.unsubscribe();
            this.sub = null;
        }
        if (this.nc) {
            await this.nc.drain();
            this.nc = null;
            logger_1.loggerRegistry.info('[lt-events:nats] disconnected');
        }
    }
}
exports.NatsEventAdapter = NatsEventAdapter;
