"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ArgusService = void 0;
const argusAgentNode_1 = require("./graph/nodes/argusAgentNode");
const errorHandlerNode_1 = require("./graph/nodes/errorHandlerNode");
const client_1 = require("../../../providers/mcp/client");
const database_1 = require("../../../database");
const tables_1 = require("../../../database/tables");
const crypto_1 = require("crypto");
const drizzle_orm_1 = require("drizzle-orm");
const logger_1 = __importDefault(require("../../../logger"));
function hasEvaluationIntent(query) {
    const q = (query || '').toLowerCase();
    if (!q) {
        return false;
    }
    const keywords = [
        'evaluation',
        'evaluations',
        'eval',
        'score',
        'scores',
        'metric',
        'metrics',
        'assertion',
        'assertions',
        'grading',
        'grade',
        'pass',
        'fail',
        'redteam',
        'red team',
        'security',
        'truScout',
        'plugins',
        'plugin',
        'strategy',
        'strategies',
        'suggestions',
        'prompt',
        'prompts',
        'response',
        'responses',
        'cost',
        'costs',
        'latency',
        'latencies',
    ];
    return keywords.some((kw) => q.includes(kw));
}
function hasGraphIntent(query) {
    const q = (query || '').toLowerCase();
    if (!q) {
        return false;
    }
    const keywords = [
        'chart',
        'charts',
        'graph',
        'graphs',
        'visualize',
        'visualisation',
        'visualization',
        'time series',
        'trend',
        'trends',
        'over time',
        'bar',
        'histogram',
        'distribution',
        'plot',
        'plots',
    ];
    return keywords.some((kw) => q.includes(kw));
}
/**
 * Argus Service - Main service for Ask Argus
 */
