/**
 * Memory Embedder Bridge - TypeScript interface to Python memory embedder
 *
 * This module provides a TypeScript bridge to the Python memory_embedder.py script,
 * which generates and searches embeddings for memory chunks using CodexLens's embedder.
 *
 * Features:
 * - Reuses CodexLens venv at ~/.codexlens/venv
 * - JSON protocol communication
 * - Three commands: embed, search, status
 * - Automatic availability checking
 */
import { spawn } from 'child_process';
import { join, dirname } from 'path';
import { homedir } from 'os';
import { existsSync } from 'fs';
import { fileURLToPath } from 'url';
// Get directory of this module
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Venv paths (reuse CodexLens venv)
const CODEXLENS_VENV = join(homedir(), '.codexlens', 'venv');
const VENV_PYTHON = process.platform === 'win32'
    ? join(CODEXLENS_VENV, 'Scripts', 'python.exe')
    : join(CODEXLENS_VENV, 'bin', 'python');
// Script path
const EMBEDDER_SCRIPT = join(__dirname, '..', '..', 'scripts', 'memory_embedder.py');
/**
 * Check if embedder is available (venv and script exist)
 * @returns True if embedder is available
 */
export function isEmbedderAvailable() {
    // Check venv python exists
    if (!existsSync(VENV_PYTHON)) {
        return false;
    }
    // Check script exists
    if (!existsSync(EMBEDDER_SCRIPT)) {
        return false;
    }
    return true;
}
/**
 * Run Python script with arguments
 * @param args - Command line arguments
 * @param timeout - Timeout in milliseconds
 * @returns JSON output from script
 */
function runPython(args, timeout = 300000) {
    return new Promise((resolve, reject) => {
        // Check availability
        if (!isEmbedderAvailable()) {
            reject(new Error('Memory embedder not available. Ensure CodexLens venv exists at ~/.codexlens/venv'));
            return;
        }
        // Spawn Python process
        const child = spawn(VENV_PYTHON, [EMBEDDER_SCRIPT, ...args], {
            stdio: ['ignore', 'pipe', 'pipe'],
            timeout,
        });
        let stdout = '';
        let stderr = '';
        child.stdout.on('data', (data) => {
            stdout += data.toString();
        });
        child.stderr.on('data', (data) => {
            stderr += data.toString();
        });
        child.on('close', (code) => {
            if (code === 0) {
                resolve(stdout.trim());
            }
            else {
                reject(new Error(`Python script failed (exit code ${code}): ${stderr || stdout}`));
            }
        });
        child.on('error', (err) => {
            if (err.code === 'ETIMEDOUT') {
                reject(new Error('Python script timed out'));
            }
            else {
                reject(new Error(`Failed to spawn Python: ${err.message}`));
            }
        });
    });
}
/**
 * Generate embeddings for memory chunks
 * @param dbPath - Path to SQLite database
 * @param options - Embedding options
 * @returns Embedding result
 */
export async function generateEmbeddings(dbPath, options = {}) {
    const { sourceId, batchSize = 8, force = false } = options;
    // Build arguments
    const args = ['embed', dbPath];
    if (sourceId) {
        args.push('--source-id', sourceId);
    }
    if (batchSize !== 8) {
        args.push('--batch-size', batchSize.toString());
    }
    if (force) {
        args.push('--force');
    }
    try {
        // Default timeout: 5 minutes
        const output = await runPython(args, 300000);
        const result = JSON.parse(output);
        return result;
    }
    catch (err) {
        return {
            success: false,
            chunks_processed: 0,
            chunks_failed: 0,
            elapsed_time: 0,
            error: err.message,
        };
    }
}
/**
 * Search memory chunks using semantic search
 * @param dbPath - Path to SQLite database
 * @param query - Search query text
 * @param options - Search options
 * @returns Search results
 */
export async function searchMemories(dbPath, query, options = {}) {
    const { topK = 10, minScore = 0.3, sourceType } = options;
    // Build arguments
    const args = ['search', dbPath, query];
    if (topK !== 10) {
        args.push('--top-k', topK.toString());
    }
    if (minScore !== 0.3) {
        args.push('--min-score', minScore.toString());
    }
    if (sourceType) {
        args.push('--type', sourceType);
    }
    try {
        // Default timeout: 30 seconds
        const output = await runPython(args, 30000);
        const result = JSON.parse(output);
        return result;
    }
    catch (err) {
        return {
            success: false,
            matches: [],
            error: err.message,
        };
    }
}
/**
 * Get embedding status statistics
 * @param dbPath - Path to SQLite database
 * @returns Embedding status
 */
export async function getEmbeddingStatus(dbPath) {
    // Build arguments
    const args = ['status', dbPath];
    try {
        // Default timeout: 30 seconds
        const output = await runPython(args, 30000);
        const result = JSON.parse(output);
        return { ...result, success: true };
    }
    catch (err) {
        return {
            success: false,
            total_chunks: 0,
            embedded_chunks: 0,
            pending_chunks: 0,
            by_type: {},
            error: err.message,
        };
    }
}
//# sourceMappingURL=memory-embedder-bridge.js.map