"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.countTraces = countTraces;
exports.queryTraces = queryTraces;
exports.queryTraceById = queryTraceById;
exports.countSpans = countSpans;
exports.querySpans = querySpans;
exports.querySpanById = querySpanById;
exports.countSessions = countSessions;
exports.querySessions = querySessions;
exports.querySessionById = querySessionById;
const clickhouseService_1 = require("../../clickhouseService");
const pulseService_1 = require("../../pulseService");
const logger_1 = __importDefault(require("../../../../logger"));
/**
 * Build WHERE clause for ClickHouse queries
 */
function buildWhereClause(conditions) {
    return conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
}
/**
 * Build WHERE clause for eval results filters
 */
function buildEvalResultsWhereClause(filters, traceIds, sessionIds) {
    const conditions = [];
    // Trace IDs or Session IDs filter
    if (traceIds && traceIds.length > 0) {
        const traceIdsStr = traceIds.map((id) => `'${id}'`).join(',');
        conditions.push(`trace_id IN (${traceIdsStr})`);
    }
    else if (sessionIds && sessionIds.length > 0) {
        const sessionIdsStr = sessionIds.map((id) => `'${id}'`).join(',');
        conditions.push(`sessionId IN (${sessionIdsStr})`);
    }
    // Always require trace_id or sessionId to be not null
    if (traceIds && traceIds.length > 0) {
        conditions.push(`trace_id IS NOT NULL AND trace_id != ''`);
    }
    else if (sessionIds && sessionIds.length > 0) {
        conditions.push(`sessionId IS NOT NULL AND sessionId != ''`);
    }
    if (!filters) {
        return conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
    }
    // Success filter (pass/fail)
    if (filters.success !== undefined) {
        const successValue = typeof filters.success === 'boolean' ? (filters.success ? 1 : 0) : filters.success;
        conditions.push(`success = ${successValue}`);
    }
    // Cost filter
    if (filters.cost) {
        if (filters.cost.min !== undefined) {
            conditions.push(`cost >= ${filters.cost.min}`);
        }
        if (filters.cost.max !== undefined) {
            conditions.push(`cost <= ${filters.cost.max}`);
        }
    }
    // Score filter
    if (filters.score) {
        if (filters.score.min !== undefined) {
            conditions.push(`score >= ${filters.score.min}`);
        }
        if (filters.score.max !== undefined) {
            conditions.push(`score <= ${filters.score.max}`);
        }
    }
    // Failure reason filter
    if (filters.failureReason) {
        conditions.push(`failure_reason = '${filters.failureReason.replace(/'/g, "''")}'`);
    }
    // Is redteam filter
    if (filters.isRedteam !== undefined) {
        const redteamValue = filters.isRedteam ? 1 : 0;
        conditions.push(`is_redteam = ${redteamValue}`);
    }
    // Provider filter
    if (filters.provider) {
        conditions.push(`provider = '${filters.provider.replace(/'/g, "''")}'`);
    }
    // Application ID filter
    if (filters.applicationId) {
        conditions.push(`application_id = '${filters.applicationId.replace(/'/g, "''")}'`);
    }
    // Metric name filter (check in named_scores JSON)
    if (filters.metricName) {
        // Check if metric name exists in named_scores JSON object
        // named_scores is a JSON object, so we check if the key exists
        conditions.push(`JSONHas(named_scores, '${filters.metricName.replace(/'/g, "''")}')`);
    }
    return conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
}
/**
 * Fetch eval results for traces
 */
