import { Logger } from '../utils/logger.js';
function writeJson(res, status, data) {
    res.writeHead(status, {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    });
    res.end(JSON.stringify(data, null, 2));
}
async function readBody(req) {
    return new Promise((resolve) => {
        let data = '';
        req.on('data', (chunk) => { data += chunk.toString(); });
        req.on('end', () => {
            try {
                resolve(data ? JSON.parse(data) : {});
            }
            catch {
                resolve({});
            }
        });
    });
}
/**
 * Dashboard API handlers — exposes all AI engine data to the dashboard UI.
 * Each handler follows the (req, res) → Promise<void> pattern for the HTTP server.
 */
export class DashboardApi {
    opts;
    constructor(opts) {
        this.opts = opts;
    }
    async handle(req, res, url, method) {
        const prefix = '/api/ai/';
        if (!url.startsWith(prefix))
            return false;
        const path = url.slice(prefix.length);
        try {
            switch (path) {
                case 'suggestions':
                    await this.getSuggestions(res);
                    break;
                case 'baselines':
                    await this.getBaselines(res);
                    break;
                case 'insights':
                    await this.getInsights(res);
                    break;
                case 'report':
                    await this.getReport(res);
                    break;
                case 'learning-state':
                    this.getLearningState(res);
                    break;
                case 'policy/assist':
                    if (method === 'POST')
                        await this.postPolicyAssist(req, res);
                    else
                        writeJson(res, 405, { error: 'Method not allowed' });
                    break;
                case 'threat/feed':
                    if (method === 'POST')
                        await this.postThreatFeed(req, res);
                    else
                        writeJson(res, 405, { error: 'Method not allowed' });
                    break;
                case 'cost/breakdown':
                    await this.getCostBreakdown(res);
                    break;
                case 'logs/export':
                    await this.getLogExport(res);
                    break;
                default:
                    writeJson(res, 404, { error: `Unknown API: ${path}` });
                    break;
            }
            return true;
        }
        catch (err) {
            Logger.error(`[DashboardApi] ${path} failed: ${err?.message}`);
            writeJson(res, 500, { error: err?.message || 'Internal server error' });
            return true;
        }
    }
    // ── AI Endpoints ────────────────────────────────────────────────────
    async getSuggestions(res) {
        const snapshot = await this.opts.collector.collectAll(this.opts.servers);
        this.opts.baselineLearner.learn(snapshot.callRecords);
        const suggestions = [];
        // Baseline anomalies
        const anomalySuggestions = this.opts.baselineLearner.suggestRules(snapshot.callRecords);
        for (const s of anomalySuggestions) {
            suggestions.push({
                id: `baseline-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
                rule: s.rule,
                confidence: this.opts.selfImprovement.adjustConfidence(s.confidence, 'baseline'),
                reason: s.reason,
                source: 'baseline',
            });
        }
        // Cost optimization
        const inputPrice = 0.435 / 1000000;
        const outputPrice = 0.87 / 1000000;
        const costPatterns = await this.opts.engine['costOptimizer']?.analyzePatterns(snapshot.callRecords, inputPrice, outputPrice);
        const burstMap = await this.opts.engine['costOptimizer']?.detectBurstPatterns(snapshot.callRecords);
        const costSuggestions = this.opts.engine['costOptimizer']?.suggestRules(costPatterns || [], burstMap) || [];
        // Cross-layer insights
        const insights = this.opts.patternRecognizer.analyze(snapshot);
        for (const i of insights) {
            if (i.suggestedRule) {
                suggestions.push({
                    id: `pattern-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
                    rule: i.suggestedRule,
                    confidence: this.opts.selfImprovement.adjustConfidence(i.confidence, 'pattern'),
                    reason: i.description,
                    source: 'pattern',
                });
            }
        }
        // Sort by confidence
        suggestions.sort((a, b) => b.confidence - a.confidence);
        writeJson(res, 200, {
            suggestions: suggestions.slice(0, 20),
            total: suggestions.length,
            autoApplyThreshold: this.opts.selfImprovement.getAdaptiveThreshold(),
            timestamp: new Date().toISOString(),
        });
    }
    async getBaselines(res) {
        const baselines = this.opts.baselineLearner.getAllBaselines();
        writeJson(res, 200, {
            baselines,
            count: baselines.length,
            timestamp: new Date().toISOString(),
        });
    }
    async getInsights(res) {
        const snapshot = await this.opts.collector.collectAll(this.opts.servers);
        const insights = this.opts.patternRecognizer.analyze(snapshot);
        const temporal = this.opts.patternRecognizer.detectTemporalPatterns(snapshot);
        const relationships = this.opts.patternRecognizer.analyzeServerRelationships(snapshot);
        writeJson(res, 200, {
            crossLayerInsights: insights,
            temporalPatterns: temporal,
            serverRelationships: Object.fromEntries(relationships),
            timestamp: new Date().toISOString(),
        });
    }
    async getReport(res) {
        const snapshot = await this.opts.collector.collectAll(this.opts.servers);
        this.opts.baselineLearner.learn(snapshot.callRecords);
        const baselines = this.opts.baselineLearner.getAllBaselines();
        const insights = this.opts.patternRecognizer.analyze(snapshot);
        const temporal = this.opts.patternRecognizer.detectTemporalPatterns(snapshot);
        const report = this.opts.reporter.generateFullReport(snapshot, baselines, insights, temporal, [], this.opts.selfImprovement.getState(), []);
        writeJson(res, 200, report);
    }
    getLearningState(res) {
        const state = this.opts.selfImprovement.getState();
        writeJson(res, 200, {
            adaptiveThreshold: state.adaptiveThreshold,
            truePositiveRate: state.truePositiveRate,
            falsePositiveRate: state.falsePositiveRate,
            moduleWeights: state.moduleWeights,
            outcomesTracked: state.outcomes.length,
            recentOutcomes: state.outcomes.slice(-20),
            timestamp: new Date().toISOString(),
        });
    }
    async postPolicyAssist(req, res) {
        const body = await readBody(req);
        const goal = body.goal;
        if (!goal) {
            writeJson(res, 400, { error: 'Missing "goal" field' });
            return;
        }
        const availableTools = body.tools || [];
        const assist = this.opts.policyAssist.generateRule(goal, availableTools.length > 0 ? availableTools : undefined);
        if (!assist) {
            writeJson(res, 400, { error: 'Could not parse goal into a rule' });
            return;
        }
        writeJson(res, 200, {
            suggestion: {
                rule: assist.rule,
                confidence: this.opts.selfImprovement.adjustConfidence(assist.confidence, 'assist'),
                reason: assist.reason,
                goal: assist.goal,
            },
            yaml: this.opts.policyAssist.toYAML(assist.rule),
        });
    }
    async postThreatFeed(req, res) {
        const body = await readBody(req);
        const feedPath = body.path;
        if (!feedPath) {
            writeJson(res, 400, { error: 'Missing "path" field for threat feed' });
            return;
        }
        const entries = this.opts.threatIntel.fetchFeed(feedPath);
        const newEntries = this.opts.threatIntel.diffFeed(entries);
        const threatSuggestions = this.opts.threatIntel.generateRules(newEntries);
        writeJson(res, 200, {
            totalEntries: entries.length,
            newEntries: newEntries.length,
            rulesGenerated: threatSuggestions.length,
            suggestions: threatSuggestions.map(s => ({
                rule: s.rule,
                confidence: this.opts.selfImprovement.adjustConfidence(s.confidence, 'threat'),
                reason: s.reason,
            })),
            timestamp: new Date().toISOString(),
        });
    }
    // ── Real Data Endpoints ──────────────────────────────────────────────
    async getCostBreakdown(res) {
        const { createRequire } = await import('node:module');
        const Database = createRequire(import.meta.url)('better-sqlite3');
        const inputPrice = 0.435 / 1000000;
        const outputPrice = 0.87 / 1000000;
        const breakdown = {};
        let totalCost = 0;
        // Read LIVE data from proxy databases
        for (const dbName of ['proxy-github', 'proxy-filesystem']) {
            try {
                const proxyDb = new Database('/private/tmp/' + dbName + '.db');
                const rows = proxyDb.prepare('SELECT * FROM call_records ORDER BY id').all();
                proxyDb.close();
                if (rows.length === 0)
                    continue;
                const tools = {};
                let srvInput = 0, srvOutput = 0, srvCalls = 0;
                const srvName = dbName.replace('proxy-', '') + '-proxy';
                for (const r of rows) {
                    const req = r.request_tokens || 0;
                    const resp = r.response_tokens || 0;
                    srvInput += req;
                    srvOutput += resp;
                    srvCalls++;
                    const tn = r.tool_name || 'unknown';
                    if (!tools[tn])
                        tools[tn] = { calls: 0, input: 0, output: 0, cost: 0 };
                    tools[tn].calls++;
                    tools[tn].input += req;
                    tools[tn].output += resp;
                    tools[tn].cost += req * inputPrice + resp * outputPrice;
                }
                const srvCost = srvInput * inputPrice + srvOutput * outputPrice;
                totalCost += srvCost;
                breakdown[srvName] = { calls: srvCalls, inputTokens: srvInput, outputTokens: srvOutput, cost: srvCost, tools };
            }
            catch { }
        }
        // Also read from dashboard DB
        try {
            const servers = await this.opts.db.getDistinctScannedServers();
            for (const srv of servers) {
                if (breakdown[srv])
                    continue;
                const records = await this.opts.db.getCallRecordsForServer(srv);
                if (records.length === 0)
                    continue;
                const tools = {};
                let srvInput = 0, srvOutput = 0, srvCalls = 0;
                for (const r of records) {
                    const req = r.requestTokens || 0;
                    const resp = r.responseTokens || 0;
                    srvInput += req;
                    srvOutput += resp;
                    srvCalls++;
                    if (!tools[r.toolName])
                        tools[r.toolName] = { calls: 0, input: 0, output: 0, cost: 0 };
                    tools[r.toolName].calls++;
                    tools[r.toolName].input += req;
                    tools[r.toolName].output += resp;
                    tools[r.toolName].cost += req * inputPrice + resp * outputPrice;
                }
                const srvCost = srvInput * inputPrice + srvOutput * outputPrice;
                totalCost += srvCost;
                breakdown[srv] = { calls: srvCalls, inputTokens: srvInput, outputTokens: srvOutput, cost: srvCost, tools };
            }
        }
        catch { }
        writeJson(res, 200, { breakdown, totalCost, pricingModel: 'deepseek-v4-pro', inputPricePerM: 0.435, outputPricePerM: 0.87, timestamp: new Date().toISOString() });
    }
    async getLogExport(res) {
        const db = this.opts.db;
        const servers = await db.getDistinctScannedServers();
        const allRecords = [];
        for (const srv of servers) {
            const records = await db.getCallRecordsForServer(srv);
            allRecords.push(...records);
        }
        // SIEM-compatible JSON output
        writeJson(res, 200, {
            format: 'siem-json',
            generator: 'mcp-guardian',
            generatedAt: new Date().toISOString(),
            totalRecords: allRecords.length,
            records: allRecords.map(r => ({
                timestamp: r.timestamp,
                serverName: r.serverName,
                toolName: r.toolName,
                requestTokens: r.requestTokens,
                responseTokens: r.responseTokens,
                totalTokens: r.totalTokens,
                durationMs: r.durationMs,
            })),
        });
    }
}
//# sourceMappingURL=dashboard-api.js.map