"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildEnterpriseRuntimeDashboard = buildEnterpriseRuntimeDashboard;
const modelRouterSingleton_1 = require("../agent/core/modelRouterSingleton");
const enterpriseDb_1 = require("./enterpriseDb");
const enterpriseRepository_1 = require("./enterpriseRepository");
const traceProcessorLeaseStore_1 = require("./traceProcessorLeaseStore");
const workingTraceProcessor_1 = require("./workingTraceProcessor");
function isActiveLeaseState(state) {
    return state !== 'released' && state !== 'failed';
}
function addCount(counts, key, by = 1) {
    counts[key] = (counts[key] ?? 0) + by;
}
function processorQueueLength(processor) {
    const worker = processor.sqlWorker;
    return worker ? worker.queuedP0 + worker.queuedP1 + worker.queuedP2 : 0;
}
function processorBelongsToScopedLeases(processor, traceIds, leaseIds) {
    if (processor.leaseId && leaseIds.has(processor.leaseId))
        return true;
    return traceIds.has(processor.traceId);
}
function queueLengthForLease(lease, processors) {
    if (lease.mode === 'isolated') {
        return processors
            .filter(processor => processor.leaseId === lease.id)
            .reduce((sum, processor) => sum + processorQueueLength(processor), 0);
    }
    return processors
        .filter(processor => processor.traceId === lease.traceId && (processor.leaseMode ?? 'shared') === 'shared')
        .reduce((sum, processor) => sum + processorQueueLength(processor), 0);
}
function summarizeQueueTotals(processors) {
    const totals = processors.reduce((sum, processor) => {
        const worker = processor.sqlWorker;
        if (!worker)
            return sum;
        sum.queuedP0 += worker.queuedP0;
        sum.queuedP1 += worker.queuedP1;
        sum.queuedP2 += worker.queuedP2;
        return sum;
    }, { queuedP0: 0, queuedP1: 0, queuedP2: 0 });
    return {
        ...totals,
        total: totals.queuedP0 + totals.queuedP1 + totals.queuedP2,
    };
}
function listRecentAgentEvents(db, scope, limit) {
    return db.prepare(`
    SELECT run_id, cursor, event_type, created_at
    FROM agent_events
    WHERE tenant_id = ?
      AND workspace_id = ?
    ORDER BY created_at DESC, cursor DESC
    LIMIT ?
  `).all(scope.tenantId, scope.workspaceId, limit)
        .map(row => ({
        runId: row.run_id,
        cursor: row.cursor,
        eventType: row.event_type,
        createdAt: row.created_at,
    }));
}
function listRecentAuditEvents(db, scope, limit) {
    return db.prepare(`
    SELECT action, resource_type, resource_id, actor_user_id, workspace_id, created_at
    FROM audit_events
    WHERE tenant_id = ?
      AND (workspace_id = ? OR workspace_id IS NULL)
    ORDER BY created_at DESC, id DESC
    LIMIT ?
  `).all(scope.tenantId, scope.workspaceId, limit)
        .map(row => ({
        action: row.action,
        resourceType: row.resource_type,
        resourceId: row.resource_id,
        actorUserId: row.actor_user_id,
        workspaceId: row.workspace_id,
        createdAt: row.created_at,
    }));
}
function getModelUsageSnapshot(deps) {
    if (deps.modelRouterUsageProvider)
        return deps.modelRouterUsageProvider();
    const router = (0, modelRouterSingleton_1.getSharedModelRouter)();
    return {
        stats: router.getStats(),
        totalCost: router.getTotalCost(),
    };
}
function buildEnterpriseRuntimeDashboard(context, deps = {}) {
    const scope = (0, enterpriseRepository_1.repositoryScopeFromRequestContext)(context);
    const generatedAtMs = deps.now?.() ?? Date.now();
    const eventLimit = Math.max(1, Math.min(100, Math.floor(deps.eventLimit ?? 20)));
    const leases = deps.listLeases
        ? deps.listLeases(scope)
        : (0, traceProcessorLeaseStore_1.getTraceProcessorLeaseStore)().listLeases(scope);
    const traceIds = new Set(leases.map(lease => lease.traceId));
    const leaseIds = new Set(leases.map(lease => lease.id));
    const traceStats = deps.traceProcessorStatsProvider
        ? deps.traceProcessorStatsProvider()
        : workingTraceProcessor_1.TraceProcessorFactory.getStats();
    const processors = traceStats.processors
        .filter(processor => processorBelongsToScopedLeases(processor, traceIds, leaseIds));
    const activeLeases = leases.filter(lease => isActiveLeaseState(lease.state));
    const countsByState = {};
    const countsByHolderType = {};
    for (const lease of leases) {
        addCount(countsByState, lease.state);
        for (const holder of lease.holders) {
            addCount(countsByHolderType, holder.holderType);
        }
    }
    let recentAgentEvents = [];
    let recentAuditEvents = [];
    const db = deps.openDb ? deps.openDb() : (0, enterpriseDb_1.openEnterpriseDb)();
    try {
        recentAgentEvents = listRecentAgentEvents(db, scope, eventLimit);
        recentAuditEvents = listRecentAuditEvents(db, scope, eventLimit);
    }
    finally {
        db.close();
    }
    const modelUsage = getModelUsageSnapshot(deps);
    const llmTotals = Object.values(modelUsage.stats).reduce((sum, stats) => {
        sum.calls += stats.calls;
        sum.tokens += stats.tokens;
        sum.failures += stats.failures;
        return sum;
    }, { calls: 0, tokens: 0, failures: 0 });
    const queueTotals = summarizeQueueTotals(processors);
    const observedProcessorRssBytes = processors.reduce((sum, processor) => {
        return sum + (processor.rssBytes && processor.rssBytes > 0 ? processor.rssBytes : 0);
    }, 0);
    return {
        success: true,
        generatedAt: new Date(generatedAtMs).toISOString(),
        scope: {
            tenantId: scope.tenantId,
            workspaceId: scope.workspaceId,
            userId: scope.userId ?? context.userId,
        },
        leases: {
            count: leases.length,
            activeCount: activeLeases.length,
            holderCount: leases.reduce((sum, lease) => sum + lease.holderCount, 0),
            totalRssBytes: leases.reduce((sum, lease) => sum + (lease.rssBytes ?? 0), 0),
            countsByState,
            countsByHolderType,
            items: leases.map(lease => ({
                id: lease.id,
                traceId: lease.traceId,
                mode: lease.mode,
                state: lease.state,
                rssBytes: lease.rssBytes,
                heartbeatAt: lease.heartbeatAt,
                expiresAt: lease.expiresAt,
                queueLength: queueLengthForLease(lease, processors),
                holderCount: lease.holderCount,
                holderTypes: Array.from(new Set(lease.holders.map(holder => holder.holderType))),
            })),
        },
        processors: {
            count: processors.length,
            traceIds: Array.from(new Set(processors.map(processor => processor.traceId))),
            queueTotals,
            rssTotals: {
                observedProcessorRssBytes,
                unknownRssProcessorCount: processors.filter(processor => processor.rssBytes === null).length,
            },
            ramBudget: traceStats.ramBudget,
            items: processors.map(processor => ({
                kind: processor.kind,
                processorId: processor.processorId,
                traceId: processor.traceId,
                leaseId: processor.leaseId,
                leaseMode: processor.leaseMode,
                status: processor.status,
                activeQueries: processor.activeQueries,
                rssBytes: processor.rssBytes,
                startupRssBytes: processor.startupRssBytes,
                peakRssBytes: processor.peakRssBytes,
                lastRssSampleAt: processor.lastRssSampleAt,
                rssSampleSource: processor.rssSampleSource,
                sqlWorker: processor.sqlWorker,
            })),
        },
        events: {
            recentAgentEvents,
            recentAuditEvents,
        },
        llmCost: {
            totalCost: modelUsage.totalCost,
            totalCalls: llmTotals.calls,
            totalTokens: llmTotals.tokens,
            totalFailures: llmTotals.failures,
            byModel: modelUsage.stats,
        },
    };
}
//# sourceMappingURL=enterpriseRuntimeDashboardService.js.map