async function fetchEvalResultsForTraces(traceIds, filters) {
    if (!traceIds || traceIds.length === 0) {
        return new Map();
    }
    const whereClause = buildEvalResultsWhereClause(filters, traceIds);
    const query = `
    SELECT
      trace_id,
      id,
      sessionId,
      eval_id,
      prompt_idx,
      test_idx,
      test_case,
      prompt,
      prompt_id,
      application_id,
      provider,
      latency_ms,
      cost,
      response,
      error,
      failure_reason,
      success,
      score,
      grading_result,
      named_scores,
      metadata,
      is_redteam,
      project_id,
      created_at,
      updated_at
    FROM ${pulseService_1.EVAL_RESULTS_TABLE_NAME}
    ${whereClause}
  `;
    try {
        const results = await clickhouseService_1.clickHouseService.query(query);
        const evalMap = new Map();
        if (results && results.length > 0) {
            results.forEach((row) => {
                const traceId = row.trace_id;
                if (!evalMap.has(traceId)) {
                    evalMap.set(traceId, []);
                }
                evalMap.get(traceId).push({
                    id: row.id,
                    trace_id: row.trace_id,
                    sessionId: row.sessionId,
                    eval_id: row.eval_id,
                    prompt_idx: row.prompt_idx,
                    test_idx: row.test_idx,
                    test_case: row.test_case,
                    prompt: row.prompt,
                    prompt_id: row.prompt_id,
                    application_id: row.application_id,
                    provider: row.provider,
                    latency_ms: row.latency_ms,
                    cost: row.cost,
                    response: row.response,
                    error: row.error,
                    failure_reason: row.failure_reason,
                    success: row.success,
                    score: row.score,
                    grading_result: row.grading_result,
                    named_scores: row.named_scores,
                    metadata: row.metadata,
                    is_redteam: row.is_redteam,
                    project_id: row.project_id,
                    created_at: row.created_at,
                    updated_at: row.updated_at,
                });
            });
        }
        return evalMap;
    }
    catch (error) {
        logger_1.default.error(`Error fetching eval results for traces: ${error}`);
        return new Map();
    }
}
/**
 * Fetch eval results for sessions
 */
async function fetchEvalResultsForSessions(sessionIds, filters) {
    if (!sessionIds || sessionIds.length === 0) {
        return new Map();
    }
    const whereClause = buildEvalResultsWhereClause(filters, undefined, sessionIds);
    const query = `
    SELECT
      sessionId,
      id,
      trace_id,
      eval_id,
      prompt_idx,
      test_idx,
      test_case,
      prompt,
      prompt_id,
      application_id,
      provider,
      latency_ms,
      cost,
      response,
      error,
      failure_reason,
      success,
      score,
      grading_result,
      named_scores,
      metadata,
      is_redteam,
      project_id,
      created_at,
      updated_at
    FROM ${pulseService_1.EVAL_RESULTS_TABLE_NAME}
    ${whereClause}
  `;
    try {
        const results = await clickhouseService_1.clickHouseService.query(query);
        const evalMap = new Map();
        if (results && results.length > 0) {
            results.forEach((row) => {
                const sessionId = row.sessionId;
                if (!evalMap.has(sessionId)) {
                    evalMap.set(sessionId, []);
                }
                evalMap.get(sessionId).push({
                    id: row.id,
                    trace_id: row.trace_id,
                    sessionId: row.sessionId,
                    eval_id: row.eval_id,
                    prompt_idx: row.prompt_idx,
                    test_idx: row.test_idx,
                    test_case: row.test_case,
                    prompt: row.prompt,
                    prompt_id: row.prompt_id,
                    application_id: row.application_id,
                    provider: row.provider,
                    latency_ms: row.latency_ms,
                    cost: row.cost,
                    response: row.response,
                    error: row.error,
                    failure_reason: row.failure_reason,
                    success: row.success,
                    score: row.score,
                    grading_result: row.grading_result,
                    named_scores: row.named_scores,
                    metadata: row.metadata,
                    is_redteam: row.is_redteam,
                    project_id: row.project_id,
                    created_at: row.created_at,
                    updated_at: row.updated_at,
                });
            });
        }
        return evalMap;
    }
    catch (error) {
        logger_1.default.error(`Error fetching eval results for sessions: ${error}`);
        return new Map();
    }
}
/**
 * Build ORDER BY clause
 * @param sorting - Sorting configuration
 * @param useAlias - Whether to use column aliases (for GROUP BY queries)
 */