class ArgusService {
    constructor(domainRegistry) {
        this.mcpInitialized = false;
        this.domainRegistry = domainRegistry;
        // Always try to enable MCP client with a default server configuration.
        // If this fails, we log and fall back to direct REST tools.
        const mcpConfig = {
            enabled: true,
            server: {
                // Use the current Node executable to run the built MCP server
                command: process.execPath,
                args: ['dist/src/server/services/argus/mcp/server.js'],
                name: 'argus-tools',
            },
            debug: process.env.ARGUS_MCP_DEBUG === 'true',
            verbose: process.env.ARGUS_MCP_VERBOSE === 'true',
        };
        try {
            this.mcpClient = new client_1.MCPClient(mcpConfig);
        }
        catch (error) {
            logger_1.default.warn(`Failed to construct MCP client, falling back to direct tools: ${error instanceof Error ? error.message : String(error)}`);
            this.mcpClient = undefined;
        }
    }
    /**
     * Initialize MCP client if configured
     */
    async initializeMCP() {
        if (!this.mcpClient || this.mcpInitialized) {
            return;
        }
        try {
            await this.mcpClient.initialize();
            this.mcpInitialized = true;
        }
        catch (error) {
            // If MCP initialization fails, log and fall back to direct REST tools.
            logger_1.default.warn(`Failed to initialize MCP client, falling back to direct tools: ${error instanceof Error ? error.message : String(error)}`);
            this.mcpClient = undefined;
            this.mcpInitialized = true;
        }
    }
    /**
     * Main ask method - processes user queries
     */
    async ask(domain, query, filters = {}, options = {}) {
        try {
            // Validate domain
            if (!this.domainRegistry.has(domain)) {
                throw new Error(`Domain ${domain} is not registered`);
            }
            // Lazily initialize MCP client on first use (if configured)
            await this.initializeMCP();
            // Auto-toggle includeEvaluationResults for evaluation-intent queries when not explicitly set.
            // By default this remains false to keep payloads small; we only enable it when the user
            // clearly asks about evaluation details (scores, pass/fail, findings, etc.).
            let effectiveFilters = { ...(filters || {}) };
            if (String(domain) === 'trupulse' &&
                effectiveFilters.includeEvaluationResults === undefined &&
                hasEvaluationIntent(query)) {
                effectiveFilters = {
                    ...effectiveFilters,
                    includeEvaluationResults: true,
                };
                logger_1.default.info('ArgusService.ask: auto-enabled includeEvaluationResults based on evaluation intent in query');
            }
            // Decide effective response format:
            // - If UI provided options.responseFormat, honor it.
            // - Otherwise, infer from query (graph vs text).
            const inferredFormat = hasGraphIntent(query) ? 'graph' : 'text';
            const responseFormat = options.responseFormat === 'both' ? 'both' : inferredFormat;
            // Create initial state
            const initialState = {
                domain,
                query,
                filters: effectiveFilters,
                userId: options.userId,
                username: options.username,
                projectId: options.projectId,
                orgId: options.orgId,
                responseFormat,
                threadId: options.threadId,
                metadata: {
                    startTime: new Date(),
                    executionPath: [],
                    apiCalls: [],
                },
            };
            // Create agent node (pass MCP client if available)
            const agentNode = (0, argusAgentNode_1.createArgusAgentNode)(domain, this.mcpClient);
            const errorHandlerNode = (0, errorHandlerNode_1.createErrorHandlerNode)();
            // Execute agent
            let state = initialState;
            try {
                state = { ...state, ...(await agentNode(state)) };
            }
            catch (error) {
                logger_1.default.error(`Agent execution error: ${error}`);
                state.error = error instanceof Error ? error.message : String(error);
            }
            // Handle errors if any
            if (state.error) {
                state = { ...state, ...(await errorHandlerNode(state)) };
            }
            // Return response
            if (!state.response) {
                throw new Error('No response generated');
            }
            const response = {
                ...state.response,
                metadata: {
                    ...state.response.metadata,
                    // Surface apiCalls collected during execution as part of the response metadata
                    apiCalls: state.metadata?.apiCalls ?? [],
                },
            };
            // Persist Argus chat history (best-effort, non-blocking on failure)
            try {
                const db = (0, database_1.getDb)();
                const chatHistoryId = (0, crypto_1.randomUUID)();
                const historyFilters = (state.filters || filters || {});
                const traceId = historyFilters.traceId;
                const sessionId = historyFilters.sessionId;
                const testRunId = historyFilters.testRunId;
                const applicationId = historyFilters.applicationId;
                const securityConfigId = historyFilters.securityConfigId;
                const tokenUsage = state.metadata?.tokenUsage;
                const effectiveChatGroupId = options.chatGroupId ?? options.threadId ?? null;
                // Persist the group's title as the first user question (earliest row in this chat group).
                let chatGroupTitle = null;
                if (effectiveChatGroupId) {
                    const firstInGroup = await db
                        .select({ query: tables_1.argusChatHistoryTable.query })
                        .from(tables_1.argusChatHistoryTable)
                        .where((0, drizzle_orm_1.eq)(tables_1.argusChatHistoryTable.chatGroupId, effectiveChatGroupId))
                        .orderBy((0, drizzle_orm_1.asc)(tables_1.argusChatHistoryTable.createdAt))
                        .limit(1);
                    if (firstInGroup.length > 0) {
                        chatGroupTitle = firstInGroup[0]?.query ?? null;
                    }
                    else {
                        chatGroupTitle = query;
                    }
                }
                await db.insert(tables_1.argusChatHistoryTable).values({
                    id: chatHistoryId,
                    query,
                    result: response.answer,
                    type: String(domain),
                    userId: options.userId,
                    username: options.username,
                    orgId: options.orgId,
                    projectId: options.projectId,
                    applicationId,
                    securityConfigId,
                    traceId,
                    sessionId,
                    testRunId,
                    threadId: options.threadId,
                    contextSource: options.contextSource ?? null,
                    chatGroupId: effectiveChatGroupId,
                    chatGroupStatus: 'active',
                    chatGroupTitle,
                    filters: historyFilters,
                    usage: tokenUsage
                        ? {
                            total: typeof tokenUsage.total === 'number'
                                ? Math.round(tokenUsage.total)
                                : undefined,
                            prompt: typeof tokenUsage.prompt === 'number'
                                ? Math.round(tokenUsage.prompt)
                                : undefined,
                            completion: typeof tokenUsage.completion === 'number'
                                ? Math.round(tokenUsage.completion)
                                : undefined,
                        }
                        : null,
                });
                response.metadata = {
                    ...(response.metadata || {}),
                    chatId: chatHistoryId,
                    chatGroupId: effectiveChatGroupId ?? undefined,
                };
            }
            catch (dbError) {
                logger_1.default.warn(`Failed to save Argus chat history: ${dbError}`);
            }
            return response;
        }
        catch (error) {
            logger_1.default.error(`Argus ask error: ${error}`);
            throw error;
        }
    }
}
exports.ArgusService = ArgusService;
//# sourceMappingURL=argusService.js.map