/**
 * Service Discovery for ControlVector Tools
 *
 * Automatically discovers cv-prd, Qdrant, and FalkorDB services.
 *
 * Discovery order:
 * 1. Check ~/.cv/services.json for explicit configuration
 * 2. Check environment variables (CV_PRD_URL, CV_QDRANT_URL, etc.)
 * 3. Auto-probe localhost on common ports
 *
 * For non-technical users, the default localhost probing "just works".
 * Power users can configure remote services via `cv services add`.
 */
import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';
// Common ports for each service
const DEFAULT_PORTS = {
    cvPrd: [8000, 8080, 3000],
    qdrant: [6333],
    falkordb: [6379],
    ollama: [11434]
};
// Environment variable names
const ENV_VARS = {
    cvPrd: 'CV_PRD_URL',
    qdrant: 'CV_QDRANT_URL',
    falkordb: 'CV_FALKORDB_URL',
    ollama: 'CV_OLLAMA_URL'
};
/**
 * Get the services config file path
 */
function getServicesPath() {
    return path.join(os.homedir(), '.cv', 'services.json');
}
/**
 * Load services from config file
 */
export async function loadServicesFile() {
    try {
        const content = await fs.readFile(getServicesPath(), 'utf-8');
        return JSON.parse(content);
    }
    catch {
        return null;
    }
}
/**
 * Save services to config file
 */
export async function saveServices(services) {
    const cvDir = path.join(os.homedir(), '.cv');
    await fs.mkdir(cvDir, { recursive: true });
    const file = {
        version: '1.0.0',
        services,
        lastUpdated: new Date().toISOString()
    };
    await fs.writeFile(getServicesPath(), JSON.stringify(file, null, 2));
}
/**
 * Check if a URL is reachable
 */
async function isReachable(url, timeout = 2000) {
    try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), timeout);
        const response = await fetch(url, {
            method: 'HEAD',
            signal: controller.signal
        });
        clearTimeout(timeoutId);
        return response.ok || response.status < 500;
    }
    catch {
        return false;
    }
}
/**
 * Check if cv-prd is available at a URL
 */
async function checkCvPrd(baseUrl) {
    try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 2000);
        const response = await fetch(`${baseUrl}/api/v1/health`, {
            signal: controller.signal
        });
        clearTimeout(timeoutId);
        if (response.ok) {
            const data = await response.json();
            return data.status === 'healthy';
        }
        return false;
    }
    catch {
        return false;
    }
}
/**
 * Check if Qdrant is available at a URL
 */
async function checkQdrant(baseUrl) {
    try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 2000);
        const response = await fetch(baseUrl, {
            signal: controller.signal
        });
        clearTimeout(timeoutId);
        if (response.ok) {
            const data = await response.json();
            return data.title === 'qdrant - vectorass engine';
        }
        return false;
    }
    catch {
        return false;
    }
}
/**
 * Check if FalkorDB (Redis protocol) is available
 * Note: Can't easily check Redis via HTTP, so we just verify the port is open
 */
async function checkFalkorDB(url) {
    // Parse redis URL
    const match = url.match(/redis:\/\/([^:]+):(\d+)/);
    if (!match)
        return false;
    const [, host, port] = match;
    // Try a simple TCP connection check via HTTP fallback
    // FalkorDB doesn't have HTTP, so we'll just mark as "potentially available"
    // The actual connection will be tested when we use it
    return true;
}
/**
 * Auto-discover a service on localhost
 */
async function probeLocalhost(service, checker) {
    const ports = DEFAULT_PORTS[service];
    const hosts = ['127.0.0.1', 'localhost'];
    for (const host of hosts) {
        for (const port of ports) {
            let url;
            if (service === 'falkordb') {
                url = `redis://${host}:${port}`;
            }
            else {
                url = `http://${host}:${port}`;
            }
            if (await checker(url)) {
                return url;
            }
        }
    }
    return null;
}
/**
 * Discover cv-prd service
 */
export async function discoverCvPrd() {
    // 1. Check config file
    const config = await loadServicesFile();
    if (config?.services.cvPrd) {
        if (await checkCvPrd(config.services.cvPrd)) {
            return config.services.cvPrd;
        }
    }
    // 2. Check environment variable
    const envUrl = process.env[ENV_VARS.cvPrd];
    if (envUrl) {
        if (await checkCvPrd(envUrl)) {
            return envUrl;
        }
    }
    // 3. Auto-probe localhost
    return probeLocalhost('cvPrd', checkCvPrd);
}
/**
 * Discover Qdrant service
 */
export async function discoverQdrant() {
    // 1. Check config file
    const config = await loadServicesFile();
    if (config?.services.qdrant) {
        if (await checkQdrant(config.services.qdrant)) {
            return config.services.qdrant;
        }
    }
    // 2. Check environment variable
    const envUrl = process.env[ENV_VARS.qdrant];
    if (envUrl) {
        if (await checkQdrant(envUrl)) {
            return envUrl;
        }
    }
    // 3. Auto-probe localhost
    return probeLocalhost('qdrant', checkQdrant);
}
/**
 * Discover FalkorDB service
 */
export async function discoverFalkorDB() {
    // 1. Check config file
    const config = await loadServicesFile();
    if (config?.services.falkordb) {
        return config.services.falkordb;
    }
    // 2. Check environment variable
    const envUrl = process.env[ENV_VARS.falkordb];
    if (envUrl) {
        return envUrl;
    }
    // 3. Default localhost
    return 'redis://127.0.0.1:6379';
}
/**
 * Discover all services
 */
export async function discoverAllServices() {
    const [cvPrd, qdrant, falkordb] = await Promise.all([
        discoverCvPrd(),
        discoverQdrant(),
        discoverFalkorDB()
    ]);
    return { cvPrd, qdrant, falkordb };
}
/**
 * Get service status for display
 */
export async function getServiceStatus() {
    const services = await discoverAllServices();
    return [
        {
            name: 'cv-prd',
            url: services.cvPrd,
            status: services.cvPrd ? 'connected' : 'not found'
        },
        {
            name: 'Qdrant',
            url: services.qdrant,
            status: services.qdrant ? 'connected' : 'not found'
        },
        {
            name: 'FalkorDB',
            url: services.falkordb,
            status: services.falkordb ? 'configured' : 'not found'
        }
    ];
}
//# sourceMappingURL=services.js.map