import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
import { init_paths, resolveSocketPath } from "../../config/paths.js";
import { isValidIPCMessage } from "./types.js";
import { mkdir } from "fs/promises";
import { dirname } from "path";
import { Socket, createServer } from "net";
//#region src/agent/ipc/socket.ts
init_logger();
init_paths();
const log = createLogger("AgentSocket");
var AgentSocketServer = class {
	server;
	socketPath;
	connections = /* @__PURE__ */ new Map();
	messageHandler;
	constructor(config, agentId) {
		this.socketPath = resolveSocketPath(config, agentId);
	}
	/**
	* Start the socket server
	*/
	async start(handler) {
		this.messageHandler = handler;
		await mkdir(dirname(this.socketPath), { recursive: true });
		return new Promise((resolve, reject) => {
			this.server = createServer((socket) => {
				this.handleConnection(socket);
			});
			this.server.on("error", (err) => {
				const em = err instanceof Error ? err.message : String(err);
				log.error({
					err,
					socketPath: this.socketPath,
					errorMessage: em
				}, `Agent IPC socket server error: ${em}`);
				reject(err);
			});
			this.server.listen(this.socketPath, () => {
				log.info({ socketPath: this.socketPath }, "Socket server listening");
				resolve();
			});
		});
	}
	/**
	* Stop the socket server
	*/
	async stop() {
		for (const [id, socket] of this.connections) {
			socket.end();
			this.connections.delete(id);
		}
		return new Promise((resolve) => {
			if (!this.server) {
				resolve();
				return;
			}
			this.server.close(() => {
				log.info("Socket server stopped");
				resolve();
			});
		});
	}
	/**
	* Get connection count
	*/
	getConnectionCount() {
		return this.connections.size;
	}
	handleConnection(socket) {
		const connectionId = `${socket.remoteAddress}:${socket.remotePort}`;
		this.connections.set(connectionId, socket);
		log.debug({ connectionId }, "New socket connection");
		let buffer = "";
		socket.on("data", async (data) => {
			buffer += data.toString("utf-8");
			const lines = buffer.split("\n");
			buffer = lines.pop() || "";
			for (const line of lines) {
				if (!line.trim()) continue;
				try {
					const msg = JSON.parse(line);
					if (!isValidIPCMessage(msg)) {
						log.warn({
							linePreview: line.length > 200 ? `${line.slice(0, 200)}…` : line,
							lineLength: line.length
						}, "IPC: JSON line failed schema validation (not a valid AgentIPCMessage)");
						continue;
					}
					await this.handleMessage(msg, (response) => {
						socket.write(JSON.stringify(response) + "\n");
					});
				} catch (error) {
					const em = error instanceof Error ? error.message : String(error);
					log.warn({
						err: error,
						errorMessage: em,
						linePreview: line.length > 160 ? `${line.slice(0, 160)}…` : line
					}, `IPC: failed to parse JSON line: ${em}`);
				}
			}
		});
		socket.on("close", () => {
			this.connections.delete(connectionId);
			log.debug({ connectionId }, "Socket connection closed");
		});
		socket.on("error", (err) => {
			log.warn({
				connectionId,
				err
			}, "Socket error");
			this.connections.delete(connectionId);
		});
	}
	async handleMessage(msg, reply) {
		if (!this.messageHandler) {
			log.warn({
				socketPath: this.socketPath,
				messageType: msg.type,
				messageId: msg.id,
				from: msg.from,
				to: msg.to
			}, "IPC message dropped: no handler (server start() without handler?)");
			return;
		}
		try {
			await this.messageHandler(msg, reply);
		} catch (error) {
			const em = error instanceof Error ? error.message : String(error);
			log.error({
				err: error,
				errorMessage: em,
				messageId: msg.id,
				messageType: msg.type,
				from: msg.from,
				to: msg.to
			}, `IPC message handler threw: ${em}`);
		}
	}
};
var AgentSocketClient = class {
	socket;
	socketPath;
	pendingResponses = /* @__PURE__ */ new Map();
	constructor(config, targetAgentId) {
		this.socketPath = resolveSocketPath(config, targetAgentId);
	}
	/**
	* Connect to the socket server
	*/
	async connect() {
		return new Promise((resolve, reject) => {
			this.socket = new Socket();
			this.socket.on("connect", () => {
				log.debug({ socketPath: this.socketPath }, "Socket connected");
				this.startListening();
				resolve();
			});
			this.socket.on("error", (err) => {
				log.warn({
					socketPath: this.socketPath,
					err
				}, "Socket connection error");
				reject(err);
			});
			this.socket.connect(this.socketPath);
		});
	}
	/**
	* Disconnect from the socket server
	*/
	disconnect() {
		for (const [_id, handler] of this.pendingResponses) {
			clearTimeout(handler.timeout);
			handler.reject(/* @__PURE__ */ new Error("Socket disconnected"));
		}
		this.pendingResponses.clear();
		this.socket?.end();
		this.socket = void 0;
	}
	/**
	* Send a message and wait for response
	*/
	async sendAndWait(msg, timeoutMs = 3e4) {
		if (!this.socket) throw new Error("Socket not connected");
		return new Promise((resolve, reject) => {
			const timeout = setTimeout(() => {
				this.pendingResponses.delete(msg.id);
				reject(/* @__PURE__ */ new Error(`Timeout waiting for response to ${msg.id}`));
			}, timeoutMs);
			this.pendingResponses.set(msg.id, {
				resolve,
				reject,
				timeout
			});
			this.socket.write(JSON.stringify(msg) + "\n", (err) => {
				if (err) {
					clearTimeout(timeout);
					this.pendingResponses.delete(msg.id);
					reject(err);
				}
			});
		});
	}
	/**
	* Send a message without waiting for response
	*/
	async send(msg) {
		if (!this.socket) throw new Error("Socket not connected");
		return new Promise((resolve, reject) => {
			this.socket.write(JSON.stringify(msg) + "\n", (err) => {
				if (err) reject(err);
				else resolve();
			});
		});
	}
	/**
	* Check if socket is connected
	*/
	isConnected() {
		return this.socket?.readyState === "open";
	}
	startListening() {
		if (!this.socket) return;
		let buffer = "";
		this.socket.on("data", (data) => {
			buffer += data.toString("utf-8");
			const lines = buffer.split("\n");
			buffer = lines.pop() || "";
			for (const line of lines) {
				if (!line.trim()) continue;
				try {
					const msg = JSON.parse(line);
					if (msg.replyTo && this.pendingResponses.has(msg.replyTo)) {
						const handler = this.pendingResponses.get(msg.replyTo);
						clearTimeout(handler.timeout);
						this.pendingResponses.delete(msg.replyTo);
						handler.resolve(msg);
					}
				} catch (error) {
					log.warn({
						line,
						error
					}, "Failed to parse response");
				}
			}
		});
		this.socket.on("close", () => {
			log.debug("Socket closed");
			this.disconnect();
		});
		this.socket.on("error", (err) => {
			log.warn({ err }, "Socket error");
		});
	}
};
async function isSocketAvailable(config, agentId) {
	const socketPath = resolveSocketPath(config, agentId);
	return new Promise((resolve) => {
		const socket = new Socket();
		socket.on("connect", () => {
			socket.end();
			resolve(true);
		});
		socket.on("error", () => {
			resolve(false);
		});
		socket.connect(socketPath);
	});
}
//#endregion
export { AgentSocketClient, AgentSocketServer, isSocketAvailable };

//# sourceMappingURL=socket.js.map