"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.storeKnowledge = storeKnowledge;
exports.getKnowledge = getKnowledge;
exports.searchKnowledge = searchKnowledge;
exports.listKnowledge = listKnowledge;
exports.deleteKnowledge = deleteKnowledge;
exports.setKnowledgeField = setKnowledgeField;
exports.removeKnowledgeField = removeKnowledgeField;
exports.listDomains = listDomains;
exports.appendKnowledge = appendKnowledge;
const db_1 = require("../../lib/db");
const publish_1 = require("../../lib/events/publish");
const sql_1 = require("./sql");
async function withClient(fn) {
    const { class: PgClient, options } = (0, db_1.getConnection)();
    const client = new PgClient(options);
    await client.connect();
    try {
        return await fn(client);
    }
    finally {
        await client.end();
    }
}
async function storeKnowledge(args) {
    return withClient(async (client) => {
        const sql = args.replace ? sql_1.REPLACE_KNOWLEDGE : sql_1.UPSERT_KNOWLEDGE;
        const { rows } = await client.query(sql, [args.domain, args.key, JSON.stringify(args.data), args.tags || []]);
        const result = { ...rows[0], updated_at: rows[0].updated_at.toISOString() };
        (0, publish_1.publishKnowledgeEvent)({ type: 'knowledge.stored', domain: args.domain, key: args.key });
        return result;
    });
}
async function getKnowledge(args) {
    return withClient(async (client) => {
        const { rows } = await client.query(sql_1.GET_KNOWLEDGE, [args.domain, args.key]);
        if (!rows.length)
            return { found: false, domain: args.domain, key: args.key };
        const row = rows[0];
        return {
            id: row.id,
            domain: row.domain,
            key: row.key,
            data: row.data,
            tags: row.tags,
            created_at: row.created_at.toISOString(),
            updated_at: row.updated_at.toISOString(),
        };
    });
}
async function searchKnowledge(args) {
    return withClient(async (client) => {
        const limit = Math.min(args.limit || 50, 200);
        const offset = args.offset || 0;
        const params = [args.domain, JSON.stringify(args.query)];
        let tagClause = '';
        if (args.tags?.length) {
            params.push(args.tags);
            tagClause = ` AND tags && $${params.length}`;
        }
        const countParams = [...params];
        const countResult = await client.query(`SELECT COUNT(*)::int AS total FROM lt_knowledge
       WHERE domain = $1 AND data @> $2::jsonb${tagClause}`, countParams);
        params.push(limit);
        const limitIdx = params.length;
        params.push(offset);
        const offsetIdx = params.length;
        const { rows } = await client.query(`SELECT id, domain, key, data, tags, created_at, updated_at
       FROM lt_knowledge
       WHERE domain = $1 AND data @> $2::jsonb${tagClause}
       ORDER BY updated_at DESC LIMIT $${limitIdx} OFFSET $${offsetIdx}`, params);
        return {
            entries: rows.map((r) => ({
                id: r.id, domain: r.domain, key: r.key, data: r.data, tags: r.tags,
                created_at: r.created_at.toISOString(), updated_at: r.updated_at.toISOString(),
            })),
            total: countResult.rows[0].total,
        };
    });
}
async function listKnowledge(args) {
    return withClient(async (client) => {
        const limit = Math.min(args.limit || 50, 200);
        const offset = args.offset || 0;
        const params = [args.domain];
        let extraClauses = '';
        if (args.tags?.length) {
            params.push(args.tags);
            extraClauses += ` AND tags && $${params.length}`;
        }
        if (args.search) {
            params.push(`%${args.search}%`);
            const searchIdx = params.length;
            // Match key by ILIKE or any tag element by ILIKE
            extraClauses += ` AND (key ILIKE $${searchIdx} OR EXISTS (SELECT 1 FROM unnest(tags) t WHERE t ILIKE $${searchIdx}))`;
        }
        const countResult = await client.query(`SELECT COUNT(*)::int AS total FROM lt_knowledge WHERE domain = $1${extraClauses}`, params);
        const queryParams = [...params, limit, offset];
        const limitIdx = params.length + 1;
        const offsetIdx = params.length + 2;
        const { rows } = await client.query(`SELECT id, domain, key, data, tags, created_at, updated_at
       FROM lt_knowledge WHERE domain = $1${extraClauses}
       ORDER BY updated_at DESC LIMIT $${limitIdx} OFFSET $${offsetIdx}`, queryParams);
        return {
            entries: rows.map((r) => ({
                id: r.id, domain: r.domain, key: r.key, data: r.data, tags: r.tags,
                created_at: r.created_at.toISOString(), updated_at: r.updated_at.toISOString(),
            })),
            total: countResult.rows[0].total,
        };
    });
}
async function deleteKnowledge(args) {
    return withClient(async (client) => {
        const { rowCount } = await client.query(sql_1.DELETE_KNOWLEDGE, [args.domain, args.key]);
        const deleted = (rowCount ?? 0) > 0;
        if (deleted) {
            (0, publish_1.publishKnowledgeEvent)({ type: 'knowledge.deleted', domain: args.domain, key: args.key });
        }
        return { deleted };
    });
}
async function setKnowledgeField(args) {
    return withClient(async (client) => {
        const pathParts = args.path.split('.');
        // Build initial data for INSERT (nested structure from path)
        let initData = { [pathParts[pathParts.length - 1]]: args.value };
        for (let i = pathParts.length - 2; i >= 0; i--) {
            initData = { [pathParts[i]]: initData };
        }
        const { rows } = await client.query(sql_1.SET_KNOWLEDGE_FIELD, [
            args.domain,
            args.key,
            JSON.stringify(initData),
            args.tags || [],
            pathParts,
            JSON.stringify(args.value),
        ]);
        return { ...rows[0], updated_at: rows[0].updated_at.toISOString() };
    });
}
async function removeKnowledgeField(args) {
    return withClient(async (client) => {
        const pathParts = args.path.split('.');
        const { rowCount } = await client.query(sql_1.REMOVE_KNOWLEDGE_FIELD, [args.domain, args.key, pathParts]);
        return { removed: (rowCount ?? 0) > 0 };
    });
}
async function listDomains() {
    return withClient(async (client) => {
        const { rows } = await client.query(sql_1.LIST_DOMAINS);
        return {
            domains: rows.map((r) => ({
                domain: r.domain,
                count: r.count,
                latest: r.latest.toISOString(),
            })),
        };
    });
}
async function appendKnowledge(args) {
    return withClient(async (client) => {
        const pathParts = args.path.split('.');
        const pathArray = pathParts;
        const valueJson = JSON.stringify(args.value);
        // Build the initial data object for INSERT (nested path support)
        let initData = { [pathParts[pathParts.length - 1]]: [args.value] };
        for (let i = pathParts.length - 2; i >= 0; i--) {
            initData = { [pathParts[i]]: initData };
        }
        const { rows } = await client.query(sql_1.APPEND_KNOWLEDGE, [args.domain, args.key, JSON.stringify(initData), pathArray, valueJson]);
        return { ...rows[0], updated_at: rows[0].updated_at.toISOString() };
    });
}
