import { init_loader, loadConfig } from "../config/loader.js";
import { loadUndiciRuntimeDeps } from "../infra/undici-fetch.js";
import { toConversation } from "./channel-shared.js";
import { createGatewayHttpClientFromConfig, resolveGatewayHttpBaseUrl } from "./gateway-http-client.js";
//#region src/mcp/channel-bridge.ts
init_loader();
const QUEUE_LIMIT = 1e3;
var XopcChannelBridge = class {
	client = null;
	queue = [];
	pendingApprovals = /* @__PURE__ */ new Map();
	cursor = 0;
	closed = false;
	eventsAbort = null;
	constructor(cfg, params) {
		this.cfg = cfg;
		this.params = params;
	}
	setServer(_server) {}
	async start() {
		this.client = createGatewayHttpClientFromConfig({
			config: this.cfg,
			gatewayUrl: this.params.gatewayUrl,
			gatewayToken: this.params.gatewayToken
		});
		this.connectEvents();
	}
	async close() {
		this.closed = true;
		this.eventsAbort?.abort();
		this.eventsAbort = null;
		this.queue.length = 0;
		this.pendingApprovals.clear();
	}
	connectEvents() {
		if (this.closed) return;
		this.eventsAbort?.abort();
		const abort = new AbortController();
		this.eventsAbort = abort;
		const baseUrl = resolveGatewayHttpBaseUrl(this.cfg, this.params.gatewayUrl);
		this.runEventsLoop(baseUrl, this.params.gatewayToken, abort.signal);
	}
	async runEventsLoop(baseUrl, token, signal) {
		const url = new URL(`${baseUrl}/api/events`);
		if (token?.trim()) url.searchParams.set("token", token.trim());
		try {
			const res = await loadUndiciRuntimeDeps().fetch(url.toString(), {
				headers: { Accept: "text/event-stream" },
				signal
			});
			if (!res.ok || !res.body) return;
			const reader = res.body.getReader();
			const decoder = new TextDecoder();
			let buffer = "";
			while (!this.closed && !signal.aborted) {
				const { done, value } = await reader.read();
				if (done) break;
				buffer += decoder.decode(value, { stream: true });
				let splitAt = buffer.indexOf("\n\n");
				while (splitAt >= 0) {
					this.handleSseChunk(buffer.slice(0, splitAt));
					buffer = buffer.slice(splitAt + 2);
					splitAt = buffer.indexOf("\n\n");
				}
			}
		} catch {}
		if (!this.closed && !signal.aborted) {
			await new Promise((resolve) => setTimeout(resolve, 2e3));
			if (!this.closed) this.connectEvents();
		}
	}
	handleSseChunk(chunk) {
		let eventName = "message";
		let data = "";
		for (const line of chunk.split("\n")) if (line.startsWith("event:")) eventName = line.slice(6).trim();
		else if (line.startsWith("data:")) data += line.slice(5).trim();
		if (!data) return;
		try {
			const parsed = JSON.parse(data);
			this.enqueueFromBroadcast({
				type: eventName,
				...parsed
			});
		} catch {
			this.enqueueFromBroadcast({
				type: eventName,
				raw: data
			});
		}
	}
	enqueueFromBroadcast(data) {
		const type = String(data.type ?? data.event ?? "");
		if (!type) return;
		if (type.includes("message") || type.includes("session")) this.pushEvent({
			cursor: ++this.cursor,
			type: "message",
			sessionKey: String(data.sessionKey ?? data.key ?? ""),
			raw: data
		});
	}
	pushEvent(event) {
		this.queue.push(event);
		while (this.queue.length > QUEUE_LIMIT) this.queue.shift();
	}
	async listConversations(args) {
		const client = this.client;
		const query = new URLSearchParams();
		if (args.limit) query.set("limit", String(args.limit));
		if (args.search) query.set("search", args.search);
		if (args.channel) query.set("channel", args.channel);
		const qs = query.toString();
		const rows = await client.getJson(`/api/sessions${qs ? `?${qs}` : ""}`);
		return (Array.isArray(rows) ? rows : rows.sessions ?? []).map((row) => toConversation(row)).filter((c) => c !== null);
	}
	async getConversation(sessionKey) {
		const client = this.client;
		try {
			return toConversation(await client.getJson(`/api/sessions/${encodeURIComponent(sessionKey)}`));
		} catch {
			return null;
		}
	}
	async readMessages(sessionKey, limit) {
		return (await this.client.getJson(`/api/sessions/${encodeURIComponent(sessionKey)}/messages?limit=${limit}`)).messages ?? [];
	}
	pollEvents(filter, limit) {
		const events = this.queue.filter((e) => e.cursor > filter.afterCursor).filter((e) => !filter.sessionKey || "sessionKey" in e && e.sessionKey === filter.sessionKey).slice(0, limit);
		return {
			events,
			nextCursor: events.length > 0 ? events[events.length - 1].cursor : filter.afterCursor
		};
	}
	async waitForEvent(filter, timeoutMs) {
		const deadline = Date.now() + timeoutMs;
		while (Date.now() < deadline && !this.closed) {
			const polled = this.pollEvents(filter, 1);
			if (polled.events.length > 0) return polled.events[0] ?? null;
			await new Promise((r) => setTimeout(r, 250));
		}
		return null;
	}
	async sendMessage(params) {
		return this.client.postJson("/api/agent", {
			sessionKey: params.sessionKey,
			message: params.text
		});
	}
	listPendingApprovals() {
		return Array.from(this.pendingApprovals.values());
	}
	async respondToApproval(params) {
		return this.client.postJson("/api/mcp/approvals/respond", params);
	}
	async handleClaudePermissionRequest(_params) {}
};
function loadMcpServeConfig() {
	return loadConfig();
}
//#endregion
export { XopcChannelBridge, loadMcpServeConfig };

//# sourceMappingURL=channel-bridge.js.map