function buildOrderBy(sorting, useAlias = false) {
    if (!sorting) {
        return useAlias ? 'ORDER BY timestamp DESC' : 'ORDER BY Timestamp DESC';
    }
    const fieldMap = {
        timestamp: useAlias ? 'timestamp' : 'Timestamp',
        duration: useAlias ? 'duration' : 'Duration',
        status: useAlias ? 'status' : 'StatusCode',
        createdAt: useAlias ? 'timestamp' : 'Timestamp',
    };
    const field = fieldMap[sorting.field] || (useAlias ? 'timestamp' : 'Timestamp');
    // Be defensive: some callers may omit `order` or pass a non-string at runtime.
    const orderRaw = sorting?.order;
    const orderUpper = (typeof orderRaw === 'string' ? orderRaw : 'desc').toUpperCase();
    const safeOrder = orderUpper === 'ASC' ? 'ASC' : 'DESC';
    return `ORDER BY ${field} ${safeOrder}`;
}
/**
 * Get count of traces matching the query (without fetching full data)
 */
async function countTraces(params) {
    try {
        const conditions = [];
        if (params.applicationId) {
            conditions.push(`t.ServiceName = '${params.applicationId}'`);
        }
        if (params.traceId) {
            conditions.push(`t.TraceId = '${params.traceId}'`);
        }
        if (params.traceIds && params.traceIds.length > 0) {
            const traceIdsStr = params.traceIds.map((id) => `'${id}'`).join(',');
            conditions.push(`t.TraceId IN (${traceIdsStr})`);
        }
        if (params.dateRange) {
            conditions.push(`t.Timestamp >= parseDateTimeBestEffort('${params.dateRange.start}')`);
            conditions.push(`t.Timestamp <= parseDateTimeBestEffort('${params.dateRange.end}')`);
        }
        if (params.status) {
            if (params.status === 'error' || params.status === 'failed') {
                conditions.push(`t.StatusCode = 'STATUS_CODE_ERROR'`);
            }
            else if (params.status === 'success') {
                conditions.push(`t.StatusCode = 'STATUS_CODE_OK'`);
            }
        }
        const whereClause = buildWhereClause(conditions);
        const query = `
      SELECT count(DISTINCT t.TraceId) as count
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} t
      ${whereClause}
    `;
        logger_1.default.debug(`Argus countTraces: ${query}`);
        const results = await clickhouseService_1.clickHouseService.query(query);
        return results && results.length > 0 ? Number(results[0].count || 0) : 0;
    }
    catch (error) {
        logger_1.default.error(`Error counting traces: ${error}`);
        throw error;
    }
}
/**
 * Query traces from ClickHouse
 */
