/**
 * Singularity Memory (SM) Client
 *
 * Purpose: Async interface to Singularity Memory platform for cross-tool knowledge federation.
 * Provides graceful fallback to local-only memory if SM unavailable.
 *
 * Consumer: memory-store.js sync agent, memory-tools.js cross-project recall.
 *
 * Integration model (layered):
 * - SF maintains local SQLite as hot cache (working memory)
 * - SM holds durable cross-tool store (episodic memory)
 * - Async fire-and-forget sync from SF → SM
 * - Cross-project recall optional (when SM available)
 */

/**
 * Initialize SM client and test connectivity.
 * Returns { connected: boolean, version: string | null, error?: string }
 *
 * Tries to connect to SM at SINGULARITY_MEMORY_ADDR (default: http://localhost:8080).
 * SM is opt-in: set SM_ENABLED=true to activate. Disabled by default.
 */
import { getErrorMessage } from "./error-utils.js";
export async function initializeSmClient() {
	// SM is opt-in — disabled unless explicitly enabled
	if (process.env.SM_ENABLED !== "true") {
		return {
			connected: false,
			version: null,
			reason: "disabled (set SM_ENABLED=true to enable)",
		};
	}

	const addr = process.env.SINGULARITY_MEMORY_ADDR || "http://localhost:8080";

	try {
		const response = await fetch(`${addr}/v1/health`, {
			method: "GET",
			signal: AbortSignal.timeout(3000), // 3-second timeout
		});

		if (!response.ok) {
			return {
				connected: false,
				version: null,
				reason: `SM health check returned ${response.status}`,
			};
		}

		const health = await response.json();
		return {
			connected: true,
			version: health.version || "unknown",
			addr,
		};
	} catch (err) {
		return {
			connected: false,
			version: null,
			reason: `SM unreachable at ${addr}: ${getErrorMessage(err)}`,
		};
	}
}

/**
 * Sync a memory to Singularity Memory.
 * Fire-and-forget: returns immediately; actual sync happens in background.
 *
 * Memory shape:
 * {
 *   id: string (uuid)
 *   category: "gotcha" | "convention" | "architecture" | "pattern" | "environment" | "preference"
 *   content: string
 *   confidence: number [0, 1]
 *   source_unit_type?: "milestone" | "slice" | "task"
 *   source_unit_id?: string
 *   created_at: number (ms)
 *   updated_at: number (ms)
 *   hit_count: number (confidence booster)
 * }
 */
export async function syncMemoryToSm(memory, opts = {}) {
	if (!opts.smConnected) {
		// SM not available — skip sync
		return { queued: false, reason: "SM not connected" };
	}

	const addr =
		opts.smAddr ||
		process.env.SINGULARITY_MEMORY_ADDR ||
		"http://localhost:8080";

	// Queue sync in background (fire-and-forget)
	setImmediate(async () => {
		try {
			const response = await fetch(`${addr}/v1/memories`, {
				method: "POST",
				headers: {
					"Content-Type": "application/json",
				},
				body: JSON.stringify({
					memory,
					source: "sf", // Identify source as SF instance
				}),
				signal: AbortSignal.timeout(5000),
			});

			if (!response.ok) {
				console.warn(
					`[sm-client] Failed to sync memory ${memory.id}: ${response.status}`,
				);
			}
		} catch (err) {
			console.warn(
				`[sm-client] Error syncing memory ${memory.id}: ${getErrorMessage(err)}`,
			);
		}
	});

	return { queued: true };
}

/**
 * Fetch cross-project memories from Singularity Memory for a query.
 * Returns [] if SM unavailable (graceful fallback to local-only).
 */
export async function querySmMemories(query, opts = {}) {
	if (!opts.smConnected) {
		// SM not available — return empty (caller will use local memories)
		return [];
	}

	const addr =
		opts.smAddr ||
		process.env.SINGULARITY_MEMORY_ADDR ||
		"http://localhost:8080";
	const limit = opts.limit || 5; // Cross-project recall limit (smaller than local)

	try {
		const response = await fetch(`${addr}/v1/memories/query`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
			},
			body: JSON.stringify({ query, limit }),
			signal: AbortSignal.timeout(5000),
		});

		if (!response.ok) {
			return [];
		}

		const data = await response.json();
		return data.memories || [];
	} catch {
		// Network error or timeout — fail open
		return [];
	}
}

/**
 * Get SM client status for doctor checks.
 */
export function getSmStatus() {
	if (process.env.SM_ENABLED !== "true") {
		return {
			connected: false,
			reason: "disabled (set SM_ENABLED=true to enable)",
		};
	}

	const addr = process.env.SINGULARITY_MEMORY_ADDR || "http://localhost:8080";
	return {
		configured: true,
		addr,
		status: "unknown", // Status should be checked via initializeSmClient
	};
}

/**
 * Disable SM for testing or manual offline mode.
 */
export function disableSmClient() {
	process.env.SM_ENABLED = "false";
}

/**
 * Re-enable SM (after being disabled).
 */
export function enableSmClient() {
	delete process.env.SM_ENABLED;
}
