const require_rolldown_runtime = require('../../../../_virtual/rolldown_runtime.cjs');
const require_proxy = require('./api/dist/esm/proxy.cjs');
const require_logger = require('./config/dist/esm/logger.cjs');
const require_built = require('./config/dist/esm/built.cjs');
let eventsource = require("eventsource");

//#region ../@intlayer/cli/dist/esm/IntlayerEventListener.mjs
/**
* IntlayerEventListener class to listen for dictionary changes via SSE (Server-Sent Events).
*
* Usage example:
*
*   import { buildIntlayerDictionary } from './transpiler/declaration_file_to_dictionary/intlayer_dictionary';
*   import { IntlayerEventListener } from '@intlayer/api';
*
*   export const checkDictionaryChanges = async () => {
*     // Instantiate the listener
*     const eventListener = new IntlayerEventListener();
*
*     // Set up your callbacks
*     eventListener.onDictionaryChange = async (dictionary) => {
*       await buildIntlayerDictionary(dictionary);
*     };
*
*     // Initialize the listener
*     await eventListener.initialize();
*
*     // Optionally, clean up later when you’re done
*     // eventListener.cleanup();
*   };
*/
var IntlayerEventListener = class {
	appLogger = require_logger.getAppLogger(require_built.built_default);
	eventSource = null;
	reconnectAttempts = 0;
	maxReconnectAttempts = 5;
	reconnectDelay = 1e3;
	isManuallyDisconnected = false;
	reconnectTimeout = null;
	/**
	* Callback triggered when a Dictionary is ADDED.
	*/
	onDictionaryAdded;
	/**
	* Callback triggered when a Dictionary is UPDATED.
	*/
	onDictionaryChange;
	/**
	* Callback triggered when a Dictionary is DELETED.
	*/
	onDictionaryDeleted;
	/**
	* Callback triggered when connection is established or re-established.
	*/
	onConnectionOpen;
	/**
	* Callback triggered when connection encounters an error.
	*/
	onConnectionError;
	constructor(intlayerConfig = require_built.built_default) {
		this.intlayerConfig = intlayerConfig;
		this.appLogger = require_logger.getAppLogger(this.intlayerConfig);
	}
	/**
	* Initializes the EventSource connection using the given intlayerConfig
	* (or the default config if none was provided).
	*/
	async initialize() {
		this.isManuallyDisconnected = false;
		await this.connect();
	}
	/**
	* Establishes the EventSource connection with automatic reconnection support.
	*/
	async connect() {
		try {
			const backendURL = this.intlayerConfig.editor.backendURL;
			const accessToken = await require_proxy.getIntlayerAPIProxy(void 0, this.intlayerConfig).oAuth.getOAuth2AccessToken();
			if (!accessToken) throw new Error("Failed to retrieve access token");
			const API_ROUTE = `${backendURL}/api/event-listener`;
			if (this.eventSource) this.eventSource.close();
			this.eventSource = new eventsource.EventSource(API_ROUTE, { fetch: (input, init) => fetch(input, {
				...init,
				headers: {
					...init?.headers ?? {},
					Authorization: `Bearer ${accessToken.data?.accessToken}`
				}
			}) });
			this.eventSource.onopen = () => {
				this.reconnectAttempts = 0;
				this.reconnectDelay = 1e3;
				this.onConnectionOpen?.();
			};
			this.eventSource.onmessage = (event) => this.handleMessage(event);
			this.eventSource.onerror = (event) => this.handleError(event);
		} catch (_error) {
			this.appLogger("Failed to establish EventSource connection:", { level: "error" });
			this.scheduleReconnect();
		}
	}
	/**
	* Cleans up (closes) the EventSource connection.
	*/
	cleanup() {
		this.isManuallyDisconnected = true;
		if (this.reconnectTimeout) {
			clearTimeout(this.reconnectTimeout);
			this.reconnectTimeout = null;
		}
		if (this.eventSource) {
			this.eventSource.close();
			this.eventSource = null;
		}
	}
	/**
	* Schedules a reconnection attempt with exponential backoff.
	*/
	scheduleReconnect() {
		if (this.isManuallyDisconnected || this.reconnectAttempts >= this.maxReconnectAttempts) {
			if (this.reconnectAttempts >= this.maxReconnectAttempts) this.appLogger([`Max reconnection attempts (${this.maxReconnectAttempts}) reached. Giving up.`], { level: "error" });
			return;
		}
		this.reconnectAttempts++;
		const delay = this.reconnectDelay * 2 ** (this.reconnectAttempts - 1);
		this.appLogger(`Scheduling reconnection attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts} in ${delay}ms`);
		this.reconnectTimeout = setTimeout(async () => {
			if (!this.isManuallyDisconnected) await this.connect();
		}, delay);
	}
	/**
	* Handles incoming SSE messages, parses the event data,
	* and invokes the appropriate callback.
	*/
	async handleMessage(event) {
		try {
			const { data } = event;
			const dataJSON = JSON.parse(data);
			for (const dataEl of dataJSON) switch (dataEl.object) {
				case "DICTIONARY":
					switch (dataEl.status) {
						case "ADDED":
							await this.onDictionaryAdded?.(dataEl.data);
							break;
						case "UPDATED":
							await this.onDictionaryChange?.(dataEl.data);
							break;
						case "DELETED":
							await this.onDictionaryDeleted?.(dataEl.data);
							break;
						default:
							this.appLogger(["Unhandled dictionary status:", dataEl.status], { level: "error" });
							break;
					}
					break;
				default:
					this.appLogger(["Unknown object type:", dataEl.object], { level: "error" });
					break;
			}
		} catch (error) {
			this.appLogger(["Error processing dictionary update:", error], { level: "error" });
		}
	}
	/**
	* Handles any SSE errors and attempts reconnection if appropriate.
	*/
	handleError(event) {
		const errorEvent = event;
		this.appLogger(["EventSource error:", {
			type: errorEvent.type,
			message: errorEvent.message,
			code: errorEvent.code,
			readyState: this.eventSource?.readyState,
			url: this.eventSource?.url
		}], { level: "error" });
		this.onConnectionError?.(event);
		if (errorEvent.type === "error" && (errorEvent.message?.includes("terminated") || errorEvent.message?.includes("closed") || this.eventSource?.readyState === eventsource.EventSource.CLOSED) && !this.isManuallyDisconnected) {
			this.appLogger("Connection was terminated by server, attempting to reconnect...");
			this.scheduleReconnect();
		} else this.cleanup();
	}
};

//#endregion
exports.IntlayerEventListener = IntlayerEventListener;
//# sourceMappingURL=IntlayerEventListener.cjs.map