/**
 * memory-bank.ts
 *
 * Lightweight memory bank utilities.
 *
 * Provides:
 *  - initMemoryBank(): create memory-bank dir and initial memories file if missing
 *  - loadMemories(): read all memories
 *  - saveMemories(data): overwrite memories file
 *  - addMemory(entry): append a memory entry and persist
 *
 * Storage format: memory-bank/memories.json
 *
 * This file is safe to add to the project even if not used right away.
 */

import { promises as fs } from "fs";
import path from "path";
import { v4 as uuidv4 } from "uuid";

export type MemoryEntry = {
    id: string;
    type?: string;
    content: any;
    tags?: string[];
    createdAt: string; // ISO
    meta?: Record<string, any>;
};

const MEM_DIR = path.join(process.cwd(), "memory-bank");
const MEM_FILE = path.join(MEM_DIR, "memories.json");

type MemFile = {
    version: number;
    createdAt: string;
    entries: MemoryEntry[];
};

async function exists(p: string) {
    try {
        await fs.access(p);
        return true;
    } catch {
        return false;
    }
}

/**
 * Ensure memory-bank directory and file exist.
 * If the file doesn't exist it will be created with an empty entries array.
 */
export async function initMemoryBank(): Promise<void> {
    if (!(await exists(MEM_DIR))) {
        await fs.mkdir(MEM_DIR, { recursive: true });
    }

    if (!(await exists(MEM_FILE))) {
        const initial: MemFile = {
            version: 1,
            createdAt: new Date().toISOString(),
            entries: [
                {
                    id: uuidv4(),
                    type: "system",
                    content: { message: "memory bank initialized" },
                    tags: ["init"],
                    createdAt: new Date().toISOString(),
                    meta: {},
                },
            ],
        };
        await fs.writeFile(MEM_FILE, JSON.stringify(initial, null, 2), "utf-8");
    }
}

/**
 * Load memories.json and return the entries array.
 * If the file is missing, initMemoryBank() will be called automatically.
 */
export async function loadMemories(): Promise<MemoryEntry[]> {
    if (!(await exists(MEM_FILE))) {
        await initMemoryBank();
    }
    const raw = await fs.readFile(MEM_FILE, "utf-8");
    const data: MemFile = JSON.parse(raw);
    return data.entries || [];
}

/**
 * Overwrite the memories file with the provided entries array.
 */
export async function saveMemories(entries: MemoryEntry[]): Promise<void> {
    const payload: MemFile = {
        version: 1,
        createdAt: new Date().toISOString(),
        entries,
    };
    await fs.writeFile(MEM_FILE, JSON.stringify(payload, null, 2), "utf-8");
}

/**
 * Create and persist a new memory entry.
 * Returns the created MemoryEntry.
 */
export async function addMemory({
    type,
    content,
    tags,
    meta,
}: {
    type?: string;
    content: any;
    tags?: string[];
    meta?: Record<string, any>;
}): Promise<MemoryEntry> {
    const entries = await loadMemories();
    const entry: MemoryEntry = {
        id: uuidv4(),
        type,
        content,
        tags: tags || [],
        createdAt: new Date().toISOString(),
        meta: meta || {},
    };
    entries.push(entry);
    await saveMemories(entries);
    return entry;
}

/**
 * Simple query helper (in-memory filter).
 * Returns matching entries.
 */
export async function findMemories(predicate: (m: MemoryEntry) => boolean): Promise<MemoryEntry[]> {
    const entries = await loadMemories();
    return entries.filter(predicate);
}

/**
 * Example quick-run when this module is invoked directly with ts-node/node.
 * (Not executed when imported.)
 */
if (require.main === module) {
    (async () => {
        try {
            await initMemoryBank();
            const entries = await loadMemories();
            console.log("Memory bank initialized. Entries:", entries.length);
        } catch (err) {
            console.error("Failed to init memory bank:", err);
            process.exit(1);
        }
    })();
}
