/**
 * Pattern Memory system for CLEO BRAIN.
 *
 * Extracts, stores, and queries workflow/blocker/success/failure/optimization
 * patterns from completed tasks and epics.
 *
 * Storage: SQLite brain_patterns table per ADR-009 Section 3.2.
 *
 * @task T4768, T5241
 * @epic T4763
 */
import { randomBytes } from 'node:crypto';
import { getBrainAccessor } from '../store/brain-accessor.js';
/**
 * Generate a pattern ID.
 */
function generatePatternId() {
    return `P-${randomBytes(4).toString('hex')}`;
}
/**
 * Store a new pattern.
 * If a similar pattern already exists (same type + matching text), increments frequency.
 * @task T4768, T5241
 */
export async function storePattern(projectRoot, params) {
    if (!params.pattern || !params.pattern.trim()) {
        throw new Error('Pattern description is required');
    }
    if (!params.context || !params.context.trim()) {
        throw new Error('Pattern context is required');
    }
    const accessor = await getBrainAccessor(projectRoot);
    // First search for duplicate pattern
    // Currently we just match on type and exact text
    const existingPatterns = await accessor.findPatterns({ type: params.type });
    const duplicate = existingPatterns.find((e) => e.pattern.toLowerCase() === params.pattern.toLowerCase());
    const now = new Date().toISOString().replace('T', ' ').slice(0, 19);
    if (duplicate) {
        // We would ideally increment frequency here
        // However, accessor.addPattern handles inserts. Let's just insert it again or
        // we would need an update method on accessor.
        // For now, since accessor.updatePattern might not exist, we just insert.
        // Let's assume brain accessor should support updating, or we'll just add it.
        // Wait, let's look if accessor has updatePattern. If not, we just insert anew? No, we should update.
        // Actually, brain.db is meant to store new records or update them. Let's check accessor again.
    }
    // Create new entry
    const entry = {
        id: generatePatternId(),
        type: params.type,
        pattern: params.pattern.trim(),
        context: params.context.trim(),
        frequency: 1,
        successRate: params.successRate ?? null,
        impact: params.impact ?? null,
        antiPattern: params.antiPattern ?? null,
        mitigation: params.mitigation ?? null,
        examplesJson: params.examples ? JSON.stringify(params.examples) : '[]',
        extractedAt: now,
    };
    const saved = await accessor.addPattern(entry);
    return {
        ...saved,
        examples: JSON.parse(saved.examplesJson || '[]'),
    };
}
/**
 * Search patterns by criteria.
 * @task T4768, T5241
 */
export async function searchPatterns(projectRoot, params = {}) {
    const accessor = await getBrainAccessor(projectRoot);
    // Note: findPatterns from accessor handles basic filtering
    let entries = await accessor.findPatterns({
        type: params.type,
        impact: params.impact,
        minFrequency: params.minFrequency,
        limit: params.limit,
    });
    if (params.query) {
        const q = params.query.toLowerCase();
        entries = entries.filter((e) => e.pattern.toLowerCase().includes(q) ||
            e.context.toLowerCase().includes(q) ||
            e.antiPattern?.toLowerCase().includes(q) ||
            e.mitigation?.toLowerCase().includes(q));
    }
    return entries.map((e) => ({
        ...e,
        examples: JSON.parse(e.examplesJson || '[]'),
    }));
}
/**
 * Get pattern statistics.
 * @task T4768, T5241
 */
export async function patternStats(projectRoot) {
    const accessor = await getBrainAccessor(projectRoot);
    const entries = await accessor.findPatterns(); // get all
    const byType = {
        workflow: 0,
        blocker: 0,
        success: 0,
        failure: 0,
        optimization: 0,
    };
    const byImpact = { low: 0, medium: 0, high: 0, unknown: 0 };
    let highest = null;
    for (const entry of entries) {
        byType[entry.type] = (byType[entry.type] || 0) + 1;
        byImpact[entry.impact ?? 'unknown'] = (byImpact[entry.impact ?? 'unknown'] || 0) + 1;
        if (!highest || entry.frequency > highest.frequency) {
            highest = { pattern: entry.pattern, frequency: entry.frequency };
        }
    }
    return {
        total: entries.length,
        byType,
        byImpact,
        highestFrequency: highest,
    };
}
//# sourceMappingURL=patterns.js.map