"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMcpServer = createMcpServer;
exports.getMcpServer = getMcpServer;
exports.getMcpServerByName = getMcpServerByName;
exports.updateMcpServer = updateMcpServer;
exports.deleteMcpServer = deleteMcpServer;
exports.updateMcpServerStatus = updateMcpServerStatus;
exports.listMcpServers = listMcpServers;
exports.getAutoConnectServers = getAutoConnectServers;
exports.findServersByTags = findServersByTags;
exports.seedMcpServer = seedMcpServer;
exports.cleanStaleBuiltinServers = cleanStaleBuiltinServers;
const db_1 = require("../../lib/db");
const logger_1 = require("../../lib/logger");
const sql_1 = require("./sql");
async function createMcpServer(input) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.CREATE_MCP_SERVER, [
        input.name,
        input.description || null,
        input.transport_type,
        JSON.stringify(input.transport_config),
        input.auto_connect ?? false,
        input.metadata ? JSON.stringify(input.metadata) : null,
        input.tags || [],
        input.compile_hints || null,
        input.credential_providers || [],
    ]);
    return rows[0];
}
async function getMcpServer(id) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_MCP_SERVER, [id]);
    return rows[0] || null;
}
async function getMcpServerByName(name) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_MCP_SERVER_BY_NAME, [name]);
    return rows[0] || null;
}
async function updateMcpServer(id, updates) {
    const pool = (0, db_1.getPool)();
    const sets = [];
    const values = [];
    let idx = 1;
    if (updates.name !== undefined) {
        sets.push(`name = $${idx++}`);
        values.push(updates.name);
    }
    if (updates.description !== undefined) {
        sets.push(`description = $${idx++}`);
        values.push(updates.description);
    }
    if (updates.transport_type !== undefined) {
        sets.push(`transport_type = $${idx++}`);
        values.push(updates.transport_type);
    }
    if (updates.transport_config !== undefined) {
        sets.push(`transport_config = $${idx++}`);
        values.push(JSON.stringify(updates.transport_config));
    }
    if (updates.auto_connect !== undefined) {
        sets.push(`auto_connect = $${idx++}`);
        values.push(updates.auto_connect);
    }
    if (updates.metadata !== undefined) {
        sets.push(`metadata = $${idx++}`);
        values.push(JSON.stringify(updates.metadata));
    }
    if (updates.tags !== undefined) {
        sets.push(`tags = $${idx++}`);
        values.push(updates.tags);
    }
    if (updates.compile_hints !== undefined) {
        sets.push(`compile_hints = $${idx++}`);
        values.push(updates.compile_hints || null);
    }
    if (updates.credential_providers !== undefined) {
        sets.push(`credential_providers = $${idx++}`);
        values.push(updates.credential_providers);
    }
    if (sets.length === 0)
        return getMcpServer(id);
    values.push(id);
    const { rows } = await pool.query(`UPDATE lt_mcp_servers SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`, values);
    return rows[0] || null;
}
async function deleteMcpServer(id) {
    const pool = (0, db_1.getPool)();
    const { rowCount } = await pool.query(sql_1.DELETE_MCP_SERVER, [id]);
    return (rowCount || 0) > 0;
}
async function updateMcpServerStatus(id, status, toolManifest) {
    const pool = (0, db_1.getPool)();
    if (status === 'connected') {
        await pool.query(sql_1.UPDATE_STATUS_CONNECTED, [id, status, toolManifest ? JSON.stringify(toolManifest) : null]);
    }
    else {
        await pool.query(sql_1.UPDATE_STATUS, [id, status]);
    }
}
async function listMcpServers(filters) {
    const pool = (0, db_1.getPool)();
    const conditions = [];
    const values = [];
    let idx = 1;
    if (filters.status) {
        conditions.push(`status = $${idx++}`);
        values.push(filters.status);
    }
    if (filters.auto_connect !== undefined) {
        conditions.push(`auto_connect = $${idx++}`);
        values.push(filters.auto_connect);
    }
    if (filters.search) {
        conditions.push(`(name ILIKE $${idx} OR description ILIKE $${idx} OR tool_manifest::text ILIKE $${idx})`);
        values.push(`%${filters.search}%`);
        idx++;
    }
    if (filters.tags?.length) {
        conditions.push(`tags && $${idx++}::text[]`);
        values.push(filters.tags);
    }
    const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
    const limit = filters.limit || 50;
    const offset = filters.offset || 0;
    const [countResult, dataResult] = await Promise.all([
        pool.query(`SELECT COUNT(*) FROM lt_mcp_servers ${where}`, values),
        pool.query(`SELECT * FROM lt_mcp_servers ${where} ORDER BY created_at DESC LIMIT $${idx++} OFFSET $${idx++}`, [...values, limit, offset]),
    ]);
    return {
        servers: dataResult.rows,
        total: parseInt(countResult.rows[0].count, 10),
    };
}
async function getAutoConnectServers() {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_AUTO_CONNECT_SERVERS);
    return rows;
}
/**
 * Find MCP servers by tags.
 * @param tags - Tags to filter by
 * @param match - 'any' (OR — server has at least one tag) or 'all' (AND — server has all tags)
 */
async function findServersByTags(tags, match = 'any') {
    if (!tags.length)
        return [];
    const pool = (0, db_1.getPool)();
    const operator = match === 'all' ? '@>' : '&&';
    const { rows } = await pool.query(`SELECT * FROM lt_mcp_servers WHERE tags ${operator} $1::text[] ORDER BY name`, [tags]);
    return rows;
}
/**
 * Seed an MCP server at startup (insert-if-absent).
 * DB is the source of truth — if the row already exists, log drift warnings
 * but do not overwrite. Returns true if inserted, false if already existed.
 */
async function seedMcpServer(input) {
    const pool = (0, db_1.getPool)();
    const { rowCount } = await pool.query(sql_1.SEED_MCP_SERVER, [
        input.name,
        input.description || null,
        'stdio',
        JSON.stringify({ builtin: true, process: 'in-memory' }),
        JSON.stringify(input.toolManifest || []),
        JSON.stringify({ builtin: true }),
        input.tags || [],
        input.compileHints || null,
        input.credentialProviders || [],
        input.category || null,
    ]);
    const inserted = (rowCount ?? 0) > 0;
    if (!inserted) {
        // Drift detection
        const existing = await getMcpServerByName(input.name);
        if (existing) {
            const drifts = [];
            if (input.description && existing.description !== input.description)
                drifts.push('description');
            if (input.compileHints && existing.compile_hints !== input.compileHints)
                drifts.push('compile_hints');
            if (JSON.stringify(input.tags || []) !== JSON.stringify(existing.tags || []))
                drifts.push('tags');
            if (drifts.length) {
                logger_1.loggerRegistry.warn(`[long-tail] MCP server drift: ${input.name} — ${drifts.join(', ')} differ between code and DB`);
            }
        }
    }
    return inserted;
}
/**
 * Remove builtin MCP servers that are no longer declared in factory config.
 */
async function cleanStaleBuiltinServers(activeNames) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.DELETE_STALE_BUILTIN_SERVERS, [activeNames]);
    for (const row of rows) {
        logger_1.loggerRegistry.info(`[long-tail] removed stale builtin MCP server: ${row.name}`);
    }
}