async function queryTraces(params) {
    try {
        const conditions = [];
        // Project/Application filter
        if (params.projectId) {
            // Note: You may need to join with applications table or use a different approach
            // This is a placeholder - adjust based on your schema
        }
        if (params.applicationId) {
            conditions.push(`t.ServiceName = '${params.applicationId}'`);
        }
        // Trace ID filter
        if (params.traceId) {
            conditions.push(`t.TraceId = '${params.traceId}'`);
        }
        if (params.traceIds && params.traceIds.length > 0) {
            const traceIdsStr = params.traceIds.map((id) => `'${id}'`).join(',');
            conditions.push(`t.TraceId IN (${traceIdsStr})`);
        }
        // Date range filter
        if (params.dateRange) {
            conditions.push(`t.Timestamp >= parseDateTimeBestEffort('${params.dateRange.start}')`);
            conditions.push(`t.Timestamp <= parseDateTimeBestEffort('${params.dateRange.end}')`);
        }
        // Status filter
        if (params.status) {
            if (params.status === 'error' || params.status === 'failed') {
                conditions.push(`t.StatusCode = 'STATUS_CODE_ERROR'`);
            }
            else if (params.status === 'success') {
                conditions.push(`t.StatusCode = 'STATUS_CODE_OK'`);
            }
        }
        // Exclude infrastructure / HTTP spans whose name starts with POST
        conditions.push(`t.SpanName NOT LIKE 'POST%'`);
        // Build query
        const whereClause = buildWhereClause(conditions);
        const orderBy = buildOrderBy(params.sorting, false); // Use raw column names (no aggregation)
        const limit = params.limit || 100;
        const offset = params.offset || 0;
        const query = `
      SELECT
        t.TraceId as traceId,
        t.Timestamp as timestamp,
        t.Duration as duration,
        t.StatusCode as status,
        t.SpanId as spanId,
        t.SpanName as name,
        t.SpanKind as spanKind,
        t.ParentSpanId as parentSpanId,
        t.ResourceAttributes as resourceAttributes,
        t.SpanAttributes as spanAttributes,
        t.\`Events.Timestamp\` as eventsTimestamp,
        t.\`Events.Attributes\` as eventsAttributes
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} t
      ${whereClause}
      ${orderBy}
      LIMIT ${limit}
      OFFSET ${offset}
    `;
        logger_1.default.debug(`Argus queryTraces: ${query}`);
        const results = await clickhouseService_1.clickHouseService.query(query);
        // Ensure traceIds are unique
        const traceIds = Array.from(new Set(results.map((trace) => trace.traceId || trace.id).filter(Boolean)));
        const traceResults = {};
        let evalMap;
        const shouldFetchEval = params.includeEvaluationResults === true;
        if (traceIds && traceIds.length > 0 && shouldFetchEval) {
            evalMap = await fetchEvalResultsForTraces(traceIds, params.evalResultsFilters);
        }
        for (const traceId of traceIds) {
            const traces = results.filter((trace) => traceId === trace.traceId || traceId === trace.id);
            if (!traceResults[traceId]) {
                traceResults[traceId] = {
                    traceId,
                    resourceAttributes: traces[0].resourceAttributes,
                    spans: [],
                    ...(evalMap && shouldFetchEval ? { evalResults: evalMap.get(traceId) || [] } : {}),
                };
            }
            traceResults[traceId].spans.push(...traces.map((trace) => ({
                spanId: trace.spanId,
                spanName: trace.name,
                spanKind: trace.spanKind,
                parentSpanId: trace.parentSpanId,
                spanAttributes: trace.spanAttributes,
                eventsAttributes: trace.eventsAttributes,
                eventsTimestamp: trace.eventsTimestamp,
                StatusCode: trace.status,
                duration: trace.duration,
            })));
        }
        const result = Object.values(traceResults);
        return result;
    }
    catch (error) {
        logger_1.default.error(`Error querying traces: ${error}`);
        throw error;
    }
}
/**
 * Query a single trace by ID
 */
