const { getDatabase } = require('../config/database');
const https = require('https');

// In-memory CVE cache — refresh every hour
let cveCache = { ts: 0, data: [] };

function nvdGet(path) {
    return new Promise((resolve, reject) => {
        const req = https.get({
            hostname: 'services.nvd.nist.gov',
            path,
            headers: { 'User-Agent': 'IT-Nexus-TV/1.0' },
        }, (res) => {
            let raw = '';
            res.on('data', c => raw += c);
            res.on('end', () => { try { resolve(JSON.parse(raw)); } catch (e) { reject(e); } });
        });
        req.on('error', reject);
        setTimeout(() => { req.destroy(); reject(new Error('timeout')); }, 15000);
    });
}

function mapCVE(v) {
    const cve = v.cve;
    const m31 = cve.metrics?.cvssMetricV31 || [];
    const m30 = cve.metrics?.cvssMetricV30 || [];
    const m2  = cve.metrics?.cvssMetricV2  || [];
    const m = m31[0] || m30[0] || m2[0];
    const score = m?.cvssData?.baseScore || 0;
    let sevRaw = (m?.cvssData?.baseSeverity || m?.baseSeverity || 'medium').toLowerCase();
    if (!['critical','high','medium','low'].includes(sevRaw)) {
        sevRaw = score >= 9 ? 'critical' : score >= 7 ? 'high' : score >= 4 ? 'medium' : 'low';
    }
    const desc = cve.descriptions?.find(d => d.lang === 'en')?.value || '';
    const sentence = desc.split(/\.\s/)[0].replace(/\s+/g, ' ').trim();
    const title = sentence.length > 110 ? sentence.substring(0, 110) + '…' : sentence || cve.id;
    const pub = new Date(cve.published);
    const diffH = Math.round((Date.now() - pub.getTime()) / 3600000);
    const published = diffH < 1 ? '< 1 Std.' : diffH < 24 ? `${diffH} Std.` : `${Math.round(diffH / 24)} Tag${Math.round(diffH / 24) !== 1 ? 'e' : ''}`;
    let vendor = 'NVD';
    const cpe = cve.configurations?.[0]?.nodes?.[0]?.cpeMatch?.[0]?.criteria || '';
    const cm = cpe.match(/cpe:2\.3:[ao]:([^:]+):/);
    if (cm) vendor = cm[1].charAt(0).toUpperCase() + cm[1].slice(1).replace(/_/g, ' ');
    return { id: cve.id, sev: sevRaw, cvss: score, title, vendor, published };
}

async function fetchCVEs() {
    try {
        // Step 1: get total count (fast, no filters)
        const r1 = await nvdGet('/rest/json/cves/2.0?resultsPerPage=1');
        const total = r1.totalResults || 0;
        if (total < 5) return null;

        // Step 2: fetch the last ~60 entries (newest published CVEs)
        const startIndex = Math.max(0, total - 60);
        const r2 = await nvdGet(`/rest/json/cves/2.0?resultsPerPage=60&startIndex=${startIndex}`);
        const vulns = (r2.vulnerabilities || []).reverse(); // newest first

        const mapped = vulns.map(mapCVE).filter(c => c.cvss >= 5);
        // Prefer high/critical, then fill with medium
        const high = mapped.filter(c => ['critical','high'].includes(c.sev));
        const medium = mapped.filter(c => c.sev === 'medium');
        const merged = [...high, ...medium].slice(0, 5);

        return merged.length >= 3 ? merged : null;
    } catch {
        return null;
    }
}

async function getStats(req, res) {
    try {
        const db = getDatabase();
        const now = Date.now();
        const fifteenMin = 15 * 60 * 1000;

        // Agents
        const agents = db.prepare('SELECT hostname, last_checkin, cpu_usage_percent, ram_total_gb, ram_used_gb, bitlocker_status FROM monitoring_agents').all();
        const agentList = agents.map(a => {
            const ms = a.last_checkin ? new Date(a.last_checkin + (a.last_checkin.includes('Z') ? '' : 'Z')).getTime() : 0;
            const ram_usage_percent = a.ram_total_gb > 0 ? Math.round((a.ram_used_gb / a.ram_total_gb) * 100) : 0;
            return { ...a, ram_usage_percent, online: ms && (now - ms) < fifteenMin };
        });
        const online = agentList.filter(a => a.online).length;

        // Tickets
        const ticketStats = db.prepare(`
            SELECT
                COUNT(*) as total,
                SUM(CASE WHEN status NOT IN ('closed','resolved') THEN 1 ELSE 0 END) as open,
                SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as inProgress,
                SUM(CASE WHEN date(created_at) = date('now') AND status IN ('closed','resolved') THEN 1 ELSE 0 END) as closedToday,
                SUM(CASE WHEN priority = 'critical' AND status NOT IN ('closed','resolved') THEN 1 ELSE 0 END) as critical,
                SUM(CASE WHEN priority = 'high' AND status NOT IN ('closed','resolved') THEN 1 ELSE 0 END) as high,
                SUM(CASE WHEN priority = 'medium' AND status NOT IN ('closed','resolved') THEN 1 ELSE 0 END) as medium,
                SUM(CASE WHEN priority = 'low' AND status NOT IN ('closed','resolved') THEN 1 ELSE 0 END) as low
            FROM tickets
        `).get();

        // Patch overview
        const patchStats = db.prepare(`
            SELECT
                COUNT(*) as total,
                SUM(CASE WHEN windows_updates_pending = 0 THEN 1 ELSE 0 END) as compliant,
                SUM(CASE WHEN windows_updates_pending > 0 THEN 1 ELSE 0 END) as warnings,
                SUM(COALESCE(windows_updates_pending, 0)) as total_pending_updates
            FROM monitoring_agents
        `).get();

        // Last security report
        const lastSecReport = db.prepare('SELECT * FROM security_reports ORDER BY created_at DESC LIMIT 1').get();

        // Ticket trend last 7 days
        const perDay7 = db.prepare(`
            SELECT date(created_at) as day, COUNT(*) as count
            FROM tickets
            WHERE created_at >= date('now', '-7 days')
            GROUP BY date(created_at)
            ORDER BY day ASC
        `).all();

        res.json({
            status: 'success',
            data: {
                agentList: agentList.map(a => ({
                    hostname: a.hostname,
                    last_checkin: a.last_checkin,
                    cpu_usage_percent: a.cpu_usage_percent,
                    ram_usage_percent: a.ram_usage_percent,
                    bitlocker_status: a.bitlocker_status,
                })),
                monitoring: { total: agents.length, online, offline: agents.length - online },
                tickets: ticketStats,
                patch: patchStats,
                lastSecReport: lastSecReport || null,
                ticketMetrics: { perDay7: perDay7.map(r => r.count) },
            },
        });
    } catch (err) {
        res.status(500).json({ status: 'error', message: err.message });
    }
}

async function getCVEs(req, res) {
    const now = Date.now();
    if (now - cveCache.ts < 3600000 && cveCache.data.length >= 3) {
        return res.json({ status: 'success', data: cveCache.data, cached: true });
    }
    const fresh = await fetchCVEs();
    if (fresh) {
        cveCache = { ts: now, data: fresh };
        return res.json({ status: 'success', data: fresh, cached: false });
    }
    if (cveCache.data.length >= 3) {
        return res.json({ status: 'success', data: cveCache.data, cached: true });
    }
    res.status(503).json({ status: 'error', message: 'CVE-Feed nicht erreichbar' });
}

module.exports = { getStats, getCVEs };
