/**
 * Memory service for Studiograph
 *
 * Manages daily memory files similar to OpenClaw:
 * - memory/YYYY-MM-DD.md for each day
 * - Loads today + yesterday at session start
 * - Appends conversation context throughout the day
 *
 * Memory is scoped per user when auth is enabled.
 * In open mode (no auth), memory goes to the shared base directory.
 */
import { existsSync, mkdirSync, readFileSync, appendFileSync, writeFileSync, readdirSync, rmSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
export class MemoryService {
    memoryBaseDir;
    constructor() {
        // Memory is always private — stored in the user's home directory, never in
        // the workspace, never committed to git.
        this.memoryBaseDir = join(homedir(), '.studiograph', 'memory');
        this.ensureDir(this.memoryBaseDir);
    }
    /**
     * Get the per-user memory directory. Falls back to the shared base directory
     * in open mode (no auth) or API-key access.
     */
    getMemoryDir(userId) {
        if (userId) {
            const dir = join(this.memoryBaseDir, String(userId));
            this.ensureDir(dir);
            return dir;
        }
        return this.memoryBaseDir;
    }
    /**
     * Ensure a directory exists
     */
    ensureDir(dir) {
        if (!existsSync(dir)) {
            mkdirSync(dir, { recursive: true });
        }
    }
    /**
     * Get daily memory file path for a given date
     */
    getDailyMemoryPath(date, userId) {
        const dateStr = date.toISOString().split('T')[0]; // YYYY-MM-DD
        return join(this.getMemoryDir(userId), `${dateStr}.md`);
    }
    /**
     * Format timestamp for memory entry
     */
    formatTimestamp(date) {
        return date.toISOString().replace('T', ' ').split('.')[0] + ' UTC';
    }
    /**
     * Write entry to today's memory file
     */
    writeMemory(entry, userId) {
        const memoryPath = this.getDailyMemoryPath(entry.timestamp, userId);
        const timestamp = this.formatTimestamp(entry.timestamp);
        // Format entry as markdown
        const lines = [
            `## ${timestamp} - ${entry.type}`,
            '',
            entry.content,
            '',
        ];
        // Add metadata if present
        if (entry.metadata) {
            lines.push('**Metadata:**');
            for (const [key, value] of Object.entries(entry.metadata)) {
                lines.push(`- **${key}**: ${value}`);
            }
            lines.push('');
        }
        lines.push('---', '');
        const entryText = lines.join('\n');
        // Append to file (or create if doesn't exist)
        if (!existsSync(memoryPath)) {
            const header = `# Memory - ${entry.timestamp.toISOString().split('T')[0]}\n\n`;
            writeFileSync(memoryPath, header + entryText, 'utf-8');
        }
        else {
            appendFileSync(memoryPath, entryText, 'utf-8');
        }
    }
    /**
     * Read memory for a specific date
     */
    readMemory(date, userId) {
        const memoryPath = this.getDailyMemoryPath(date, userId);
        if (!existsSync(memoryPath)) {
            return null;
        }
        return readFileSync(memoryPath, 'utf-8');
    }
    /**
     * Read today's memory
     */
    readToday(userId) {
        return this.readMemory(new Date(), userId);
    }
    /**
     * Read yesterday's memory
     */
    readYesterday(userId) {
        const yesterday = new Date();
        yesterday.setDate(yesterday.getDate() - 1);
        return this.readMemory(yesterday, userId);
    }
    /**
     * Load recent memory (today + yesterday)
     */
    loadRecentMemory(userId) {
        const parts = [];
        const yesterday = this.readYesterday(userId);
        if (yesterday) {
            parts.push('# Yesterday\n', yesterday, '\n');
        }
        const today = this.readToday(userId);
        if (today) {
            parts.push('# Today\n', today, '\n');
        }
        if (parts.length === 0) {
            return '# No recent memory\n\nNo memory entries from today or yesterday.';
        }
        return parts.join('\n');
    }
    /**
     * List all memory files
     */
    listMemoryFiles(userId) {
        const dir = this.getMemoryDir(userId);
        if (!existsSync(dir)) {
            return [];
        }
        return readdirSync(dir)
            .filter(file => file.endsWith('.md'))
            .sort()
            .reverse(); // Most recent first
    }
    /**
     * Search memory files for a keyword
     */
    searchMemory(keyword, limit = 10, userId) {
        const dir = this.getMemoryDir(userId);
        const files = this.listMemoryFiles(userId).slice(0, limit);
        const results = [];
        for (const file of files) {
            const filePath = join(dir, file);
            const content = readFileSync(filePath, 'utf-8');
            if (content.toLowerCase().includes(keyword.toLowerCase())) {
                // Extract snippet around keyword
                const lines = content.split('\n');
                const matchingLines = lines.filter(line => line.toLowerCase().includes(keyword.toLowerCase()));
                if (matchingLines.length > 0) {
                    results.push({
                        date: file.replace('.md', ''),
                        snippet: matchingLines.slice(0, 3).join('\n'),
                    });
                }
            }
        }
        return results;
    }
    /**
     * Save session summary to memory
     */
    saveSessionSummary(summary, metadata, userId) {
        this.writeMemory({
            timestamp: new Date(),
            type: 'conversation',
            content: summary,
            metadata,
        }, userId);
    }
    /**
     * Save a note to memory
     */
    saveNote(note, metadata, userId) {
        this.writeMemory({
            timestamp: new Date(),
            type: 'note',
            content: note,
            metadata,
        }, userId);
    }
    /**
     * Clear all memory files
     */
    clear(userId) {
        const files = this.listMemoryFiles(userId);
        const dir = this.getMemoryDir(userId);
        if (files.length === 0)
            return 0;
        for (const file of files) {
            rmSync(join(dir, file));
        }
        return files.length;
    }
    /**
     * Save a decision to memory
     */
    saveDecision(decision, metadata, userId) {
        this.writeMemory({
            timestamp: new Date(),
            type: 'decision',
            content: decision,
            metadata,
        }, userId);
    }
}
//# sourceMappingURL=memory-service.js.map