async function queryTraceById(params) {
    try {
        // Note: Multiple records can exist for a single traceId, each with different span data
        // Fetch ALL records for this traceId, not just the first one
        const query = `
      SELECT
        t.TraceId as traceId,
        t.Timestamp as timestamp,
        t.Duration as duration,
        t.StatusCode as status,
        t.SpanId as spanId,
        t.SpanName as name,
        t.SpanKind as spanKind,
        t.ParentSpanId as parentSpanId,
        t.ResourceAttributes as resourceAttributes,
        t.SpanAttributes as spanAttributes,
        t.\`Events.Timestamp\` as eventsTimestamp,
        t.\`Events.Attributes\` as eventsAttributes
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} t
      WHERE t.TraceId = '${params.traceId}' AND t.SpanName NOT LIKE 'POST%'
      ORDER BY t.Timestamp ASC
    `;
        const results = await clickhouseService_1.clickHouseService.query(query);
        if (results && results.length > 0) {
            let evalResults = [];
            if (params.includeEvaluationResults === true) {
                const evalMap = await fetchEvalResultsForTraces([params.traceId], params.evalResultsFilters);
                const traceEvalResults = evalMap.get(params.traceId) || [];
                evalResults = traceEvalResults.map((evalResult) => ({
                    id: evalResult.id,
                    evalId: evalResult.eval_id,
                    success: evalResult.success,
                    failureReason: evalResult.failure_reason,
                    error: evalResult.error,
                    prompt: evalResult.prompt.raw || evalResult.prompt,
                    response: evalResult.response.output || evalResult.response,
                    score: evalResult.score,
                    cost: evalResult.cost,
                    latencyMs: evalResult.latency_ms,
                    traceId: evalResult.trace_id,
                    sessionId: evalResult.session_id,
                    applicationId: evalResult.application_id,
                    gradingResult: evalResult.grading_result,
                    isRedteam: evalResult.is_redteam,
                    provider: evalResult.provider,
                }));
            }
            const result = {
                traceId: results[0].traceId,
                resourceAttributes: results[0].resourceAttributes,
                ...(evalResults.length > 0 ? { evalResults } : {}),
                spans: results.map((trace) => ({
                    spanId: trace.spanId,
                    spanName: trace.name,
                    spanKind: trace.spanKind,
                    parentSpanId: trace.parentSpanId,
                    spanAttributes: trace.spanAttributes,
                    eventsAttributes: trace.eventsAttributes,
                    eventsTimestamp: trace.eventsTimestamp,
                    status: trace.status,
                    duration: trace.duration,
                    timestamp: trace.timestamp,
                })),
            };
            return result;
        }
        return [];
    }
    catch (error) {
        logger_1.default.error(`Error querying trace by ID: ${error}`);
        throw error;
    }
}
/**
 * Get count of spans matching the query (without fetching full data)
 */
async function countSpans(params) {
    try {
        const conditions = [];
        if (params.applicationId) {
            conditions.push(`s.ServiceName = '${params.applicationId}'`);
        }
        if (params.spanId) {
            conditions.push(`s.SpanId = '${params.spanId}'`);
        }
        if (params.spanIds && params.spanIds.length > 0) {
            const spanIdsStr = params.spanIds.map((id) => `'${id}'`).join(',');
            conditions.push(`s.SpanId IN (${spanIdsStr})`);
        }
        if (params.traceId) {
            conditions.push(`s.TraceId = '${params.traceId}'`);
        }
        if (params.dateRange) {
            conditions.push(`s.Timestamp >= parseDateTimeBestEffort('${params.dateRange.start}')`);
            conditions.push(`s.Timestamp <= parseDateTimeBestEffort('${params.dateRange.end}')`);
        }
        if (params.status) {
            if (params.status === 'error') {
                conditions.push(`s.StatusCode = 'STATUS_CODE_ERROR'`);
            }
            else if (params.status === 'success') {
                conditions.push(`s.StatusCode = 'STATUS_CODE_OK'`);
            }
        }
        const whereClause = buildWhereClause(conditions);
        const query = `
      SELECT count(*) as count
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} s
      ${whereClause}
    `;
        logger_1.default.debug(`Argus countSpans: ${query}`);
        const results = await clickhouseService_1.clickHouseService.query(query);
        return results && results.length > 0 ? Number(results[0].count || 0) : 0;
    }
    catch (error) {
        logger_1.default.error(`Error counting spans: ${error}`);
        throw error;
    }
}
/**
 * Query spans from ClickHouse
 */
