// storage/vector-store/json-fallback.ts — JSON-based fallback storage backend.
// SPEC-075 AC-04: Same interface as SQLite adapter, uses JSON files.
import { readJson, writeJson, projectDataDir } from '../base-store.js';
import { cosineSimilarity } from '../../engine/vector-store/similarity.js';
let warnedOnce = false;
/**
 * JSON fallback storage backend.
 * Used when better-sqlite3 is not available.
 */
export class JsonFallbackBackend {
    filePath;
    cache = null;
    constructor(projectId) {
        this.filePath = `${projectDataDir(projectId)}/vector-store.json`;
        if (!warnedOnce) {
            console.warn('[Planu] SQLite not available, using JSON fallback. ' +
                'Install better-sqlite3 for better performance.');
            warnedOnce = true;
        }
    }
    async load() {
        if (this.cache) {
            return this.cache;
        }
        this.cache = await readJson(this.filePath, { entries: [] });
        return this.cache;
    }
    async save(data) {
        this.cache = data;
        await writeJson(this.filePath, data);
    }
    async insert(entry) {
        const data = await this.load();
        data.entries.push(entry);
        await this.save(data);
    }
    async update(id, partial) {
        const data = await this.load();
        const idx = data.entries.findIndex((e) => e.id === id);
        if (idx === -1) {
            return;
        }
        const existing = data.entries[idx];
        /* v8 ignore start -- defensive: idx found via findIndex so entry always exists */
        if (existing) {
            /* v8 ignore stop */
            data.entries[idx] = { ...existing, ...partial, id: existing.id };
        }
        await this.save(data);
    }
    async delete(id) {
        const data = await this.load();
        data.entries = data.entries.filter((e) => e.id !== id);
        await this.save(data);
    }
    async getById(id) {
        const data = await this.load();
        return data.entries.find((e) => e.id === id);
    }
    async getAll(type) {
        const data = await this.load();
        if (!type) {
            return [...data.entries];
        }
        return data.entries.filter((e) => e.type === type);
    }
    async searchSimilar(embedding, topK, threshold, type) {
        const data = await this.load();
        const filtered = type ? data.entries.filter((e) => e.type === type) : data.entries;
        const results = [];
        for (const entry of filtered) {
            const similarity = cosineSimilarity(embedding, entry.embedding);
            if (similarity >= threshold) {
                results.push({ entry, similarity });
            }
        }
        results.sort((a, b) => b.similarity - a.similarity);
        return results.slice(0, topK);
    }
}
/** Reset the warning flag (for testing). */
export function resetJsonFallbackWarning() {
    warnedOnce = false;
}
//# sourceMappingURL=json-fallback.js.map