"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DescribeDataModelController = void 0;
exports.buildDescribeDataModel = buildDescribeDataModel;
const logger_1 = __importDefault(require("../../../../logger"));
const clickhouseService_1 = require("../../../services/clickhouseService");
const pulseService_1 = require("../../../services/pulseService");
function buildDescribeDataModel(options) {
    const focusEntity = options.spanId
        ? 'span'
        : options.traceId
            ? 'trace'
            : options.sessionId
                ? 'session'
                : undefined;
    return {
        service: {
            name: options.serviceName,
            version: options.version,
            environment: options.environment,
        },
        time_range: {
            earliest_event_time: options.earliestEventTime,
            latest_event_time: options.latestEventTime,
            retention_days: options.retentionDays,
        },
        supported_conventions: {
            otel_traces: true,
            otel_logs: true,
            otel_metrics: true,
            otel_genai: true,
            otel_mcp_semantics: true,
            openinference_compatible: true,
        },
        entities: [
            {
                name: 'session',
                description: focusEntity === 'session'
                    ? 'Logical end-user interaction that can span multiple traces. In the current context, this describes the session that owns the provided sessionId (and any traces/spans/evals attached to it).'
                    : 'Logical end-user interaction that can span multiple traces.',
                primary_key: 'session_id',
                aliases: ['conversation', 'thread'],
                common_filters: [
                    'session_id',
                    'tenant_id',
                    'app_id',
                    'environment',
                    'status',
                    'user_id',
                    'start_time',
                    'end_time',
                    'duration_ms',
                    'has_security_findings',
                    'evaluation.avg_score',
                ],
            },
            {
                name: 'trace',
                description: focusEntity === 'trace'
                    ? 'Distributed execution path for a single request or workflow segment inside a session. In the current context, this describes the trace identified by the provided traceId and how its spans and evaluations hang off of it.'
                    : 'Distributed execution path for a single request or workflow segment inside a session.',
                primary_key: 'trace_id',
                common_filters: [
                    'trace_id',
                    'session_id',
                    'root_span_id',
                    'status',
                    'service.name',
                    'operation_name',
                    'duration_ms',
                    'error.type',
                ],
            },
            {
                name: 'span',
                description: focusEntity === 'span'
                    ? 'Single unit of work inside a trace. In the current context, this describes the span identified by the provided spanId and its relationship to its parent trace, session, and any attached evaluations or security findings.'
                    : 'Single unit of work inside a trace.',
                primary_key: 'span_id',
                common_filters: [
                    'span_id',
                    'trace_id',
                    'session_id',
                    'parent_span_id',
                    'name',
                    'step_type',
                    'status',
                    'duration_ms',
                    'gen_ai.operation.name',
                    'gen_ai.request.model',
                    'gen_ai.provider.name',
                ],
            },
            {
                name: 'evaluation',
                description: focusEntity
                    ? 'Quality/evaluation result linked to a span, trace, or session. In the current context, this captures evaluation rows that attach to the focused entity (session/trace/span) via entity_id or trace_id/sessionId.'
                    : 'Quality/evaluation result linked to a span, trace, or session.',
                primary_key: 'evaluation_id',
                common_filters: [
                    'evaluation_id',
                    'entity_type',
                    'entity_id',
                    'metric',
                    'score',
                    'threshold',
                    'status',
                    'model',
                    'prompt_version',
                ],
            },
            {
                name: 'security_finding',
                description: focusEntity
                    ? 'Security or guardrail event linked to a span, trace, or session. In the current context, this captures security findings that are attached to the focused entity (session/trace/span) via entity_id or trace_id/sessionId.'
                    : 'Security or guardrail event linked to a span, trace, or session.',
                primary_key: 'finding_id',
                common_filters: [
                    'finding_id',
                    'entity_type',
                    'entity_id',
                    'category',
                    'severity',
                    'confidence',
                    'action_taken',
                    'phase',
                ],
            },
            {
                name: 'log',
                description: 'Application/system log record correlated to trace_id and span_id when available.',
                primary_key: 'log_id',
                common_filters: [
                    'log_id',
                    'trace_id',
                    'span_id',
                    'session_id',
                    'service.name',
                    'level',
                    'timestamp',
                ],
            },
        ],
        normalized_step_types: [
            {
                name: 'CHAIN',
                description: 'Top-level orchestration or workflow span.',
            },
            {
                name: 'LLM',
                description: 'Model inference/chat/completion call.',
            },
            /*   {
                name: 'RETRIEVER',
                description: 'Vector search or knowledge retrieval step.',
              },
              {
                name: 'RERANKER',
                description: 'Ranking or reranking step after retrieval.',
              }, */
            {
                name: 'TOOL',
                description: 'External or internal tool/function/API call.',
            },
            {
                name: 'AGENT',
                description: 'Agent planning/decision span.',
            },
            {
                name: 'GUARDRAIL',
                description: 'Input/output safety, policy, or validation check.',
            },
            {
                name: 'EVALUATOR',
                description: 'LLM quality, relevance, groundedness, or rubric evaluation.',
            },
            {
                name: 'EMBEDDING',
                description: 'Embedding generation step.',
            },
            {
                name: 'MCP',
                description: 'Model Context Protocol operation or tool interaction.',
            },
            {
                name: 'OTHER',
                description: 'Unclassified span.',
            },
        ],
        entity_relationships: [
            {
                from: 'session',
                to: 'trace',
                relationship: 'one_to_many',
                description: 'A session can contain multiple traces.',
            },
            {
                from: 'trace',
                to: 'span',
                relationship: 'one_to_many',
                description: 'A trace contains many spans.',
            },
            {
                from: 'span',
                to: 'log',
                relationship: 'one_to_many',
                description: 'Logs may be correlated to a span.',
            },
            {
                from: 'session',
                to: 'evaluation',
                relationship: 'one_to_many',
                description: 'Evaluations can be attached directly to the session or to child spans/traces.',
            },
            {
                from: 'session',
                to: 'security_finding',
                relationship: 'one_to_many',
                description: 'Security findings can be attached directly to the session or to child spans/traces.',
            },
        ],
        query_capabilities: {
            filter_operators: [
                'eq',
                'neq',
                'in',
                'not_in',
                'contains',
                'starts_with',
                'ends_with',
                'gt',
                'gte',
                'lt',
                'lte',
                'exists',
            ],
            sort_supported: true,
            pagination_supported: true,
            timeseries_supported: true,
            aggregations_supported: [
                'count',
                'sum',
                'avg',
                'min',
                'max',
                'p50',
                'p95',
                'p99',
            ],
            full_text_search_supported: true,
        },
        important_dimensions: [
            {
                key: 'tenant_id',
                type: 'string',
                description: 'Customer tenant identifier.',
            },
            {
                key: 'app_id',
                type: 'string',
                description: 'Application identifier.',
            },
            {
                key: 'environment',
                type: 'string',
                description: 'Environment such as prod, staging, dev.',
            },
            {
                key: 'service.name',
                type: 'string',
                description: 'OTel service name.',
            },
            {
                key: 'gen_ai.conversation.id',
                type: 'string',
                description: 'Conversation/session correlation field when available.',
            },
            {
                key: 'gen_ai.operation.name',
                type: 'string',
                description: 'GenAI operation such as chat, generate_content, embeddings.',
            },
            {
                key: 'gen_ai.provider.name',
                type: 'string',
                description: 'LLM provider name.',
            },
            {
                key: 'gen_ai.request.model',
                type: 'string',
                description: 'Requested model.',
            },
            {
                key: 'gen_ai.response.model',
                type: 'string',
                description: 'Actual serving model.',
            },
            {
                key: 'gen_ai.usage.input_tokens',
                type: 'number',
                description: 'Input token count.',
            },
            {
                key: 'gen_ai.usage.output_tokens',
                type: 'number',
                description: 'Output token count.',
            },
            {
                key: 'mcp.method.name',
                type: 'string',
                description: 'MCP method name when MCP spans are captured.',
            },
        ],
        privacy_and_redaction: {
            llm_input_capture: 'configurable',
            llm_output_capture: 'configurable',
            pii_redaction_supported: true,
            redaction_policies: [
                'none',
                'mask_pii',
                'mask_secrets',
                'mask_pii_and_secrets',
            ],
        },
        examples: {
            session_lookup: {
                entity: 'session',
                filter: {
                    session_id: options.sessionId ?? 'sess_9f3a2c',
                },
            },
            slow_llm_spans: {
                entity: 'span',
                filter: {
                    step_type: 'LLM',
                    'gen_ai.request.model': 'gpt-4.1',
                    duration_ms: {
                        gte: 3000,
                    },
                    ...(options.traceId ? { trace_id: options.traceId } : {}),
                    ...(options.spanId ? { span_id: options.spanId } : {}),
                },
                sort: [
                    {
                        field: 'duration_ms',
                        order: 'desc',
                    },
                ],
            },
            prompt_injection_findings: {
                entity: 'security_finding',
                filter: {
                    category: 'prompt_injection',
                    severity: ['medium', 'high'],
                    ...(options.sessionId ? { session_id: options.sessionId } : {}),
                    ...(options.traceId ? { trace_id: options.traceId } : {}),
                },
            },
        },
    };
}
async function getTimeRangeForContext(params) {
    const { traceId, sessionId, spanId } = params;
    const now = new Date();
    const fallbackEarliest = new Date(now);
    fallbackEarliest.setDate(fallbackEarliest.getDate() - 30);
    // If no specific context is provided, just return the 30-day window
    if (!traceId && !sessionId && !spanId) {
        return {
            earliest_event_time: fallbackEarliest.toISOString(),
            latest_event_time: now.toISOString(),
            retention_days: 30,
        };
    }
    const safe = (value) => value.replace(/'/g, "''");
    const conditions = [];
    if (traceId) {
        conditions.push(`TraceId = '${safe(traceId)}'`);
    }
    if (sessionId) {
        conditions.push(`(SpanAttributes['session.id'] = '${safe(sessionId)}' OR SessionId = '${safe(sessionId)}')`);
    }
    if (spanId) {
        conditions.push(`SpanId = '${safe(spanId)}'`);
    }
    const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
    const query = `
    SELECT 
      toString(min(Timestamp)) AS earliest,
      toString(max(Timestamp)) AS latest
    FROM ${pulseService_1.OTEL_TRACES_TABLE_NAME}
    ${whereClause}
  `;
    try {
        const results = await clickhouseService_1.clickHouseService.query(query);
        const earliestStr = results?.[0]?.earliest;
        const latestStr = results?.[0]?.latest;
        if (!earliestStr || !latestStr) {
            return {
                earliest_event_time: fallbackEarliest.toISOString(),
                latest_event_time: now.toISOString(),
                retention_days: 30,
            };
        }
        const earliest = new Date(earliestStr);
        const latest = new Date(latestStr);
        if (Number.isNaN(earliest.getTime()) || Number.isNaN(latest.getTime())) {
            return {
                earliest_event_time: fallbackEarliest.toISOString(),
                latest_event_time: now.toISOString(),
                retention_days: 30,
            };
        }
        const diffMs = latest.getTime() - earliest.getTime();
        const retentionDays = Math.max(1, Math.round(diffMs / (1000 * 60 * 60 * 24)));
        return {
            earliest_event_time: earliest.toISOString(),
            latest_event_time: latest.toISOString(),
            retention_days: retentionDays,
        };
    }
    catch (error) {
        logger_1.default.error(`describe_data_model time range error: ${error}`);
        return {
            earliest_event_time: fallbackEarliest.toISOString(),
            latest_event_time: now.toISOString(),
            retention_days: 30,
        };
    }
}
class DescribeDataModelController {
    /**
     * GET /api/argus/tools/describe-data-model
     * Returns supported entities, time range, retention, conventions, and field catalog
     * for the current project, optionally scoped by traceId/sessionId/spanId.
     */
    static async describe(req, res) {
        try {
            const { traceId, sessionId, spanId } = req.query;
            const timeRange = await getTimeRangeForContext({
                traceId,
                sessionId,
                spanId,
            });
            const data = buildDescribeDataModel({
                serviceName: 'Ask Argus',
                version: '1.0.0',
                environment: process.env.NODE_ENV || 'production',
                earliestEventTime: timeRange.earliest_event_time,
                latestEventTime: timeRange.latest_event_time,
                retentionDays: timeRange.retention_days,
                traceId,
                sessionId,
                spanId,
            });
            res.json({
                success: true,
                data,
            });
        }
        catch (error) {
            logger_1.default.error(`describe_data_model error: ${error}`);
            res.status(500).json({
                success: false,
                message: error instanceof Error ? error.message : 'Internal server error',
            });
        }
    }
}
exports.DescribeDataModelController = DescribeDataModelController;
//# sourceMappingURL=describeDataModelController.js.map