async function querySpans(params) {
    try {
        const conditions = [];
        if (params.applicationId) {
            conditions.push(`s.ServiceName = '${params.applicationId}'`);
        }
        if (params.spanId) {
            conditions.push(`s.SpanId = '${params.spanId}'`);
        }
        if (params.spanIds && params.spanIds.length > 0) {
            const spanIdsStr = params.spanIds.map((id) => `'${id}'`).join(',');
            conditions.push(`s.SpanId IN (${spanIdsStr})`);
        }
        if (params.traceId) {
            conditions.push(`s.TraceId = '${params.traceId}'`);
        }
        if (params.dateRange) {
            conditions.push(`s.Timestamp >= parseDateTimeBestEffort('${params.dateRange.start}')`);
            conditions.push(`s.Timestamp <= parseDateTimeBestEffort('${params.dateRange.end}')`);
        }
        if (params.status) {
            if (params.status === 'error') {
                conditions.push(`s.StatusCode = 'STATUS_CODE_ERROR'`);
            }
            else if (params.status === 'success') {
                conditions.push(`s.StatusCode = 'STATUS_CODE_OK'`);
            }
        }
        // Exclude infrastructure / HTTP spans whose name starts with POST
        conditions.push(`s.SpanName NOT LIKE 'POST%'`);
        const whereClause = buildWhereClause(conditions);
        const orderBy = buildOrderBy(params.sorting);
        const limit = params.limit || 100;
        const offset = params.offset || 0;
        const query = `
      SELECT
        s.SpanId as spanId,
        s.TraceId as traceId,
        s.Timestamp as timestamp,
        s.Duration as duration,
        s.StatusCode as status,
        s.SpanName as name,
        s.ParentSpanId as parentSpanId,
        s.SpanKind as spanKind,
        s.SpanAttributes as spanAttributes,
        s.StatusMessage as statusMessage,
        s.\`Events.Timestamp\` as eventsTimestamp,
        s.\`Events.Attributes\` as eventsAttributes
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} s
      ${whereClause}
      ${orderBy}
      LIMIT ${limit}
      OFFSET ${offset}
    `;
        logger_1.default.debug(`Argus querySpans: ${query}`);
        const results = await clickhouseService_1.clickHouseService.query(query);
        if (results && results.length > 0) {
            const traceIds = [...new Set(results.map((span) => span.traceId).filter(Boolean))];
            let evalMap;
            const shouldFetchEval = params.includeEvaluationResults === true;
            if (traceIds.length > 0 && shouldFetchEval) {
                evalMap = await fetchEvalResultsForTraces(traceIds, params.evalResultsFilters);
            }
            // Attach eval results to spans (empty array when not explicitly requested)
            results.forEach((span) => {
                const traceId = span.traceId;
                if (evalMap && shouldFetchEval) {
                    const traceEvalResults = evalMap.get(traceId) || [];
                    span.evalResults = traceEvalResults.map((evalResult) => ({
                        id: evalResult.id,
                        evalId: evalResult.eval_id,
                        success: evalResult.success,
                        failureReason: evalResult.failure_reason,
                        error: evalResult.error,
                        prompt: evalResult.prompt.raw || evalResult.prompt,
                        response: evalResult.response.output || evalResult.response,
                        score: evalResult.score,
                        cost: evalResult.cost,
                        latencyMs: evalResult.latency_ms,
                        traceId: evalResult.trace_id,
                        sessionId: evalResult.session_id,
                        applicationId: evalResult.application_id,
                        gradingResult: evalResult.grading_result,
                        isRedteam: evalResult.is_redteam,
                        provider: evalResult.provider,
                    }));
                }
            });
        }
        return results || [];
    }
    catch (error) {
        logger_1.default.error(`Error querying spans: ${error}`);
        throw error;
    }
}
/**
 * Query a single span by ID
 */
