import { createRequire } from "node:module";
import fs, { existsSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { createHash } from "node:crypto";

//#region ../shad-core/src/engine-runtime.ts
async function instantiateMemoryEngineRuntime(params) {
	if (params.primaryBackend && params.createPrimary) try {
		const primary = await params.createPrimary();
		if (primary) return {
			backend: params.primaryBackend,
			manager: new FallbackMemoryManager({
				primary,
				fallbackFactory: params.createFallback
			}, params.onPrimaryClose)
		};
	} catch (err) {
		const message = err instanceof Error ? err.message : String(err);
		params.onPrimaryCreateError?.(message);
	}
	return {
		backend: "builtin",
		manager: await params.createFallback()
	};
}
var FallbackMemoryManager = class {
	constructor(deps, onClose) {
		this.deps = deps;
		this.onClose = onClose;
		this.fallback = null;
		this.primaryFailed = false;
	}
	async search(query, opts) {
		if (!this.primaryFailed) try {
			return await this.deps.primary.search(query, opts);
		} catch (err) {
			this.primaryFailed = true;
			this.lastError = err instanceof Error ? err.message : String(err);
			warn(`qmd memory failed; switching to builtin index: ${this.lastError}`);
			await this.deps.primary.close?.().catch(() => {});
		}
		const fallback = await this.ensureFallback();
		if (fallback) return await fallback.search(query, opts);
		throw new Error(this.lastError ?? "memory search unavailable");
	}
	async readFile(params) {
		if (!this.primaryFailed) return await this.deps.primary.readFile(params);
		const fallback = await this.ensureFallback();
		if (fallback) return await fallback.readFile(params);
		throw new Error(this.lastError ?? "memory read unavailable");
	}
	status() {
		if (!this.primaryFailed) return this.deps.primary.status();
		const fallbackStatus = this.fallback?.status();
		const fallbackInfo = {
			from: "qmd",
			reason: this.lastError ?? "unknown"
		};
		if (fallbackStatus) {
			const custom = fallbackStatus.custom ?? {};
			return {
				...fallbackStatus,
				fallback: fallbackInfo,
				custom: {
					...custom,
					fallback: {
						disabled: true,
						reason: this.lastError ?? "unknown"
					}
				}
			};
		}
		const primaryStatus = this.deps.primary.status();
		const custom = primaryStatus.custom ?? {};
		return {
			...primaryStatus,
			fallback: fallbackInfo,
			custom: {
				...custom,
				fallback: {
					disabled: true,
					reason: this.lastError ?? "unknown"
				}
			}
		};
	}
	async sync(params) {
		if (!this.primaryFailed) {
			await this.deps.primary.sync?.(params);
			return;
		}
		await (await this.ensureFallback())?.sync?.(params);
	}
	async probeEmbeddingAvailability() {
		if (!this.primaryFailed) return await this.deps.primary.probeEmbeddingAvailability();
		const fallback = await this.ensureFallback();
		if (fallback) return await fallback.probeEmbeddingAvailability();
		return {
			ok: false,
			error: this.lastError ?? "memory embeddings unavailable"
		};
	}
	async probeVectorAvailability() {
		if (!this.primaryFailed) return await this.deps.primary.probeVectorAvailability();
		return await (await this.ensureFallback())?.probeVectorAvailability() ?? false;
	}
	trackNewTokens(count) {
		this.deps.primary.trackNewTokens?.(count);
	}
	async flushIndex(reason) {
		await this.deps.primary.flushIndex?.(reason);
	}
	async close() {
		await this.deps.primary.close?.();
		await this.fallback?.close?.();
		this.onClose?.();
	}
	async ensureFallback() {
		if (this.fallback) return this.fallback;
		const fallback = await this.deps.fallbackFactory();
		if (!fallback) {
			warn("memory fallback requested but builtin index is unavailable");
			return null;
		}
		this.fallback = fallback;
		return this.fallback;
	}
};
function warn(message) {
	console.warn(`[memory] ${message}`);
}

//#endregion
//#region ../shad-core/src/native-loader.ts
const SHAD_CORE_NATIVE_PATH_ENV = "EDWINPAI_SHAD_CORE_NATIVE_PATH";
const COMPANION_SCOPE = "@edwinpai";
const COMPANION_NAME_PREFIX = "shad-core";
const NATIVE_ARTIFACT_FILE = "shad-core.node";
const COMPANION_PACKAGE_SUFFIX_BY_RUNTIME_TRIPLE = {
	"darwin-arm64": "darwin-arm64",
	"darwin-x64": "darwin-x64",
	"linux-arm64": "linux-arm64-gnu",
	"linux-x64": "linux-x64-gnu",
	"win32-x64": "win32-x64-msvc"
};
/**
* Best-effort resolver for the future protected native shad-core binding.
*
* This does not pretend the current package is native: it returns `null` until
* a real `shad-core.node` artifact is supplied by env path, bundled artifact,
* staging dir, or runtime-triple companion package. The goal is to make the
* native package contract executable before moving memory internals behind it.
*/
function loadNativeShadCore(options = {}) {
	const candidate = resolveNativeShadCoreCandidatePath(options);
	if (!candidate) return null;
	const requireFn = options.requireFn ?? defaultRequire;
	try {
		const binding = requireFn(candidate);
		return isNativeShadCoreBinding(binding) ? binding : null;
	} catch {
		return null;
	}
}
function resolveNativeShadCoreCandidatePath(options = {}) {
	const envPath = options.envPath !== void 0 ? options.envPath : process.env[SHAD_CORE_NATIVE_PATH_ENV];
	if (envPath && envPath.trim().length > 0 && existsSync(envPath)) return envPath;
	const bundled = defaultBundledArtifactPath(options);
	if (bundled && existsSync(bundled)) return bundled;
	const staged = defaultStagedArtifactPath(options);
	if (staged && existsSync(staged)) return staged;
	const companion = defaultInstalledCompanionArtifactPath(options);
	if (companion && existsSync(companion)) return companion;
	return null;
}
function getShadCoreNativeRuntimeTriple(platform, arch) {
	if (platform === "darwin" && arch === "x64") return "darwin-x64";
	if (platform === "darwin" && arch === "arm64") return "darwin-arm64";
	if (platform === "linux" && arch === "x64") return "linux-x64";
	if (platform === "linux" && arch === "arm64") return "linux-arm64";
	if (platform === "win32" && arch === "x64") return "win32-x64";
	return null;
}
function getShadCoreCompanionPackageName(runtimeTriple) {
	const packageSuffix = COMPANION_PACKAGE_SUFFIX_BY_RUNTIME_TRIPLE[runtimeTriple];
	if (!packageSuffix) return null;
	return `${COMPANION_SCOPE}/${COMPANION_NAME_PREFIX}-${packageSuffix}`;
}
function defaultBundledArtifactPath(options) {
	if (options.bundledPath !== void 0) return options.bundledPath;
	const triple = getShadCoreNativeRuntimeTriple(options.platform ?? process.platform, options.arch ?? process.arch);
	if (!triple) return null;
	const here = resolveModuleDir();
	return here ? join(here, "..", "native", triple, NATIVE_ARTIFACT_FILE) : null;
}
function defaultStagedArtifactPath(options) {
	if (options.stagedPath !== void 0) return options.stagedPath;
	const triple = getShadCoreNativeRuntimeTriple(options.platform ?? process.platform, options.arch ?? process.arch);
	if (!triple) return null;
	const here = resolveModuleDir();
	return here ? join(here, "..", "native-staging", triple, NATIVE_ARTIFACT_FILE) : null;
}
function defaultInstalledCompanionArtifactPath(options) {
	if (options.companionPath && options.companionPath.trim().length > 0) return options.companionPath;
	const runtimeTriple = getShadCoreNativeRuntimeTriple(options.platform ?? process.platform, options.arch ?? process.arch);
	if (!runtimeTriple) return null;
	const packageName = options.companionPackageName ?? getShadCoreCompanionPackageName(runtimeTriple);
	if (!packageName) return null;
	const resolveFn = options.resolveFn ?? defaultResolve;
	try {
		return resolveFn(packageName);
	} catch {
		return null;
	}
}
function isNativeShadCoreBinding(value) {
	return typeof value === "object" && value !== null;
}
function resolveModuleDir() {
	try {
		return dirname(fileURLToPath(import.meta.url));
	} catch {
		return null;
	}
}
function defaultRequire(path) {
	return createRequire(import.meta.url)(path);
}
function defaultResolve(specifier) {
	return createRequire(import.meta.url).resolve(specifier);
}

//#endregion
//#region ../shad-core/src/primitives.ts
let nativeBinding;
function hashText(value) {
	const nativeHash = getNativeBinding()?.hashText?.(value)?.sha256;
	if (typeof nativeHash === "string" && nativeHash.length > 0) return nativeHash;
	return hashTextFallback(value);
}
function chunkMarkdown(content, chunking) {
	const nativeChunks = getNativeBinding()?.chunkMarkdown?.(content, chunking);
	if (Array.isArray(nativeChunks)) {
		const normalized = normalizeNativeChunks(nativeChunks);
		if (normalized) return normalized;
	}
	return chunkMarkdownFallback(content, chunking);
}
function buildFtsQuery(raw) {
	const nativeQuery = getNativeBinding()?.buildFtsQuery?.(raw);
	if (typeof nativeQuery === "string") return nativeQuery.length > 0 ? nativeQuery : null;
	if (nativeQuery === null) return null;
	return buildFtsQueryFallback(raw);
}
function bm25RankToScore(rank) {
	const nativeScore = getNativeBinding()?.bm25RankToScore?.(rank);
	if (typeof nativeScore === "number" && Number.isFinite(nativeScore)) return nativeScore;
	return bm25RankToScoreFallback(rank);
}
function cosineSimilarity(a, b) {
	const nativeScore = getNativeBinding()?.cosineSimilarity?.(a, b);
	if (typeof nativeScore === "number" && Number.isFinite(nativeScore)) return nativeScore;
	return cosineSimilarityFallback(a, b);
}
function mergeHybridResults(params) {
	const nativeMerge = getNativeBinding()?.mergeHybridResults;
	if (nativeMerge) {
		const nativeResults = nativeMerge(params.vector.map(nativeVectorResult), params.keyword.map(nativeKeywordResult), {
			vectorWeight: params.vectorWeight,
			vector_weight: params.vectorWeight,
			textWeight: params.textWeight,
			text_weight: params.textWeight
		});
		if (Array.isArray(nativeResults)) {
			const normalized = normalizeNativeHybridResults(nativeResults);
			if (normalized) return normalized;
		}
	}
	return mergeHybridResultsFallback(params);
}
function getNativeBinding() {
	if (nativeBinding !== void 0) return nativeBinding;
	nativeBinding = loadNativeShadCore();
	return nativeBinding;
}
function hashTextFallback(value) {
	return createHash("sha256").update(value).digest("hex");
}
function chunkMarkdownFallback(content, chunking) {
	const lines = content.split("\n");
	if (lines.length === 0) return [];
	const maxChars = Math.max(32, chunking.tokens * 4);
	const overlapChars = Math.max(0, chunking.overlap * 4);
	const chunks = [];
	let current = [];
	let currentChars = 0;
	const flush = () => {
		if (current.length === 0) return;
		const firstEntry = current[0];
		const lastEntry = current[current.length - 1];
		if (!firstEntry || !lastEntry) return;
		const text = current.map((entry) => entry.line).join("\n");
		chunks.push({
			startLine: firstEntry.lineNo,
			endLine: lastEntry.lineNo,
			text,
			hash: hashText(text)
		});
	};
	const carryOverlap = () => {
		if (overlapChars <= 0 || current.length === 0) {
			current = [];
			currentChars = 0;
			return;
		}
		let acc = 0;
		const kept = [];
		for (let i = current.length - 1; i >= 0; i -= 1) {
			const entry = current[i];
			if (!entry) continue;
			acc += entry.line.length + 1;
			kept.unshift(entry);
			if (acc >= overlapChars) break;
		}
		current = kept;
		currentChars = kept.reduce((sum, entry) => sum + entry.line.length + 1, 0);
	};
	for (let i = 0; i < lines.length; i += 1) {
		const line = lines[i] ?? "";
		const lineNo = i + 1;
		const segments = [];
		if (line.length === 0) segments.push("");
		else for (let start = 0; start < line.length; start += maxChars) segments.push(line.slice(start, start + maxChars));
		for (const segment of segments) {
			const lineSize = segment.length + 1;
			if (currentChars + lineSize > maxChars && current.length > 0) {
				flush();
				carryOverlap();
			}
			current.push({
				line: segment,
				lineNo
			});
			currentChars += lineSize;
		}
	}
	flush();
	return chunks;
}
function buildFtsQueryFallback(raw) {
	const tokens = raw.match(/[A-Za-z0-9_]+/g)?.map((token) => token.trim()).filter(Boolean) ?? [];
	if (tokens.length === 0) return null;
	return tokens.map((token) => `"${token.replaceAll("\"", "")}"`).join(" AND ");
}
function bm25RankToScoreFallback(rank) {
	return 1 / (1 + (Number.isFinite(rank) ? Math.max(0, rank) : 999));
}
function cosineSimilarityFallback(a, b) {
	if (a.length === 0 || b.length === 0 || a.length !== b.length) return 0;
	let dot = 0;
	let magA = 0;
	let magB = 0;
	for (let i = 0; i < a.length; i += 1) {
		const av = a[i] ?? 0;
		const bv = b[i] ?? 0;
		dot += av * bv;
		magA += av * av;
		magB += bv * bv;
	}
	if (magA === 0 || magB === 0) return 0;
	return dot / (Math.sqrt(magA) * Math.sqrt(magB));
}
function mergeHybridResultsFallback(params) {
	const byId = /* @__PURE__ */ new Map();
	for (const result of params.vector) byId.set(result.id, {
		...result,
		textScore: 0
	});
	for (const result of params.keyword) {
		const existing = byId.get(result.id);
		if (existing) {
			existing.textScore = result.textScore;
			if (result.snippet.length > 0) existing.snippet = result.snippet;
		} else byId.set(result.id, {
			...result,
			vectorScore: 0
		});
	}
	return Array.from(byId.values()).map((entry) => ({
		path: entry.path,
		startLine: entry.startLine,
		endLine: entry.endLine,
		score: params.vectorWeight * entry.vectorScore + params.textWeight * entry.textScore,
		snippet: entry.snippet,
		source: entry.source
	})).toSorted((a, b) => b.score - a.score);
}
function nativeVectorResult(result) {
	return {
		id: result.id,
		path: result.path,
		startLine: result.startLine,
		start_line: result.startLine,
		endLine: result.endLine,
		end_line: result.endLine,
		source: result.source,
		snippet: result.snippet,
		vectorScore: result.vectorScore,
		vector_score: result.vectorScore
	};
}
function nativeKeywordResult(result) {
	return {
		id: result.id,
		path: result.path,
		startLine: result.startLine,
		start_line: result.startLine,
		endLine: result.endLine,
		end_line: result.endLine,
		source: result.source,
		snippet: result.snippet,
		textScore: result.textScore,
		text_score: result.textScore
	};
}
function normalizeNativeHybridResults(results) {
	const out = [];
	for (const result of results) {
		const startLine = result.startLine ?? result.start_line;
		const endLine = result.endLine ?? result.end_line;
		if (typeof result.path !== "string" || typeof startLine !== "number" || typeof endLine !== "number" || typeof result.score !== "number" || typeof result.snippet !== "string" || typeof result.source !== "string") return null;
		out.push({
			path: result.path,
			startLine,
			endLine,
			score: result.score,
			snippet: result.snippet,
			source: result.source
		});
	}
	return out;
}
function normalizeNativeChunks(chunks) {
	const out = [];
	for (const chunk of chunks) {
		const startLine = chunk.startLine ?? chunk.start_line;
		const endLine = chunk.endLine ?? chunk.end_line;
		if (typeof startLine !== "number" || typeof endLine !== "number" || typeof chunk.text !== "string" || typeof chunk.hash !== "string") return null;
		out.push({
			startLine,
			endLine,
			text: chunk.text,
			hash: chunk.hash
		});
	}
	return out;
}

//#endregion
//#region ../../src/memory/internal.ts
function ensureDir(dir) {
	try {
		fs.mkdirSync(dir, { recursive: true });
	} catch {}
	return dir;
}
function parseEmbedding(raw) {
	try {
		const parsed = JSON.parse(raw);
		return Array.isArray(parsed) ? parsed : [];
	} catch {
		return [];
	}
}

//#endregion
export { chunkMarkdown as a, mergeHybridResults as c, buildFtsQuery as i, instantiateMemoryEngineRuntime as l, parseEmbedding as n, cosineSimilarity as o, bm25RankToScore as r, hashText as s, ensureDir as t };