import { getAllActiveServerNames, parseSecurityScanDetails, summarizeRecords, } from './db-aggregate.js';
import { loadAllRecordsInWindow } from './cost-timeseries.js';
import { parseWindowDays } from './time-buckets.js';
import { buildChartMeta } from './chart-meta.js';
import { getSemanticAuditStats } from '../ai/async-semantic-audit.js';
import { loadSemanticAuditRecordsAsync } from '../ai/semantic-audit-store.js';
import { getSecurityThreatQuarantine } from './security-threat-quarantine.js';
function scoreLabel(score) {
    if (score == null)
        return 'Unknown';
    if (score >= 85)
        return 'Strong';
    if (score >= 70)
        return 'Good';
    if (score >= 50)
        return 'Fair';
    return 'At risk';
}
function ruleToThreatType(rule, reason) {
    const r = `${rule || ''} ${reason || ''}`.toLowerCase();
    if (r.includes('semantic') || r.includes('prompt') || r.includes('injection')) {
        return 'Semantic Prompt Injection';
    }
    if (r.includes('sql'))
        return 'SQL Injection Attempt';
    if (r.includes('brute') || r.includes('auth'))
        return 'Brute Force Login';
    if (r.includes('xss'))
        return 'XSS Payload Detected';
    if (r.includes('privilege') || r.includes('escalation'))
        return 'Privilege Escalation';
    if (rule)
        return rule.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
    return 'Policy violation';
}
function severityFromRule(rule) {
    const r = (rule || '').toLowerCase();
    if (r.includes('semantic') || r.includes('secret') || r.includes('injection'))
        return 'critical';
    if (r.includes('shell') || r.includes('path') || r.includes('sql'))
        return 'high';
    if (r.includes('auth') || r.includes('brute'))
        return 'high';
    if (r.includes('warn'))
        return 'medium';
    return 'medium';
}
function pseudoSource(serverName, toolName) {
    const hash = [...`${serverName}:${toolName}`].reduce((s, c) => s + c.charCodeAt(0), 0);
    const octet = hash % 254 + 1;
    return `10.${(hash >> 8) % 255}.${octet % 255}.${(hash >> 4) % 255}`;
}
function threatIdFromRecord(r, index) {
    const ts = Date.parse(String(r.timestamp || ''));
    const n = Number.isFinite(ts) ? ts % 10000 : index;
    return `THR-${2840 + (n % 900) + index}`;
}
function blockThreatKey(r) {
    return `block:${r.serverName}:${r.toolName}:${r.timestamp || ''}`;
}
function buildThreatsFromRecords(blocked) {
    return blocked.slice(0, 20).map((r, i) => ({
        id: threatIdFromRecord(r, i),
        threatKey: blockThreatKey(r),
        type: ruleToThreatType(r.blockRule, r.blockReason),
        source: pseudoSource(r.serverName, r.toolName),
        severity: severityFromRule(r.blockRule),
        status: 'blocked',
    }));
}
async function buildThreatsFromSemantic(tenantId) {
    const records = await loadSemanticAuditRecordsAsync({ limit: 10, tenantId });
    return records
        .filter((r) => r.semanticAudit?.suspicious)
        .map((r, i) => ({
        id: `THR-S${2840 + i}`,
        threatKey: `semantic:${r.id}`,
        type: 'Semantic Prompt Injection',
        source: pseudoSource(r.serverName, r.toolName || 'unknown'),
        severity: (r.semanticAudit?.confidence ?? 0) >= 0.85 ? 'critical' : 'high',
        status: r.syncDecision?.action === 'block' ? 'blocked' : 'monitored',
    }));
}
function p50Latency(records) {
    const lat = records.map((r) => r.durationMs || 0).filter((n) => n > 0).sort((a, b) => a - b);
    if (!lat.length)
        return null;
    return lat[Math.floor(lat.length / 2)] ?? null;
}
export async function buildSecurityDashboard(db, tenantId, windowDaysInput, opts) {
    const windowDays = parseWindowDays(windowDaysInput);
    const semStats = getSemanticAuditStats();
    const empty = {
        available: false,
        windowDays,
        generatedAt: new Date().toISOString(),
        securityScore: null,
        scoreLabel: 'Unknown',
        layers: [
            { id: 'network', label: 'Network', status: 'alert' },
            { id: 'auth', label: 'Auth', status: 'alert' },
            { id: 'data', label: 'Data', status: 'alert' },
            { id: 'api', label: 'API', status: 'alert' },
        ],
        executiveSummary: ['Start the Guardian proxy and route MCP traffic to populate live threat data.'],
        threats: [],
        activeThreatCount: 0,
        semanticEngineActive: semStats.enabled,
        autoBlockOn: opts?.policyMode === 'block',
        auditLatencyMs: null,
        rbacPolicy: 'Defense-In-Depth',
        meta: buildChartMeta({
            windowDays,
            recordCount: 0,
            sparse: true,
            dataSources: [],
            emptyReason: 'No history database connected',
        }),
        emptyReason: 'No history database connected',
    };
    if (!db)
        return empty;
    const records = await loadAllRecordsInWindow(db, tenantId, windowDays);
    const sum = summarizeRecords(records);
    const blocked = records.filter((r) => r.blocked);
    const quarantine = getSecurityThreatQuarantine(tenantId);
    const suppressed = quarantine.quarantinedKeys();
    const semanticThreats = await buildThreatsFromSemantic(tenantId);
    const recordThreats = buildThreatsFromRecords(blocked);
    const seen = new Set();
    const threats = [];
    for (const t of [...semanticThreats, ...recordThreats]) {
        if (suppressed.has(t.threatKey))
            continue;
        const key = `${t.type}:${t.source}`;
        if (seen.has(key))
            continue;
        seen.add(key);
        threats.push(t);
        if (threats.length >= 12)
            break;
    }
    let manifestScore = null;
    let scanned = 0;
    let scoreSum = 0;
    const srvs = await getAllActiveServerNames(db, tenantId);
    for (const srv of srvs) {
        const sc = await db.getLatestSecurityScan(srv, tenantId);
        if (sc) {
            const details = parseSecurityScanDetails(sc);
            if (details?.score != null) {
                scoreSum += details.score;
                scanned++;
            }
        }
    }
    if (scanned > 0)
        manifestScore = Math.round(scoreSum / scanned);
    const passRate = sum.total > 0 ? (sum.passed / sum.total) * 100 : 100;
    const blockPenalty = sum.total > 0 ? Math.min(25, (sum.blocked / sum.total) * 100) : 0;
    const semanticPenalty = semStats.flagged > 0 ? Math.min(15, semStats.flagged * 2) : 0;
    const base = manifestScore ?? Math.round(passRate);
    const securityScore = Math.max(0, Math.min(100, Math.round(base - blockPenalty - semanticPenalty)));
    const dataAlert = semStats.flagged > 0 || semanticThreats.some((t) => t.status === 'monitored');
    const networkSecure = sum.total > 0 && sum.passed / sum.total > 0.5;
    const apiSecure = sum.total > 0;
    const authSecure = process.env.DASHBOARD_AUTH_DISABLED !== 'true' || !!process.env.DASHBOARD_JWT_SECRET;
    const layers = [
        { id: 'network', label: 'Network', status: networkSecure ? 'secure' : 'alert' },
        { id: 'auth', label: 'Auth', status: authSecure ? 'secure' : 'alert' },
        { id: 'data', label: 'Data', status: dataAlert ? 'alert' : 'secure' },
        { id: 'api', label: 'API', status: apiSecure ? 'secure' : 'alert' },
    ];
    const authIntegrity = sum.total > 0 ? Math.round((sum.passed / sum.total) * 1000) / 10 : 100;
    return {
        available: true,
        windowDays,
        generatedAt: new Date().toISOString(),
        securityScore,
        scoreLabel: scoreLabel(securityScore),
        layers,
        executiveSummary: [
            sum.blocked > 0
                ? `${sum.blocked} threats blocked in last ${windowDays >= 1 ? Math.round(windowDays * 24) + 'h' : 'window'}`
                : 'No blocks recorded in the selected window',
            `Auth layer integrity: ${authIntegrity}%`,
        ],
        threats,
        activeThreatCount: threats.filter((t) => t.status !== 'resolved').length,
        semanticEngineActive: semStats.enabled,
        autoBlockOn: opts?.policyMode === 'block',
        auditLatencyMs: p50Latency(records),
        rbacPolicy: 'Defense-In-Depth',
        meta: buildChartMeta({
            windowDays,
            recordCount: records.length,
            dataSources: ['history.db', 'semantic-audit-store'],
        }),
        emptyReason: records.length === 0 ? 'No traffic in window' : undefined,
    };
}
//# sourceMappingURL=security-dashboard.js.map