async function querySpanById(params) {
    try {
        // Note: Each spanId has only one record in the table
        const query = `
      SELECT
        s.SpanId as spanId,
        s.TraceId as traceId,
        s.Timestamp as timestamp,
        s.Duration as duration,
        s.StatusCode as status,
        s.SpanName as name,
        s.ParentSpanId as parentSpanId,
        s.SpanKind as spanKind,
        s.SpanAttributes as spanAttributes,
        s.StatusMessage as statusMessage,
        s.\`Events.Timestamp\` as eventsTimestamp,
        s.\`Events.Attributes\` as eventsAttributes
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} s
      WHERE s.SpanId = '${params.spanId}'
      LIMIT 1
    `;
        const results = await clickhouseService_1.clickHouseService.query(query);
        if (results && results.length > 0) {
            const span = results[0];
            // Fetch eval results separately only when includeEvaluationResults is true
            if (span.TraceId && params.includeEvaluationResults === true) {
                const evalMap = await fetchEvalResultsForTraces([span.TraceId], params.evalResultsFilters);
                span.evalResults = evalMap.get(span.TraceId) || [];
            }
            return span;
        }
        return null;
    }
    catch (error) {
        logger_1.default.error(`Error querying span by ID: ${error}`);
        throw error;
    }
}
/**
 * Query sessions from ClickHouse
 * Note: Sessions might be stored differently - adjust based on your schema
 */
/**
 * Get count of sessions matching the query (without fetching full data)
 */
async function countSessions(params) {
    try {
        const conditions = [];
        if (params.applicationId) {
            conditions.push(`t.ServiceName = '${params.applicationId}'`);
        }
        if (params.sessionId) {
            conditions.push(`t.SpanAttributes['session.id'] = '${params.sessionId}'`);
        }
        if (params.sessionIds && params.sessionIds.length > 0) {
            const sessionIdsStr = params.sessionIds.map((id) => `'${id}'`).join(',');
            conditions.push(`t.SpanAttributes['session.id'] IN (${sessionIdsStr})`);
        }
        if (params.dateRange) {
            conditions.push(`t.Timestamp >= parseDateTimeBestEffort('${params.dateRange.start}')`);
            conditions.push(`t.Timestamp <= parseDateTimeBestEffort('${params.dateRange.end}')`);
        }
        if (params.status) {
            if (params.status === 'failed') {
                conditions.push(`t.StatusCode = 'STATUS_CODE_ERROR'`);
            }
            else if (params.status === 'active' || params.status === 'completed') {
                conditions.push(`t.StatusCode = 'STATUS_CODE_OK'`);
            }
        }
        // Ensure session.id exists
        conditions.push(`t.SpanAttributes['session.id'] IS NOT NULL`);
        conditions.push(`t.SpanAttributes['session.id'] != ''`);
        const whereClause = buildWhereClause(conditions);
        const query = `
      SELECT count(DISTINCT t.SpanAttributes['session.id']) as count
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} t
      ${whereClause}
    `;
        logger_1.default.debug(`Argus countSessions: ${query}`);
        const results = await clickhouseService_1.clickHouseService.query(query);
        return results && results.length > 0 ? Number(results[0].count || 0) : 0;
    }
    catch (error) {
        logger_1.default.error(`Error counting sessions: ${error}`);
        throw error;
    }
}
async function querySessions(params) {
    try {
        // For now, sessions might be derived from traces
        // Adjust this based on your actual session storage
        const conditions = [];
        if (params.applicationId) {
            conditions.push(`t.ServiceName = '${params.applicationId}'`);
        }
        if (params.sessionId) {
            // Adjust based on how sessions are stored
            conditions.push(`t.SpanAttributes['session.id'] = '${params.sessionId}'`);
        }
        if (params.sessionIds && params.sessionIds.length > 0) {
            const sessionIdsStr = params.sessionIds.map((id) => `'${id}'`).join(',');
            conditions.push(`t.SpanAttributes['session.id'] IN (${sessionIdsStr})`);
        }
        if (params.dateRange) {
            conditions.push(`t.Timestamp >= parseDateTimeBestEffort('${params.dateRange.start}')`);
            conditions.push(`t.Timestamp <= parseDateTimeBestEffort('${params.dateRange.end}')`);
        }
        // Exclude infrastructure / HTTP spans whose name starts with POST
        conditions.push(`t.SpanName NOT LIKE 'POST%'`);
        const whereClause = buildWhereClause(conditions);
        const orderBy = buildOrderBy(params.sorting, true); // Use alias for GROUP BY query
        const limit = params.limit || 100;
        const offset = params.offset || 0;
        // Group by session ID to get unique sessions
        const query = `
      SELECT
        t.SpanAttributes['session.id'] as sessionId,
        min(t.Timestamp) as timestamp,
        any(t.ServiceName) as applicationId,
        any(t.TraceId) as traceId,
        any(t.SpanId) as spanId,
        any(t.ParentSpanId) as parentSpanId,
        any(t.SpanName) as name,
        any(t.StatusCode) as status,
        any(t.Duration) as duration,
        any(t.StatusMessage) as statusMessage,
        any(t.ResourceAttributes) as resourceAttributes,
        any(t.SpanAttributes) as spanAttributes,
        any(t.\`Events.Timestamp\`) as eventsTimestamp
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} t
      ${whereClause}
      GROUP BY t.SpanAttributes['session.id']
      ${orderBy}
      LIMIT ${limit}
      OFFSET ${offset}
    `;
        logger_1.default.debug(`Argus querySessions: ${query}`);
        const results = await clickhouseService_1.clickHouseService.query(query);
        if (results && results.length > 0) {
            const sessionIds = results.map((session) => session.sessionId || session.id).filter(Boolean);
            let evalMap;
            const shouldFetchEval = params.includeEvaluationResults === true;
            if (sessionIds.length > 0 && shouldFetchEval) {
                evalMap = await fetchEvalResultsForSessions(sessionIds, params.evalResultsFilters);
            }
            // Attach eval results to sessions (empty array when not explicitly requested)
            results.forEach((session) => {
                const sessionId = session.sessionId || session.id;
                if (evalMap && shouldFetchEval) {
                    session.evalResults = evalMap.get(sessionId) || [];
                }
            });
        }
        return results || [];
    }
    catch (error) {
        logger_1.default.error(`Error querying sessions: ${error}`);
        throw error;
    }
}
/**
 * Query a single session by ID
 */
