"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.classifyQueryIntent = classifyQueryIntent;
exports.buildContext = buildContext;
exports.getShortContext = getShortContext;
exports.getFullContext = getFullContext;
exports.getTopicContext = getTopicContext;
const database_1 = require("../database/database");
const handoff_store_1 = require("../handoff/handoff-store");
const style_memory_1 = require("../style/style-memory");
const summary_generator_1 = require("../stores/summary-generator");
const memory_search_1 = require("../stores/memory-search");
const INTENT_KEYWORDS = {
    testing: ['test', 'testing', 'jest', 'vitest', 'spec', 'coverage', 'unit test', 'integration test', 'e2e'],
    bug: ['bug', 'error', 'fix', 'issue', 'crash', 'exception', 'fail', 'broken', 'regression', 'debug'],
    architecture: ['arch', 'architecture', 'structure', 'design', 'pattern', 'refactor', 'module', 'layer', 'dependency'],
    status: ['status', 'progress', 'what did', 'where was', 'last', 'recent', 'session', 'handoff', 'continue'],
    style: ['style', 'format', 'indent', 'semicolon', 'quote', 'naming', 'convention', 'preference'],
    memory: ['remember', 'memory', 'decision', 'lesson', 'learned', 'why', 'history', 'evolution'],
    general: [],
};
function classifyQueryIntent(query) {
    if (!query)
        return 'general';
    const lower = query.toLowerCase();
    for (const [intent, keywords] of Object.entries(INTENT_KEYWORDS)) {
        if (intent === 'general')
            continue;
        for (const kw of keywords) {
            if (lower.includes(kw))
                return intent;
        }
    }
    return 'general';
}
// Intent → which sources to prioritize
const INTENT_SOURCE_PRIORITY = {
    testing: ['patterns', 'errors_fixes', 'decisions', 'session', 'style'],
    bug: ['errors_fixes', 'patterns', 'session', 'decisions', 'search'],
    architecture: ['patterns', 'decisions', 'style', 'session', 'summary'],
    status: ['handoff', 'session', 'summary', 'decisions', 'errors_fixes'],
    style: ['style', 'patterns', 'session'],
    memory: ['decisions', 'session', 'errors_fixes', 'patterns', 'summary'],
    general: ['handoff', 'session', 'decisions', 'errors_fixes', 'patterns', 'style', 'summary'],
};
// ============================================================
// Step helpers
// ============================================================
function detectBranch(project) {
    try {
        const { execSync } = require('child_process');
        return execSync('git branch --show-current', { encoding: 'utf-8', timeout: 3000 }).trim() || 'main';
    }
    catch {
        return 'main';
    }
}
function getRecentSession(db, project, limit = 20) {
    const session = db.prepare(`SELECT id, start_time, end_time FROM sessions WHERE project = ? ORDER BY id DESC LIMIT 1`).get(project);
    if (!session)
        return [];
    return db.prepare(`SELECT type, summary, topic, importance, files_json, created_at
     FROM memory_events
     WHERE project = ? AND created_at >= ? AND created_at <= ?
     ORDER BY importance DESC, created_at DESC LIMIT ?`).all(project, session.start_time, session.end_time || new Date().toISOString(), limit);
}
function getMatchingDecisions(db, project, topic, file, limit = 10) {
    let sql = `SELECT type, summary, topic, importance, files_json, created_at FROM memory_events WHERE project = ? AND type = 'decision'`;
    const params = [project];
    if (topic) {
        sql += ` AND topic = ?`;
        params.push(topic);
    }
    if (file) {
        sql += ` AND files_json LIKE ?`;
        params.push(`%${file}%`);
    }
    sql += ` ORDER BY importance DESC, created_at DESC LIMIT ?`;
    params.push(limit);
    return db.prepare(sql).all(...params);
}
function getMatchingErrorsFixes(db, project, topic, file, limit = 10) {
    let sql = `SELECT type, summary, topic, importance, files_json, created_at FROM memory_events WHERE project = ? AND type IN ('error', 'fix')`;
    const params = [project];
    if (topic) {
        sql += ` AND topic = ?`;
        params.push(topic);
    }
    if (file) {
        sql += ` AND files_json LIKE ?`;
        params.push(`%${file}%`);
    }
    sql += ` ORDER BY importance DESC, created_at DESC LIMIT ?`;
    params.push(limit);
    return db.prepare(sql).all(...params);
}
function getPatterns(db, project, topic, limit = 10) {
    let sql = `SELECT pattern, category, importance FROM memory_patterns WHERE project = ?`;
    const params = [project];
    if (topic) {
        sql += ` AND category LIKE ?`;
        params.push(`%${topic}%`);
    }
    sql += ` ORDER BY importance DESC LIMIT ?`;
    params.push(limit);
    return db.prepare(sql).all(...params);
}
function rankSources(sources, intent) {
    const now = Date.now();
    const DAY = 86400000;
    // Get priority order for this intent
    const priorityOrder = intent ? INTENT_SOURCE_PRIORITY[intent] : INTENT_SOURCE_PRIORITY.general;
    // Compute recency bonus for each source
    const withRecency = sources.map(s => {
        let recencyBonus = 0;
        let frequencyBoost = 0;
        let crossSourceCorrelation = 0;
        let intentBoost = 0;
        // Intent boost: prioritize sources that match the query intent
        const intentIndex = priorityOrder.indexOf(s.type);
        if (intentIndex >= 0) {
            intentBoost = (priorityOrder.length - intentIndex) * 5; // Higher priority = higher boost
        }
        // Recency: boost recent events
        const data = s.data;
        if (Array.isArray(data) && data.length > 0 && typeof data[0] === 'object' && data[0] !== null && 'created_at' in data[0]) {
            const newest = data.reduce((max, item) => {
                const t = item?.created_at;
                return t && t > max ? t : max;
            }, '');
            if (newest) {
                const ageMs = now - new Date(newest).getTime();
                if (ageMs < DAY)
                    recencyBonus = 20; // < 24 hours
                else if (ageMs < 7 * DAY)
                    recencyBonus = 10; // < 7 days
                else if (ageMs < 30 * DAY)
                    recencyBonus = 5; // < 30 days
            }
        }
        // Frequency: boost sources with many matching events
        if (Array.isArray(data) && data.length > 3) {
            frequencyBoost = Math.min(data.length * 2, 20); // max +20 for 10+ events
        }
        return { source: s, recencyBonus, frequencyBoost, crossSourceCorrelation, intentBoost };
    });
    // Cross-source correlation: boost topics that appear across multiple source types
    const topicCounts = new Map();
    for (const { source: s } of withRecency) {
        const data = s.data;
        if (Array.isArray(data)) {
            for (const item of data) {
                const topic = item?.topic;
                if (topic) {
                    if (!topicCounts.has(topic))
                        topicCounts.set(topic, new Set());
                    topicCounts.get(topic).add(s.type);
                }
            }
        }
    }
    for (const entry of withRecency) {
        const data = entry.source.data;
        if (Array.isArray(data)) {
            for (const item of data) {
                const topic = item?.topic;
                if (topic && topicCounts.get(topic).size > 1) {
                    entry.crossSourceCorrelation = 15;
                    break;
                }
            }
        }
    }
    // Compute final score and sort
    return withRecency
        .map(({ source: s, recencyBonus, frequencyBoost, crossSourceCorrelation, intentBoost }) => ({
        source: s,
        finalScore: s.importance * 3 + recencyBonus + frequencyBoost + crossSourceCorrelation + intentBoost,
    }))
        .sort((a, b) => b.finalScore - a.finalScore)
        .map(({ source }) => source);
}
function buildCompactContext(resp) {
    const lines = [];
    lines.push(`# Context: ${resp.project} (${resp.branch})`);
    lines.push(`Mode: ${resp.mode} | Sources: ${resp.stats.totalSources} | Generated: ${resp.generatedAt}`);
    lines.push('');
    for (const src of resp.sources) {
        lines.push(`## [${src.type}] — ${src.reason}`);
        if (src.type === 'handoff' && typeof src.data === 'string') {
            // Truncate handoff to first 30 lines
            const handoffLines = src.data.split('\n').slice(0, 30);
            lines.push(...handoffLines);
            if (src.data.split('\n').length > 30) {
                lines.push('... (truncated)');
            }
        }
        else if (src.type === 'session' && Array.isArray(src.data)) {
            for (const ev of src.data) {
                lines.push(`- [${ev.type}] (imp:${ev.importance}) ${ev.summary}`);
            }
        }
        else if (src.type === 'decisions' && Array.isArray(src.data)) {
            for (const ev of src.data) {
                lines.push(`- (imp:${ev.importance}) ${ev.summary}`);
            }
        }
        else if (src.type === 'errors_fixes' && Array.isArray(src.data)) {
            for (const ev of src.data) {
                lines.push(`- [${ev.type}] (imp:${ev.importance}) ${ev.summary}`);
            }
        }
        else if (src.type === 'patterns' && Array.isArray(src.data)) {
            for (const p of src.data) {
                lines.push(`- [${p.category}] ${p.pattern}`);
            }
        }
        else if (src.type === 'style' && typeof src.data === 'string') {
            lines.push(src.data);
        }
        else if (src.type === 'summary' && typeof src.data === 'string') {
            lines.push(src.data);
        }
        lines.push('');
    }
    return lines.join('\n');
}
// ============================================================
// Main pipeline
// ============================================================
function buildContext(req) {
    const db = (0, database_1.getDb)();
    const { project, projectDir, topic, file, query, mode = 'short' } = req;
    const branch = req.branch || detectBranch(project);
    // Classify query intent for targeted retrieval
    const intent = classifyQueryIntent(query || topic);
    const sources = [];
    // Step 3: Current handoff
    try {
        const handoff = (0, handoff_store_1.getCurrentHandoff)(projectDir);
        if (handoff && !handoff.includes('No handoff entries yet')) {
            sources.push({
                type: 'handoff',
                reason: 'current project handoff',
                data: handoff,
                importance: 95,
            });
        }
    }
    catch { /* non-critical */ }
    // Step 4: Recent session events
    const sessionEvents = getRecentSession(db, project, mode === 'full' ? 30 : 15);
    if (sessionEvents.length > 0) {
        sources.push({
            type: 'session',
            reason: `recent session (${sessionEvents.length} events)`,
            data: sessionEvents,
            importance: 70,
        });
    }
    // Step 5: Matching decisions
    const decisions = getMatchingDecisions(db, project, topic, file, mode === 'full' ? 15 : 8);
    if (decisions.length > 0) {
        sources.push({
            type: 'decisions',
            reason: topic ? `decisions matching topic "${topic}"` : 'recent decisions',
            data: decisions,
            importance: 90,
        });
    }
    // Step 6: Matching errors/fixes
    const errorsFixes = getMatchingErrorsFixes(db, project, topic, file, mode === 'full' ? 15 : 8);
    if (errorsFixes.length > 0) {
        sources.push({
            type: 'errors_fixes',
            reason: topic ? `errors/fixes matching topic "${topic}"` : 'recent errors and fixes',
            data: errorsFixes,
            importance: 80,
        });
    }
    // Step 7: Patterns
    const patterns = getPatterns(db, project, topic, mode === 'full' ? 15 : 8);
    if (patterns.length > 0) {
        sources.push({
            type: 'patterns',
            reason: topic ? `patterns matching "${topic}"` : 'learned patterns',
            data: patterns,
            importance: 75,
        });
    }
    // Step 8: Style rules
    try {
        const devStyle = (0, style_memory_1.loadDeveloperStyle)(projectDir);
        const projStyle = (0, style_memory_1.loadProjectStyle)(projectDir);
        const styleText = `Communication: ${devStyle.communication}\nCoding: ${devStyle.coding}\nVerification: ${devStyle.verification.join(', ')}\nPrivacy: ${devStyle.privacy.join(', ')}\nArchitecture: ${projStyle.architecture}\nNaming: ${projStyle.naming}\nTesting: ${projStyle.testing}`;
        sources.push({
            type: 'style',
            reason: 'developer and project style',
            data: styleText,
            importance: 60,
        });
    }
    catch { /* non-critical */ }
    // Step 8.5: Developer profile from Teach (if available)
    try {
        const { getProfileForContext } = require('../teach/teach-context');
        const profileSource = getProfileForContext();
        if (profileSource) {
            sources.push(profileSource);
        }
    }
    catch { /* teach not yet used — skip */ }
    // Step 9: Summaries
    try {
        const daily = (0, summary_generator_1.generateDailySummary)(project);
        if (daily.totalEvents > 0) {
            const summaryText = `Today: ${daily.totalEvents} events, ${Object.keys(daily.byType).length} types. Key decisions: ${daily.keyDecisions.length}. Errors: ${daily.errors.length}. Top topics: ${daily.topTopics.join(', ')}`;
            sources.push({
                type: 'summary',
                reason: 'daily summary',
                data: summaryText,
                importance: 55,
            });
        }
    }
    catch { /* non-critical */ }
    // Step 10: Query-based search
    if (query) {
        try {
            const searchResults = (0, memory_search_1.fuzzySearchMemory)({ query, project, limit: 10 });
            if (searchResults.length > 0) {
                sources.push({
                    type: 'search',
                    reason: `query match for "${query}"`,
                    data: searchResults,
                    importance: 70,
                });
            }
        }
        catch { /* non-critical */ }
    }
    // Step 10.5: CI data (if relevant to intent)
    if (intent === 'bug' || intent === 'status') {
        try {
            const ciDb = (0, database_1.getDb)();
            const ciEvents = ciDb.prepare(`SELECT type, summary, topic, importance, created_at FROM memory_events WHERE project = ? AND type IN ('verification', 'error') AND (topic LIKE 'ci-%') ORDER BY created_at DESC LIMIT 5`).all(project);
            if (ciEvents.length > 0) {
                sources.push({
                    type: 'ci',
                    reason: `recent CI events (${ciEvents.length})`,
                    data: ciEvents,
                    importance: 75,
                });
            }
        }
        catch { /* non-critical */ }
    }
    // Step 10: Rank (with intent-based priority)
    const ranked = rankSources(sources, intent);
    // Step 11: Build compact context
    const resp = {
        project,
        branch,
        mode,
        sources: ranked,
        compactContext: '',
        generatedAt: new Date().toISOString(),
        stats: {
            totalSources: ranked.length,
            totalEvents: sessionEvents.length + decisions.length + errorsFixes.length,
            relevanceScore: ranked.reduce((sum, s) => sum + s.importance, 0) / Math.max(ranked.length, 1),
        },
    };
    resp.compactContext = buildCompactContext(resp);
    return resp;
}
// ============================================================
// Convenience wrappers
// ============================================================
function getShortContext(project, projectDir) {
    return buildContext({ project, projectDir, mode: 'short' }).compactContext;
}
function getFullContext(project, projectDir) {
    return buildContext({ project, projectDir, mode: 'full' }).compactContext;
}
function getTopicContext(project, projectDir, topic) {
    return buildContext({ project, projectDir, mode: 'topic', topic }).compactContext;
}
//# sourceMappingURL=context-pipeline.js.map