/**
 * VectorDrive Manager — Singleton wrapping the native vectordrive VectorDb.
 *
 * Loads the `vectordrive` npm package dynamically (optional dependency),
 * creates a persisted VectorDb in `.sf/vectordrive/`, and exposes status
 * and search/store operations with graceful degradation.
 */
import { mkdirSync } from "node:fs";
import { dirname } from "node:path";

const DB_DIR = ".sf/vectordrive";
const DB_PATH = `${DB_DIR}/forge.vectors`;
const DIMENSIONS = 384;
function getDbPath() {
	const home = process.env.HOME || process.env.USERPROFILE || ".";
	return `${home}/${DB_PATH}`;
}
function ensureDir(path) {
	try {
		mkdirSync(dirname(path), { recursive: true });
	} catch {
		// ignore
	}
}
/** Simple text→vector fallback when no embedding model is available. */
export function textToVector(text, dimensions = DIMENSIONS) {
	const vec = new Array(dimensions).fill(0);
	const normalized = text.toLowerCase().trim();
	for (let i = 0; i < normalized.length; i++) {
		vec[i % dimensions] += normalized.charCodeAt(i) / 65535;
	}
	const mag = Math.sqrt(vec.reduce((s, v) => s + v * v, 0));
	return mag > 0 ? vec.map((v) => v / mag) : vec;
}
export class VectordriveManager {
	static instance;
	status = null;
	initPromise = null;
	// eslint-disable-next-line @typescript-eslint/no-explicit-any
	db = null;
	// eslint-disable-next-line @typescript-eslint/no-explicit-any
	vd = null;
	static getInstance() {
		if (!VectordriveManager.instance) {
			VectordriveManager.instance = new VectordriveManager();
		}
		return VectordriveManager.instance;
	}
	async getStatus() {
		if (this.status?.initialized) return this.status;
		if (this.initPromise) return this.initPromise;
		this.initPromise = this.probe();
		return this.initPromise;
	}
	// eslint-disable-next-line @typescript-eslint/no-explicit-any
	async getDb() {
		const status = await this.getStatus();
		if (status.backend !== "vectordrive") return null;
		return this.db;
	}
	async probe() {
		const dbPath = getDbPath();
		let vectordrive = null;
		try {
			const modName = "vectordrive";
			vectordrive = await import(modName);
		} catch (err) {
			this.status = {
				backend: "none",
				version: null,
				implementation: null,
				initialized: true,
				vectorCount: 0,
				error: `vectordrive package not installed: ${err instanceof Error ? err.message : String(err)}`,
				dbPath: null,
			};
			return this.status;
		}
		try {
			this.vd = vectordrive;
			ensureDir(dbPath);
			const VectorDb = vectordrive.VectorDb || vectordrive.VectorDB;
			if (typeof VectorDb !== "function") {
				throw new Error("vectordrive package does not export VectorDb");
			}
			this.db = new VectorDb({
				dimensions: DIMENSIONS,
				storagePath: dbPath,
				distanceMetric: "cosine",
			});
			const count = await this.db.len();
			const version = vectordrive.getVersion?.() ?? null;
			const impl = vectordrive.getImplementationType?.() ?? "unknown";
			this.status = {
				backend: "vectordrive",
				version: version?.version ?? null,
				implementation: impl,
				initialized: true,
				vectorCount: count,
				error: null,
				dbPath,
			};
			return this.status;
		} catch (err) {
			this.status = {
				backend: "none",
				version: null,
				implementation: null,
				initialized: true,
				vectorCount: 0,
				error: err instanceof Error ? err.message : String(err),
				dbPath: null,
			};
			return this.status;
		}
	}
	async store(entry) {
		const db = await this.getDb();
		if (!db) return false;
		try {
			await db.insert({
				id: entry.id,
				vector: entry.vector,
				metadata: entry.metadata,
			});
			return true;
		} catch {
			return false;
		}
	}
	async search(vector, k) {
		const db = await this.getDb();
		if (!db) return [];
		try {
			const results = await db.search({ vector, k });
			return results.map((r) => ({
				id: String(r.id),
				score: Number(r.score),
				metadata: r.metadata,
			}));
		} catch {
			return [];
		}
	}
	async delete(id) {
		const db = await this.getDb();
		if (!db) return false;
		try {
			return await db.delete(id);
		} catch {
			return false;
		}
	}
	async close() {
		this.db = null;
		this.vd = null;
		this.status = null;
		this.initPromise = null;
	}
}
