/**
 * SyncServer singleton — shared across server/index.ts and modules.
 *
 * Participant mode: server maintains its own Automerge docs.
 * On any doc change, debounced-save to disk via doc-persistence.
 *
 * When a doc belongs to an encrypted space (meta.encrypted === true),
 * the save is encrypted at rest using the space's encryptionKeyId.
 *
 * Relay mode: for encrypted spaces, the server stores opaque blobs
 * it cannot decrypt, enabling cross-device restore.
 */

import { SyncServer } from "./local-first/sync-server";
import { saveDoc, saveDocImmediate, saveEncryptedBlob, loadEncryptedBlob } from "./local-first/doc-persistence";
import { getDocumentData } from "./community-store";
import { spaceKnowledgeIndex } from "./space-knowledge";

/**
 * Look up the encryption key ID for a doc's space.
 * DocIds are formatted as "spaceSlug:module:collection[:itemId]".
 * Returns the encryptionKeyId if the space has encryption enabled, else undefined.
 */
function getEncryptionKeyId(docId: string): string | undefined {
	const spaceSlug = docId.split(":")[0];
	if (!spaceSlug || spaceSlug === "global") return undefined;
	const data = getDocumentData(spaceSlug);
	if (data?.meta?.encrypted && data.meta.encryptionKeyId) {
		return data.meta.encryptionKeyId;
	}
	return undefined;
}

export const syncServer = new SyncServer({
	participantMode: true,
	maxDocs: 500,
	onDocChange: (docId, doc) => {
		const spaceSlug = docId.split(":")[0];
		if (spaceSlug && spaceSlug !== "global") spaceKnowledgeIndex.invalidate(spaceSlug);
		const encryptionKeyId = getEncryptionKeyId(docId);
		saveDoc(docId, doc, encryptionKeyId);
	},
	onDocEvict: (docId, doc) => {
		// Persist to disk immediately before evicting from memory (no debounce!)
		const encryptionKeyId = getEncryptionKeyId(docId);
		saveDocImmediate(docId, doc, encryptionKeyId).catch(e => {
			console.error(`[SyncInstance] Eviction save failed for ${docId}:`, e);
		});
	},
	onRelayBackup: (docId, blob) => {
		saveEncryptedBlob(docId, blob);
	},
	onRelayLoad: (docId) => {
		return loadEncryptedBlob(docId);
	},
});

/**
 * Flush all in-memory docs to disk immediately, then resolve.
 * Called on SIGTERM/SIGINT before process exit.
 */
export async function flushAndShutdown(): Promise<void> {
	console.log("[SyncInstance] Flushing all docs to disk before shutdown...");
	const start = Date.now();
	await syncServer.flushAll(async (docId, doc) => {
		const encryptionKeyId = getEncryptionKeyId(docId);
		await saveDocImmediate(docId, doc, encryptionKeyId);
	});
	console.log(`[SyncInstance] Flush complete (${Date.now() - start}ms)`);
}
