import { randomUUID } from 'node:crypto';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
const DEFAULT_LIMIT = 50;
/**
 * Tier 1: File-based memory backend.
 *
 * Stores entries as JSON in `.aperant/memory/entries.json`.
 * Pure Node.js — no native dependencies. Suitable for CLI users
 * who run tasks occasionally. Uses substring matching for search.
 */
export class FileMemoryBackend {
    tier = 'file';
    filePath;
    dirPath;
    /** Simple write lock to handle concurrent operations. */
    writeLock = Promise.resolve();
    constructor(baseDir) {
        this.dirPath = join(baseDir, '.aperant', 'memory');
        this.filePath = join(this.dirPath, 'entries.json');
    }
    async store(entry) {
        return this.withLock(async () => {
            const entries = await this.loadEntries();
            const id = randomUUID();
            const now = new Date().toISOString();
            const newEntry = {
                ...entry,
                id,
                createdAt: now,
                updatedAt: now,
            };
            entries.push(newEntry);
            await this.saveEntries(entries);
            return id;
        });
    }
    async retrieve(query) {
        const entries = await this.loadEntries();
        const limit = query.limit ?? DEFAULT_LIMIT;
        let filtered = entries.filter((e) => !e.deprecated);
        if (query.text) {
            const lower = query.text.toLowerCase();
            filtered = filtered.filter((e) => e.content.toLowerCase().includes(lower));
        }
        if (query.type) {
            filtered = filtered.filter((e) => e.type === query.type);
        }
        if (query.tags && query.tags.length > 0) {
            filtered = filtered.filter((e) => query.tags.some((t) => e.tags.includes(t)));
        }
        // Sort by updatedAt descending (most recent first)
        filtered.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
        return filtered.slice(0, limit);
    }
    async delete(id) {
        return this.withLock(async () => {
            const entries = await this.loadEntries();
            const updated = entries.filter((e) => e.id !== id);
            await this.saveEntries(updated);
        });
    }
    async deprecate(id) {
        return this.withLock(async () => {
            const entries = await this.loadEntries();
            const entry = entries.find((e) => e.id === id);
            if (entry) {
                entry.deprecated = true;
                entry.updatedAt = new Date().toISOString();
                await this.saveEntries(entries);
            }
        });
    }
    async close() {
        // No connections to close — file I/O is stateless
    }
    // --- Internal helpers ---
    async loadEntries() {
        try {
            const raw = await readFile(this.filePath, 'utf-8');
            return JSON.parse(raw);
        }
        catch {
            // File doesn't exist or is invalid — start fresh
            return [];
        }
    }
    async saveEntries(entries) {
        await mkdir(this.dirPath, { recursive: true });
        await writeFile(this.filePath, JSON.stringify(entries, null, 2), 'utf-8');
    }
    /**
     * Simple write lock to serialize mutations.
     * Prevents concurrent store/delete/deprecate from clobbering each other.
     */
    withLock(fn) {
        const prev = this.writeLock;
        let resolve;
        this.writeLock = new Promise((r) => {
            resolve = r;
        });
        return prev.then(async () => {
            try {
                return await fn();
            }
            finally {
                resolve();
            }
        });
    }
}
//# sourceMappingURL=file-backend.js.map