async function querySessionById(params) {
    try {
        // Note: Multiple records can exist for a single sessionId, each with different trace/span data
        // Fetch ALL records for this sessionId, not just the first one
        const query = `
      SELECT
        t.SpanId as spanId,
        t.TraceId as traceId,
        t.Timestamp as timestamp,
        t.Duration as duration,
        t.StatusCode as status,
        t.SpanName as name,
        t.ParentSpanId as parentSpanId,
        t.SpanKind as spanKind,
        t.SpanAttributes as spanAttributes,
        t.StatusMessage as statusMessage,
        t.\`Events.Timestamp\` as eventsTimestamp,
        t.\`Events.Attributes\` as eventsAttributes,
        t.ResourceAttributes as resourceAttributes
      FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME} t
      WHERE t.SpanAttributes['session.id'] = '${params.sessionId}'
      ORDER BY t.Timestamp ASC
    `;
        const results = await clickhouseService_1.clickHouseService.query(query);
        if (results && results.length > 0) {
            let evalResults = [];
            if (params.includeEvaluationResults === true) {
                const evalMap = await fetchEvalResultsForSessions([params.sessionId], params.evalResultsFilters);
                evalResults = evalMap.get(params.sessionId) || [];
            }
            // Attach eval results to each session record
            return results.map((session) => ({
                ...session,
                ...(evalResults.length > 0 ? { evalResults } : {}),
            }));
        }
        return [];
    }
    catch (error) {
        logger_1.default.error(`Error querying session by ID: ${error}`);
        throw error;
    }
}
//# sourceMappingURL=clickhouseQueries.js.map