// tools/learn.ts — Store learned patterns for project knowledge enrichment
// Persists architecture, convention, estimation, stack, and quality patterns
// to pattern-store for future use by estimation, auditing, and spec generation.
// SPEC-011: adds dispatchFeedbackEvent for feedback loop dispatch.
import { patternStore, knowledgeStore } from '../storage/index.js';
import { t, ti } from '../i18n/index.js';
import { TFIDFEngine } from '../engine/vector-store/tfidf.js';
import { cosineSimilarity } from '../engine/vector-store/similarity.js';
/** Default cosine similarity threshold for semantic deduplication. */
const DEFAULT_DEDUP_THRESHOLD = 0.85;
export async function handleLearn(args) {
    const { projectId, type, pattern, source } = args;
    // 1. Validate project exists
    const knowledge = await knowledgeStore.getKnowledge(projectId);
    if (!knowledge) {
        return {
            content: [{ type: 'text', text: t('project.notFound') }],
            isError: true,
        };
    }
    // 2. Check for existing similar pattern to prevent duplicates
    const existingPatterns = await patternStore.listPatterns(projectId);
    const duplicate = existingPatterns.find((p) => p.type === type && p.pattern.toLowerCase() === pattern.toLowerCase());
    if (duplicate) {
        // Increment usage count instead of creating a duplicate
        const updated = await patternStore.incrementPatternUsage(projectId, duplicate.id);
        return {
            content: [
                {
                    type: 'text',
                    text: `Pattern already exists (id: ${duplicate.id}). Usage count incremented to ${updated.usageCount}.`,
                },
                {
                    type: 'text',
                    text: JSON.stringify({
                        action: 'incremented',
                        patternId: duplicate.id,
                        type: duplicate.type,
                        pattern: duplicate.pattern,
                        usageCount: updated.usageCount,
                    }, null, 2),
                },
            ],
        };
    }
    // 3. Semantic deduplication check (SPEC-075 AC-08)
    const dedupWarning = checkSemanticDuplicate(existingPatterns, pattern, type);
    // 4. Create new pattern (store even if semantically similar — just warn)
    const patternId = `PAT-${type.substring(0, 3).toUpperCase()}-${Date.now().toString(36).toUpperCase()}`;
    const learnedPattern = {
        id: patternId,
        projectId,
        type,
        pattern,
        source: source ?? 'user-defined',
        learnedAt: new Date().toISOString(),
        confidence: 0.8, // Initial confidence; increases with usage
        usageCount: 1,
    };
    await patternStore.addPattern(projectId, learnedPattern);
    // 5. Build output
    const output = {
        action: 'created',
        patternId,
        type,
        pattern,
        source: learnedPattern.source,
        totalPatterns: existingPatterns.length + 1,
        patternsByType: buildPatternSummary(existingPatterns, learnedPattern),
    };
    if (dedupWarning) {
        output.dedupWarning = dedupWarning;
    }
    const contentItems = [
        {
            type: 'text',
            text: ti('tools.learn_pattern.success', { type, pattern }),
        },
    ];
    if (dedupWarning) {
        contentItems.push({
            type: 'text',
            text: `Warning: A semantically similar pattern already exists (id: ${dedupWarning.existingPatternId}, similarity: ${dedupWarning.similarity.toFixed(3)}): "${dedupWarning.existingPattern}". Pattern stored but flagged as potential duplicate.`,
        });
    }
    contentItems.push({
        type: 'text',
        text: JSON.stringify(output, null, 2),
    });
    return { content: contentItems };
}
/**
 * SPEC-075 AC-08: Check existing patterns for semantic similarity using TF-IDF.
 * Returns a DedupWarning if a pattern with cosine similarity > threshold exists.
 */
function checkSemanticDuplicate(existingPatterns, newPattern, patternType, threshold = DEFAULT_DEDUP_THRESHOLD) {
    // Filter to same-type patterns only
    const sameType = existingPatterns.filter((p) => p.type === patternType);
    if (sameType.length === 0) {
        return undefined;
    }
    // Build TF-IDF engine from existing patterns + the new one
    const tfidf = new TFIDFEngine();
    for (const p of sameType) {
        tfidf.addDocument(p.pattern);
    }
    tfidf.addDocument(newPattern);
    // Embed the new pattern
    const newEmbedding = tfidf.embed(newPattern);
    // Find the most similar existing pattern
    let bestSimilarity = 0;
    let bestMatch;
    for (const p of sameType) {
        const embedding = tfidf.embed(p.pattern);
        const sim = cosineSimilarity(newEmbedding, embedding);
        if (sim > bestSimilarity) {
            bestSimilarity = sim;
            bestMatch = p;
        }
    }
    if (bestMatch && bestSimilarity > threshold) {
        return {
            existingPatternId: bestMatch.id,
            existingPattern: bestMatch.pattern,
            similarity: bestSimilarity,
            threshold,
        };
    }
    return undefined;
}
function buildPatternSummary(existing, newPattern) {
    const all = [...existing, newPattern];
    const summary = {};
    for (const p of all) {
        summary[p.type] = (summary[p.type] ?? 0) + 1;
    }
    return summary;
}
/**
 * SPEC-011: Dispatch a feedback loop event to the project's feedback history.
 * Silently ignores errors so it never blocks the calling operation.
 */
export async function dispatchFeedbackEvent(projectId, event) {
    try {
        await knowledgeStore.saveFeedbackEvent(projectId, event);
    }
    catch {
        // Feedback dispatch is best-effort — never block the calling operation
    }
}
//# sourceMappingURL=learn.js.map