"use client";

import { useEffect, useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import api from '../../../lib/api';
import { Vulnerability, Asset } from '../../../types';
import {
    ArrowLeftIcon,
    ShieldExclamationIcon,
    ServerIcon,
    CalendarIcon,
    UserCircleIcon,
    LinkIcon,
    DocumentTextIcon
} from '@heroicons/react/24/outline';
import Link from 'next/link';

interface VulnDetail extends Vulnerability {
    asset?: Asset;
    assigned_user_name?: string;
    assigned_group_name?: string;
}

// Linux-kernel CVEs report their "fix" as an upstream git commit hash
// (e.g. 7713bd320ed4fc3d08a22...) rather than a Debian package version —
// raw it looks like garbage in the "Fixed in" cell. Detect a hex hash
// (no version separators) and show a short, labelled form instead.
function formatFixedVersion(v?: string | null): string {
    if (!v) return '';
    const s = v.trim();
    if (/^[0-9a-f]{12,64}$/i.test(s) && !/[.:~_+]/.test(s)) {
        return `upstream commit ${s.slice(0, 12)}`;
    }
    return s;
}

// AI remediation (OpenRouter). Self-contained: checks whether the feature
// is configured, then generates OS-aware fix guidance on demand.
// Copy-to-clipboard button for code blocks.
function CopyButton({ text }: { text: string }) {
    const [copied, setCopied] = useState(false);
    return (
        <button
            onClick={async () => {
                // navigator.clipboard only exists in a secure context (HTTPS or
                // localhost). Over plain http://<ip> it's undefined → fall back
                // to a temp-textarea + execCommand so Copy still works.
                let ok = false;
                try {
                    if (navigator.clipboard?.writeText) {
                        await navigator.clipboard.writeText(text);
                        ok = true;
                    }
                } catch { /* fall through */ }
                if (!ok) {
                    try {
                        const ta = document.createElement('textarea');
                        ta.value = text;
                        ta.style.position = 'fixed';
                        ta.style.opacity = '0';
                        document.body.appendChild(ta);
                        ta.focus(); ta.select();
                        ok = document.execCommand('copy');
                        document.body.removeChild(ta);
                    } catch { /* give up */ }
                }
                if (ok) { setCopied(true); setTimeout(() => setCopied(false), 1500); }
            }}
            className="absolute top-2 right-2 text-[10px] font-mono px-2 py-1 rounded bg-gray-700/80 text-gray-100 hover:bg-gray-600"
        >
            {copied ? '✓ Copied' : 'Copy'}
        </button>
    );
}

// Render a small subset of Markdown: fenced code blocks (with copy button),
// **bold**, `inline code`, #/## headings, and - bullet lists. Good enough
// for LLM remediation output without pulling in a markdown dependency.
function inlineFmt(s: string, keyBase: string) {
    // Handle <br> first (LLMs emit it in table cells / steps) so it renders
    // as a line break instead of literal text — and WITHOUT splitting the
    // markdown line, which would corrupt table rows.
    const brParts = s.split(/(<br\s*\/?>)/gi);
    return brParts.map((bp, bi) => {
        if (/^<br/i.test(bp)) return <br key={`${keyBase}-br-${bi}`} />;
        // split on **bold** and `code`, keep delimiters
        const parts = bp.split(/(\*\*[^*]+\*\*|`[^`]+`)/g);
        return parts.map((p, i) => {
            const k = `${keyBase}-${bi}-${i}`;
            if (/^\*\*[^*]+\*\*$/.test(p)) return <strong key={k}>{p.slice(2, -2)}</strong>;
            if (/^`[^`]+`$/.test(p)) return <code key={k} className="px-1 py-0.5 rounded bg-gray-100 text-pink-700 text-[13px] font-mono">{p.slice(1, -1)}</code>;
            return <span key={k}>{p}</span>;
        });
    });
}

const _isRow = (l: string) => /^\s*\|.*\|\s*$/.test(l);
const _isSep = (l: string) => /^\s*\|[\s:|-]+\|\s*$/.test(l);
const _cells = (l: string) => l.trim().replace(/^\|/, '').replace(/\|$/, '').split('|').map(c => c.trim());

function AiMarkdown({ content }: { content: string }) {
    // Unescape literal escapes some models emit (e.g. "\nadb shell …\n" shown
    // verbatim). <br> is left intact here and handled in inlineFmt.
    const norm = (content || '').replace(/\\r\\n|\\n/g, '\n').replace(/\\t/g, '  ');
    // Split into code-fence vs text segments.
    const segs = norm.split(/(```[\s\S]*?```)/g);
    return (
        <div className="text-sm text-gray-800 leading-relaxed space-y-2">
            {segs.map((seg, si) => {
                const fence = seg.match(/^```(\w*)\n?([\s\S]*?)```$/);
                if (fence) {
                    const code = fence[2].replace(/\n$/, '');
                    return (
                        <div key={si} className="relative">
                            {fence[1] && <span className="absolute top-2 left-3 text-[10px] font-mono uppercase text-gray-400">{fence[1]}</span>}
                            <CopyButton text={code} />
                            <pre className="bg-gray-900 text-gray-100 rounded-md p-3 pt-7 overflow-x-auto text-[13px] font-mono whitespace-pre">{code}</pre>
                        </div>
                    );
                }
                // text segment → walk lines, grouping GFM tables.
                const lines = seg.split('\n');
                const out: React.ReactNode[] = [];
                let i = 0;
                while (i < lines.length) {
                    const line = lines[i];
                    // GFM table: header row + separator row + body rows.
                    if (_isRow(line) && i + 1 < lines.length && _isSep(lines[i + 1])) {
                        const header = _cells(line);
                        let j = i + 2;
                        const rows: string[][] = [];
                        while (j < lines.length && _isRow(lines[j]) && !_isSep(lines[j])) { rows.push(_cells(lines[j])); j++; }
                        out.push(
                            <div key={`${si}-t${i}`} className="overflow-x-auto my-2">
                                <table className="text-[13px] border-collapse w-full">
                                    <thead><tr>{header.map((c, ci) => (
                                        <th key={ci} className="border border-gray-300 bg-gray-50 px-2 py-1 text-left font-semibold">{inlineFmt(c, `${si}-th-${i}-${ci}`)}</th>
                                    ))}</tr></thead>
                                    <tbody>{rows.map((r, ri) => (
                                        <tr key={ri}>{header.map((_, ci) => (
                                            <td key={ci} className="border border-gray-300 px-2 py-1 align-top">{inlineFmt(r[ci] ?? '', `${si}-td-${i}-${ri}-${ci}`)}</td>
                                        ))}</tr>
                                    ))}</tbody>
                                </table>
                            </div>
                        );
                        i = j;
                        continue;
                    }
                    const key = `${si}-${i}`;
                    if (!line.trim()) { out.push(<div key={key} className="h-1" />); i++; continue; }
                    const h = line.match(/^(#{1,4})\s+(.*)$/);
                    if (h) { out.push(<p key={key} className="font-bold text-gray-900 mt-2">{inlineFmt(h[2], key)}</p>); i++; continue; }
                    const li2 = line.match(/^\s*[-*]\s+(.*)$/);
                    if (li2) { out.push(<p key={key} className="pl-4 relative before:content-['•'] before:absolute before:left-0 before:text-gray-400">{inlineFmt(li2[1], key)}</p>); i++; continue; }
                    const num = line.match(/^\s*(\d+)\.\s+(.*)$/);
                    if (num) { out.push(<p key={key} className="pl-1"><span className="font-bold text-gray-700">{num[1]}.</span> {inlineFmt(num[2], key)}</p>); i++; continue; }
                    out.push(<p key={key}>{inlineFmt(line, key)}</p>); i++;
                }
                return <div key={si}>{out}</div>;
            })}
        </div>
    );
}

// Remediation section: the scanner solution (Nessus) plus CVE-level
// external sources (MSRC, later Ubuntu/CentOS), each in its own block.
type RemItem = { kind: string; title?: string; detail?: string; kb?: string; fixed_build?: string; url?: string };
type RemGroup = { source: string; items: RemItem[]; fetched_at?: string };
const SOURCE_LABEL: Record<string, string> = { msrc: 'Microsoft (MSRC)', ubuntu: 'Ubuntu USN', redhat: 'Red Hat / CentOS / Alma', osv: 'OSV.dev (aggregator)' };

function RemediationsSection({ vulnId, scannerFallback }: { vulnId: number; scannerFallback?: string | null }) {
    const [scanner, setScanner] = useState<string | null>(scannerFallback || null);
    const [external, setExternal] = useState<RemGroup[]>([]);

    useEffect(() => {
        let ok = true;
        api.get(`/api/v1/vulnerabilities/${vulnId}/remediations`)
            .then(r => { if (!ok) return; setScanner(r.data?.scanner ?? null); setExternal(r.data?.external || []); })
            .catch(() => {});
        return () => { ok = false; };
    }, [vulnId]);

    if (!scanner && external.length === 0) return null;

    const renderItems = (items: RemItem[]) => {
        const fixes = items.filter(i => i.kind === 'fix');
        const notes = items.filter(i => i.kind !== 'fix');
        return (
            <div className="space-y-3">
                {fixes.length > 0 && (
                    <div>
                        <p className="text-[10px] uppercase tracking-wider text-emerald-700 font-mono mb-1">Patches / KBs</p>
                        <ul className="space-y-1">
                            {fixes.map((f, i) => (
                                <li key={i} className="text-sm flex items-center gap-2 flex-wrap">
                                    <span className="inline-flex items-center rounded bg-emerald-100 px-1.5 py-0.5 text-[11px] font-bold text-emerald-700">{f.title || 'Fix'}</span>
                                    {f.url && <a href={f.url} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline text-xs font-mono">download →</a>}
                                </li>
                            ))}
                        </ul>
                    </div>
                )}
                {notes.map((n, i) => (
                    <div key={i}>
                        <p className={`text-[10px] uppercase tracking-wider font-mono mb-1 ${n.kind === 'mitigation' ? 'text-amber-700' : 'text-indigo-700'}`}>
                            {n.kind === 'mitigation' ? 'Mitigation / Containment' : n.kind === 'workaround' ? 'Workaround' : 'Advisory'}
                        </p>
                        {n.detail && <p className="text-sm text-gray-700 whitespace-pre-wrap leading-relaxed">{n.detail}</p>}
                        {n.url && (
                            <a href={n.url} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline text-sm font-mono break-all">
                                {n.title || n.url} →
                            </a>
                        )}
                    </div>
                ))}
            </div>
        );
    };

    return (
        <div className="space-y-4">
            {scanner && (
                <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                    <h2 className="text-lg font-bold text-gray-900 mb-3 flex items-center gap-2">
                        <span>🛠️</span> Remediation
                        <span className="text-[10px] uppercase tracking-wider text-gray-400 font-mono">via scanner</span>
                    </h2>
                    <p className="text-sm text-gray-700 whitespace-pre-wrap leading-relaxed">{scanner}</p>
                </div>
            )}
            {external.map((g, gi) => (
                <div key={gi} className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                    <h2 className="text-lg font-bold text-gray-900 mb-3 flex items-center gap-2">
                        <span>🛡️</span> Remediation
                        <span className="text-[10px] uppercase tracking-wider text-gray-400 font-mono">via {SOURCE_LABEL[g.source] || g.source}</span>
                    </h2>
                    {renderItems(g.items)}
                </div>
            ))}
        </div>
    );
}

function AIRemediationSection({ vulnId }: { vulnId: number }) {
    const [enabled, setEnabled] = useState<boolean | null>(null);
    const [busy, setBusy] = useState(false);
    const [content, setContent] = useState<string | null>(null);
    const [model, setModel] = useState<string | null>(null);
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        let ok = true;
        api.get('/api/v1/vulnerabilities/ai-remediation/status')
            .then(r => { if (ok) setEnabled(!!r.data?.enabled); })
            .catch(() => { if (ok) setEnabled(false); });
        return () => { ok = false; };
    }, []);

    if (enabled === false) return null;  // feature off → no clutter

    const run = async () => {
        setBusy(true); setError(null);
        try {
            const r = await api.post(`/api/v1/vulnerabilities/${vulnId}/ai-remediation`);
            setContent(r.data?.content || '');
            setModel(r.data?.model || null);
        } catch (e: any) {
            setError(e?.response?.data?.detail || e?.message || 'unknown error');
        } finally {
            setBusy(false);
        }
    };

    return (
        <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
            <div className="flex items-center justify-between mb-3">
                <h2 className="text-lg font-bold text-gray-900 flex items-center gap-2">
                    <span>🤖</span> AI Remediation
                    {model && <span className="text-[10px] uppercase tracking-wider text-gray-400 font-mono">{model}</span>}
                </h2>
                <button
                    onClick={run}
                    disabled={busy || enabled === null}
                    className="inline-flex items-center gap-1 text-xs font-mono px-3 py-2 border border-indigo-500 text-indigo-700 rounded-md hover:bg-indigo-50 disabled:opacity-50 disabled:cursor-not-allowed"
                >
                    {busy ? <><span className="animate-spin">⟳</span> Generating…</>
                          : content ? 'Regenerate' : 'Generate fix steps'}
                </button>
            </div>
            {error && <p className="text-sm text-red-600 font-mono">Error: {error}</p>}
            {content
                ? <AiMarkdown content={content} />
                : !error && <p className="text-xs text-gray-400 font-mono">OS-aware fix commands generated on demand via OpenRouter.</p>}
        </div>
    );
}

// Refresh button with loading state + ephemeral "done" badge so a
// click that returns identical EPSS/KEV data still gives the operator
// visual confirmation the call ran (vs the previous silent UX).
function ThreatIntelRefreshButton({
    vulnId,
    onRefreshed,
}: { vulnId: number; onRefreshed: (v: any) => void }) {
    const [busy, setBusy] = useState(false);
    const [done, setDone] = useState(false);
    return (
        <button
            disabled={busy}
            onClick={async () => {
                setBusy(true);
                setDone(false);
                try {
                    const res = await api.post(`/api/v1/vulnerabilities/${vulnId}/enrich`);
                    onRefreshed(res.data.vulnerability);
                    setDone(true);
                    setTimeout(() => setDone(false), 2500);
                } catch (e: any) {
                    alert(`Enrichment failed: ${e?.response?.data?.detail || 'unknown'}`);
                } finally {
                    setBusy(false);
                }
            }}
            className="text-xs font-mono px-2 py-1 rounded border border-gray-200 hover:bg-gray-50 disabled:opacity-60"
        >
            {busy ? 'Refreshing…' : done ? '✓ Refreshed' : 'Refresh'}
        </button>
    );
}

export default function VulnerabilityDetailPage() {
    const params = useParams();
    const router = useRouter();
    const [vuln, setVuln] = useState<VulnDetail | null>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);
    const [userRole, setUserRole] = useState('');
    useEffect(() => {
        api.get('/auth/me').then(r => setUserRole(r.data?.role || '')).catch(() => { });
    }, []);
    const canEdit = userRole === 'admin' || userRole === 'editor';
    // Audit / change history for this vuln — populated separately so
    // a slow audit query doesn't block the vuln detail render.
    type AuditEntry = {
        id: number;
        username: string | null;
        event_type: string;
        event_description: string;
        old_value: string | null;
        new_value: string | null;
        timestamp: string;
    };
    const [history, setHistory] = useState<AuditEntry[]>([]);

    useEffect(() => {
        const fetchVulnerability = async () => {
            try {
                const res = await api.get(`/api/v1/vulnerabilities/${params.id}`);
                setVuln(res.data);
            } catch (err: any) {
                setError(err.response?.data?.detail || 'Failed to load vulnerability');
            } finally {
                setLoading(false);
            }
        };
        const fetchHistory = async () => {
            try {
                // Audit router is mounted at /audit/* (NOT /api/v1/audit/*)
                // Same gotcha as the CSV-export href fix.
                const res = await api.get(`/audit/logs`, {
                    params: { resource_type: 'vulnerability', resource_id: params.id, limit: 50 },
                });
                setHistory(Array.isArray(res.data) ? res.data : []);
            } catch {
                setHistory([]);
            }
        };

        if (params.id) {
            fetchVulnerability();
            fetchHistory();
        }
    }, [params.id]);

    const [dismissBusy, setDismissBusy] = useState(false);
    const reloadVuln = async () => {
        try {
            const res = await api.get(`/api/v1/vulnerabilities/${params.id}`);
            setVuln(res.data);
        } catch { /* keep current */ }
    };
    // Dismiss = mark false positive (with reason). Works for EOL/pseudo-CVE
    // rows too — they're normal vulnerability records. Reactivate reverses it.
    const handleDismiss = async () => {
        const reason = window.prompt(
            'Dismiss this finding as a false positive?\nEnter a reason (audit-logged):',
            'Not applicable / accepted'
        );
        if (reason === null) return;
        setDismissBusy(true);
        try {
            await api.patch(`/api/v1/vulnerabilities/${params.id}/false-positive`, { reason });
            await reloadVuln();
        } catch (e: any) {
            alert(`Dismiss failed: ${e?.response?.data?.detail || e?.message || 'unknown'}`);
        } finally {
            setDismissBusy(false);
        }
    };
    const handleReactivate = async () => {
        setDismissBusy(true);
        try {
            await api.patch(`/api/v1/vulnerabilities/${params.id}/unmark-false-positive`);
            await reloadVuln();
        } catch (e: any) {
            alert(`Reactivate failed: ${e?.response?.data?.detail || e?.message || 'unknown'}`);
        } finally {
            setDismissBusy(false);
        }
    };

    // Parse the JSON payload audit-logs use for status changes.
    // new_value can be a plain string (old format) or a JSON object
    // {status, reason, source, cve_id} (new format).
    const parseAudit = (raw: string | null): { status?: string; reason?: string; source?: string } => {
        if (!raw) return {};
        try {
            const parsed = JSON.parse(raw);
            if (parsed && typeof parsed === 'object') return parsed;
        } catch { /* not JSON */ }
        return { status: raw };
    };

    const severityColors: Record<string, string> = {
        critical: 'bg-red-100 text-red-800 border-red-200',
        high: 'bg-orange-100 text-orange-800 border-orange-200',
        medium: 'bg-yellow-100 text-yellow-800 border-yellow-200',
        low: 'bg-green-100 text-green-800 border-green-200',
    };

    const statusColors: Record<string, string> = {
        open: 'bg-red-100 text-red-700',
        patched: 'bg-green-100 text-green-700',
        deferred: 'bg-yellow-100 text-yellow-700',
        accepted_risk: 'bg-gray-100 text-gray-700',
        false_positive: 'bg-blue-100 text-blue-700',
    };

    if (loading) {
        return (
            <div className="p-8 flex justify-center items-center min-h-screen">
                <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-truevuln-blue"></div>
            </div>
        );
    }

    if (error || !vuln) {
        return (
            <div className="p-8">
                <div className="max-w-4xl mx-auto bg-red-50 border border-red-200 rounded-lg p-6">
                    <h2 className="text-lg font-bold text-red-800">Error</h2>
                    <p className="text-red-600 mt-2">{error || 'Vulnerability not found'}</p>
                    <button
                        onClick={() => router.back()}
                        className="mt-4 text-red-700 hover:text-red-900 flex items-center gap-2"
                    >
                        <ArrowLeftIcon className="h-4 w-4" /> Go back
                    </button>
                </div>
            </div>
        );
    }

    return (
        <div className="p-8 max-w-6xl mx-auto">
            {/* Header */}
            <div className="mb-6">
                <button
                    onClick={() => router.back()}
                    className="text-gray-500 hover:text-gray-700 flex items-center gap-2 mb-4 font-mono text-sm"
                >
                    <ArrowLeftIcon className="h-4 w-4" /> Back to Vulnerabilities
                </button>

                <div className="flex items-start justify-between">
                    <div>
                        <h1 className="text-3xl font-bold text-gray-900 font-mono">{vuln.cve_id}</h1>
                        <p className="text-gray-500 mt-1 font-mono text-sm">
                            Detected: {vuln.detected_at ? new Date(vuln.detected_at).toLocaleString('de-CH', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }) : 'Unknown'}
                        </p>
                    </div>
                    <div className="flex items-center gap-3">
                        <span className={`px-4 py-2 rounded-lg text-sm font-bold uppercase ${severityColors[vuln.severity] || 'bg-gray-100'}`}>
                            {vuln.severity}
                        </span>
                        <span className={`px-4 py-2 rounded-lg text-sm font-medium ${statusColors[vuln.status] || 'bg-gray-100'}`}>
                            {vuln.status.replace('_', ' ')}
                        </span>
                        {canEdit && (vuln.status === 'false_positive' ? (
                            <button
                                onClick={handleReactivate}
                                disabled={dismissBusy}
                                className="px-3 py-2 rounded-lg text-sm font-medium border border-gray-300 text-gray-700 hover:bg-gray-50 disabled:opacity-50"
                                title="Reopen this finding"
                            >
                                {dismissBusy ? '…' : 'Reactivate'}
                            </button>
                        ) : (
                            <button
                                onClick={handleDismiss}
                                disabled={dismissBusy}
                                className="px-3 py-2 rounded-lg text-sm font-medium border border-amber-300 text-amber-700 hover:bg-amber-50 disabled:opacity-50"
                                title="Dismiss as false positive (hides it from the active list)"
                            >
                                {dismissBusy ? '…' : 'Dismiss'}
                            </button>
                        ))}
                    </div>
                </div>
            </div>

            {/* Main Content */}
            <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
                {/* Left Column - Details */}
                <div className="lg:col-span-2 space-y-6">
                    {/* Description Card */}
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                            <DocumentTextIcon className="h-5 w-5 text-gray-500" />
                            Description
                        </h2>
                        {vuln.title && (
                            <p className="font-semibold text-gray-800 mb-2">{vuln.title}</p>
                        )}
                        <p className="text-gray-700 leading-relaxed">
                            {vuln.description || (!vuln.title ? 'No description available.' : '')}
                        </p>
                    </div>

                    {/* Affected Packages (per-package detail when multiple packages
                        hit by the same CVE on the same asset, e.g. CVE-2023-48795
                        on PuTTY + WinSCP). Falls back to the legacy parent-row
                        summary when no child rows exist (pseudo-CVEs etc). */}
                    {((vuln.packages && vuln.packages.length > 0) || vuln.package_name) && (
                        <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                            <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                                Affected Package{(vuln.packages && vuln.packages.length > 1) ? 's' : ''}
                                {vuln.status === 'open' && vuln.has_fix_any && (
                                    <span
                                        className="inline-flex items-center rounded-md bg-emerald-100 px-2 py-0.5 text-xs font-bold text-emerald-700"
                                        title="At least one package has a known fix"
                                    >
                                        PATCH AVAILABLE
                                    </span>
                                )}
                            </h2>

                            {vuln.packages && vuln.packages.length > 0 ? (
                                <div className="space-y-2">
                                    {vuln.packages.map((p, idx) => (
                                        <div key={`${p.package_name}-${idx}`} className="bg-gray-50 rounded-lg p-3 font-mono text-sm">
                                            <div className="grid grid-cols-12 gap-2 items-center">
                                                <div className="col-span-5">
                                                    <span className="text-[10px] uppercase tracking-wider text-gray-500">Package</span>
                                                    {/* Wrap, don't clip. "Microsoft Exchange Server
                                                        Subscription Edition" lost its distinguishing
                                                        half to an ellipsis — and that half is what
                                                        separates it from plain "Microsoft Exchange
                                                        Server", which sits on the same host. */}
                                                    <p className="font-bold text-gray-900 break-words leading-tight"
                                                       title={p.package_name}>{p.package_name}</p>
                                                </div>
                                                <div className="col-span-3">
                                                    <span className="text-[10px] uppercase tracking-wider text-gray-500">Installed</span>
                                                    <p className="font-bold text-gray-900">{p.package_version || '—'}</p>
                                                </div>
                                                <div className="col-span-3">
                                                    <span className="text-[10px] uppercase tracking-wider text-gray-500">Fixed in</span>
                                                    <p className={`font-bold break-words ${p.has_fix ? 'text-emerald-700' : 'text-gray-400'}`}
                                                       title={p.fixed_version || ''}>
                                                        {formatFixedVersion(p.fixed_version) || (p.has_fix ? '—' : 'not announced')}
                                                    </p>
                                                </div>
                                                <div className="col-span-1 text-right">
                                                    {p.has_fix ? (
                                                        <span className="inline-flex items-center rounded bg-emerald-100 px-1.5 py-0.5 text-[10px] font-bold text-emerald-700">FIX</span>
                                                    ) : (
                                                        <span className="inline-flex items-center rounded bg-gray-100 px-1.5 py-0.5 text-[10px] font-bold text-gray-500">—</span>
                                                    )}
                                                </div>
                                            </div>
                                            {/* Detected by — every scanner that confirmed THIS package,
                                                never blank (API falls back to the finding's sources). */}
                                            <div className="mt-1 flex items-center gap-1 text-[10px] uppercase tracking-wider text-gray-400">
                                                <span>via</span>
                                                {(p.source || 'unknown').split(',').filter(Boolean).map(s => (
                                                    <span key={s} className="rounded bg-gray-200 px-1 py-0.5 font-semibold text-gray-600">{s}</span>
                                                ))}
                                            </div>
                                        </div>
                                    ))}
                                </div>
                            ) : (
                                <div className="bg-gray-50 rounded-lg p-4 font-mono text-sm">
                                    <div className="grid grid-cols-3 gap-4">
                                        <div>
                                            <span className="text-gray-500">Package:</span>
                                            <p className="font-bold text-gray-900">{vuln.package_name}</p>
                                        </div>
                                        {vuln.package_vendor && (
                                            <div>
                                                <span className="text-gray-500">Vendor:</span>
                                                <p className="font-bold text-gray-900 break-words">{vuln.package_vendor}</p>
                                            </div>
                                        )}
                                        {vuln.package_version && (
                                            <div>
                                                <span className="text-gray-500">Installed:</span>
                                                <p className="font-bold text-gray-900">{vuln.package_version}</p>
                                            </div>
                                        )}
                                        {vuln.fixed_version && (
                                            <div>
                                                <span className="text-gray-500">Fixed in:</span>
                                                <p className="font-bold text-emerald-700 break-words" title={vuln.fixed_version}>{formatFixedVersion(vuln.fixed_version)}</p>
                                            </div>
                                        )}
                                    </div>
                                </div>
                            )}
                        </div>
                    )}

                    {/* Remediation — scanner solution + external sources (MSRC, ...) */}
                    <RemediationsSection vulnId={vuln.id} scannerFallback={vuln.remediation} />

                    {/* AI remediation (OpenRouter) — hidden when not configured */}
                    {/* Editor+ only: generating fix steps hits an editor-gated
                        endpoint and the output isn't persisted, so there's
                        nothing for a read-only user to see. */}
                    {canEdit && <AIRemediationSection vulnId={vuln.id} />}

                    {/* External Links — only for real CVE ids. EOL- /
                        NESSUS-PLUGIN- pseudo-CVEs have no NVD/CVE.org/Exploit-DB
                        record, so the links would 404 / lead to nirvana. */}
                    {/^CVE-/i.test(vuln.cve_id) && (
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                            <LinkIcon className="h-5 w-5 text-gray-500" />
                            External References
                        </h2>
                        <div className="flex flex-wrap gap-3">
                            <a
                                href={`https://nvd.nist.gov/vuln/detail/${vuln.cve_id}`}
                                target="_blank"
                                rel="noopener noreferrer"
                                className="inline-flex items-center gap-2 px-4 py-2 bg-blue-50 text-blue-700 rounded-lg hover:bg-blue-100 transition-colors font-mono text-sm"
                            >
                                NVD Database →
                            </a>
                            <a
                                href={`https://www.cve.org/CVERecord?id=${vuln.cve_id}`}
                                target="_blank"
                                rel="noopener noreferrer"
                                className="inline-flex items-center gap-2 px-4 py-2 bg-green-50 text-green-700 rounded-lg hover:bg-green-100 transition-colors font-mono text-sm"
                            >
                                CVE.org →
                            </a>
                            <a
                                href={`https://www.exploit-db.com/search?cve=${vuln.cve_id.replace('CVE-', '')}`}
                                target="_blank"
                                rel="noopener noreferrer"
                                className="inline-flex items-center gap-2 px-4 py-2 bg-red-50 text-red-700 rounded-lg hover:bg-red-100 transition-colors font-mono text-sm"
                            >
                                Exploit-DB →
                            </a>
                        </div>
                    </div>
                    )}
                </div>

                {/* Right Column - Metadata */}
                <div className="space-y-6">
                    {/* CVSS Score */}
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                            <ShieldExclamationIcon className="h-5 w-5 text-gray-500" />
                            CVSS Score
                        </h2>
                        <div className="text-center">
                            <div className={`text-5xl font-bold ${(vuln.cvss_score || 0) >= 9 ? 'text-red-600' :
                                    (vuln.cvss_score || 0) >= 7 ? 'text-orange-500' :
                                        (vuln.cvss_score || 0) >= 4 ? 'text-yellow-500' :
                                            'text-green-500'
                                }`}>
                                {vuln.cvss_score?.toFixed(1) || 'N/A'}
                            </div>
                            <p className="text-gray-500 text-sm mt-1">out of 10.0</p>
                        </div>
                    </div>

                    {/* Threat Intel Enrichment */}
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <div className="flex items-center justify-between mb-4">
                            <h2 className="text-lg font-bold text-gray-900 flex items-center gap-2">
                                <ShieldExclamationIcon className="h-5 w-5 text-gray-500" />
                                Threat Intelligence
                            </h2>
                            <ThreatIntelRefreshButton
                                vulnId={vuln.id}
                                onRefreshed={(v) => setVuln(v)}
                            />
                        </div>
                        {vuln.enrichment_updated_at && (
                            <p className="text-[11px] text-gray-400 font-mono -mt-3 mb-3">
                                Last refreshed: {new Date(vuln.enrichment_updated_at).toLocaleString('de-CH', {
                                    day: '2-digit', month: '2-digit', year: 'numeric',
                                    hour: '2-digit', minute: '2-digit', second: '2-digit',
                                })}
                            </p>
                        )}

                        {/* CISA KEV (US) */}
                        <div className="mb-4">
                            <div className="text-xs text-gray-500 mb-1">CISA KEV (US)</div>
                            {vuln.kev_listed ? (
                                <div className="bg-red-50 border border-red-200 rounded-md p-3">
                                    <div className="flex items-center gap-2">
                                        <span className="inline-flex items-center rounded-sm bg-red-100 px-2 py-0.5 text-xs font-bold text-red-700">
                                            ACTIVELY EXPLOITED
                                        </span>
                                        {vuln.kev_ransomware_use && (
                                            <span className="inline-flex items-center rounded-sm bg-purple-100 px-2 py-0.5 text-xs font-bold text-purple-700">
                                                RANSOMWARE
                                            </span>
                                        )}
                                    </div>
                                    {vuln.kev_date_added && (
                                        <p className="text-xs text-gray-600 mt-2 font-mono">
                                            Added to catalog: {new Date(vuln.kev_date_added).toLocaleDateString()}
                                        </p>
                                    )}
                                </div>
                            ) : (
                                <p className="text-sm text-gray-400 italic">Not in CISA KEV catalog</p>
                            )}
                        </div>

                        {/* ENISA EUVD (EU) */}
                        <div className="mb-4">
                            <div className="text-xs text-gray-500 mb-1">ENISA EUVD (EU)</div>
                            {vuln.euvd_listed ? (
                                <div className="bg-blue-50 border border-blue-200 rounded-md p-3">
                                    <div className="flex items-center gap-2 flex-wrap">
                                        <span className="inline-flex items-center rounded-sm bg-blue-100 px-2 py-0.5 text-xs font-bold text-blue-700">
                                            EU EXPLOITED
                                        </span>
                                        {vuln.euvd_critical && (
                                            <span className="inline-flex items-center rounded-sm bg-amber-100 px-2 py-0.5 text-xs font-bold text-amber-700">
                                                ENISA CRITICAL
                                            </span>
                                        )}
                                    </div>
                                    {vuln.euvd_id && (
                                        <p className="text-xs text-gray-600 mt-2 font-mono">
                                            EUVD-ID: {vuln.euvd_id}
                                        </p>
                                    )}
                                    {vuln.euvd_date_added && (
                                        <p className="text-xs text-gray-600 font-mono">
                                            Added: {new Date(vuln.euvd_date_added).toLocaleDateString()}
                                        </p>
                                    )}
                                </div>
                            ) : (
                                <p className="text-sm text-gray-400 italic">Not in ENISA EUVD catalog</p>
                            )}
                        </div>

                        {/* EPSS */}
                        <div className="mb-4">
                            <div className="text-xs text-gray-500 mb-1">EPSS (Exploit Prediction)</div>
                            {vuln.epss_score != null ? (
                                <div>
                                    <div className="flex items-baseline gap-2">
                                        <span className={`text-2xl font-bold font-mono ${vuln.epss_score >= 0.5 ? 'text-red-600' : vuln.epss_score >= 0.1 ? 'text-orange-600' : 'text-gray-700'}`}>
                                            {(vuln.epss_score * 100).toFixed(2)}%
                                        </span>
                                        <span className="text-xs text-gray-500 font-mono">
                                            Percentile {((vuln.epss_percentile || 0) * 100).toFixed(1)}
                                        </span>
                                    </div>
                                    <div className="w-full h-2 bg-gray-100 rounded-full overflow-hidden mt-2">
                                        <div
                                            className={`h-full ${vuln.epss_score >= 0.5 ? 'bg-red-500' : vuln.epss_score >= 0.1 ? 'bg-orange-500' : 'bg-green-500'}`}
                                            style={{ width: `${vuln.epss_score * 100}%` }}
                                        />
                                    </div>
                                    <p className="text-[10px] text-gray-400 mt-1 font-mono">
                                        Probability of exploitation in next 30 days (FIRST.org EPSS)
                                    </p>
                                </div>
                            ) : (
                                <p className="text-sm text-gray-400 italic">No EPSS data</p>
                            )}
                        </div>

                        {/* Plan M — Public Exploit Catalogs */}
                        {((vuln.metasploit_module_count || 0) > 0
                          || (vuln.exploit_db_count || 0) > 0
                          || (vuln.pocs_github_count || 0) > 0) && (
                            <div className="mb-4 border-t border-gray-100 pt-3">
                                <div className="text-xs text-gray-500 mb-2">Public Exploit Catalogs</div>
                                <div className="space-y-2 text-sm">
                                    {(vuln.metasploit_module_count || 0) > 0 && (
                                        <div className="bg-red-50 border border-red-200 rounded-md p-2">
                                            <div className="flex items-center justify-between">
                                                <span className="text-xs font-bold text-red-800">Metasploit</span>
                                                <span className="text-xs font-mono">{vuln.metasploit_module_count} module(s)</span>
                                            </div>
                                            {vuln.metasploit_modules && (
                                                <ul className="mt-1 ml-3 text-[10px] font-mono text-red-900 list-disc">
                                                    {vuln.metasploit_modules.slice(0, 5).map((m, i) => (
                                                        <li key={i} className="truncate" title={m}>{m}</li>
                                                    ))}
                                                </ul>
                                            )}
                                        </div>
                                    )}
                                    {(vuln.exploit_db_count || 0) > 0 && (
                                        <div className="bg-orange-50 border border-orange-200 rounded-md p-2">
                                            <div className="flex items-center justify-between">
                                                <span className="text-xs font-bold text-orange-800">Exploit-DB</span>
                                                <span className="text-xs font-mono">{vuln.exploit_db_count} entries</span>
                                            </div>
                                            {vuln.exploit_db_ids && (
                                                <div className="mt-1 flex flex-wrap gap-1">
                                                    {vuln.exploit_db_ids.slice(0, 10).map((id) => (
                                                        <a
                                                            key={id}
                                                            href={`https://www.exploit-db.com/exploits/${id}`}
                                                            target="_blank"
                                                            rel="noopener noreferrer"
                                                            className="text-[10px] font-mono px-1.5 py-0.5 rounded bg-white border border-orange-300 hover:bg-orange-100"
                                                        >EDB-{id}</a>
                                                    ))}
                                                </div>
                                            )}
                                        </div>
                                    )}
                                    {(vuln.pocs_github_count || 0) > 0 && (
                                        <div className="bg-yellow-50 border border-yellow-200 rounded-md p-2">
                                            <div className="flex items-center justify-between">
                                                <span className="text-xs font-bold text-yellow-800">PoC-in-GitHub</span>
                                                <span className="text-xs font-mono">{vuln.pocs_github_count} repo(s)</span>
                                            </div>
                                            {vuln.pocs_github_urls && (
                                                <ul className="mt-1 ml-3 text-[10px] font-mono list-disc text-yellow-900">
                                                    {vuln.pocs_github_urls.slice(0, 5).map((u, i) => (
                                                        <li key={i} className="truncate">
                                                            <a href={u} target="_blank" rel="noopener noreferrer" className="hover:underline">{u}</a>
                                                        </li>
                                                    ))}
                                                </ul>
                                            )}
                                        </div>
                                    )}
                                </div>
                            </div>
                        )}

                        {/* Priority Score Breakdown */}
                        {vuln.priority_breakdown && (
                            <div className="border-t border-gray-100 pt-3 mt-3">
                                <div className="text-xs text-gray-500 mb-2">Priority Score Breakdown</div>
                                <div className="space-y-1 text-xs font-mono">
                                    <div className="flex justify-between"><span className="text-gray-600">CVSS</span><span>{vuln.priority_breakdown.cvss.toFixed(1)}</span></div>
                                    <div className="flex justify-between">
                                        <span className="text-gray-600">Exploit ({vuln.priority_breakdown.exploit_source})</span>
                                        <span>+{vuln.priority_breakdown.exploit_bonus.toFixed(1)}</span>
                                    </div>
                                    <div className="flex justify-between"><span className="text-gray-600">× Asset Factor</span><span>× {vuln.priority_breakdown.asset_factor.toFixed(1)}</span></div>
                                    <div className="flex justify-between"><span className="text-gray-600">+ Age</span><span>+{vuln.priority_breakdown.age_bonus.toFixed(1)}</span></div>
                                    {vuln.priority_breakdown.kev_bonus > 0 && (
                                        <div className="flex justify-between text-red-700"><span>+ KEV Bonus</span><span>+{vuln.priority_breakdown.kev_bonus.toFixed(1)}</span></div>
                                    )}
                                    {(vuln.priority_breakdown.euvd_bonus ?? 0) > 0 && (
                                        <div className="flex justify-between text-blue-700"><span>+ EUVD Bonus</span><span>+{(vuln.priority_breakdown.euvd_bonus ?? 0).toFixed(1)}</span></div>
                                    )}
                                    {/* Plan M — public-exploit catalog counts shown as
                                        informational rows. Already folded into
                                        exploit_bonus via max(); explicit listing here
                                        so the operator sees ALL contributing signals,
                                        not only the highest-weighted one. */}
                                    {(vuln.priority_breakdown.metasploit_module_count ?? 0) > 0 && (
                                        <div className="flex justify-between text-red-800" title="Already counted in exploit_bonus via max() — listed for transparency">
                                            <span>↳ Metasploit modules</span>
                                            <span>{vuln.priority_breakdown.metasploit_module_count}</span>
                                        </div>
                                    )}
                                    {(vuln.priority_breakdown.exploit_db_count ?? 0) > 0 && (
                                        <div className="flex justify-between text-orange-700" title="Already counted in exploit_bonus via max() — listed for transparency">
                                            <span>↳ Exploit-DB entries</span>
                                            <span>{vuln.priority_breakdown.exploit_db_count}</span>
                                        </div>
                                    )}
                                    {(vuln.priority_breakdown.pocs_github_count ?? 0) > 0 && (
                                        <div className="flex justify-between text-yellow-800" title="Already counted in exploit_bonus via max() — listed for transparency">
                                            <span>↳ GitHub PoCs</span>
                                            <span>{vuln.priority_breakdown.pocs_github_count}</span>
                                        </div>
                                    )}
                                    <div className="flex justify-between border-t border-gray-200 pt-1 mt-1 font-bold">
                                        <span>= Priority Total</span>
                                        <span>{vuln.priority_breakdown.total.toFixed(1)}</span>
                                    </div>
                                    {vuln.priority_breakdown.cpr != null && (
                                        <div className="flex justify-between pt-2 mt-1 border-t border-dashed border-gray-200" title="CPR (Cybersecurity Priority Risk) = (CVSS×10 × 0.6) + (EPSS_Percentile × 0.4) — JacquesKruger algorithm">
                                            <span className="text-gray-600">CPR ((CVSS×10)·0.6 + EPSS%·0.4)</span>
                                            <span className={`font-bold ${vuln.priority_breakdown.cpr >= 30 ? 'text-red-700' : vuln.priority_breakdown.cpr >= 10 ? 'text-orange-600' : 'text-gray-700'}`}>
                                                {vuln.priority_breakdown.cpr.toFixed(2)}
                                            </span>
                                        </div>
                                    )}
                                    {(vuln.priority_breakdown.catalog_count ?? 0) >= 2 && (
                                        <div className="text-purple-700 text-[10px] italic pt-1">
                                            Confirmed by both CISA KEV and ENISA EUVD
                                        </div>
                                    )}
                                </div>
                            </div>
                        )}

                        {vuln.enrichment_updated_at && (
                            <p className="text-[10px] text-gray-400 mt-3 font-mono">
                                Last enriched: {new Date(vuln.enrichment_updated_at).toLocaleString()}
                            </p>
                        )}
                    </div>

                    {/* Asset Info */}
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                            <ServerIcon className="h-5 w-5 text-gray-500" />
                            Affected Asset
                        </h2>
                        <Link
                            href={`/vulnerabilities?asset_id=${vuln.asset_id}`}
                            className="block bg-gray-50 rounded-lg p-4 hover:bg-gray-100 transition-colors"
                            title="Show all findings on this asset"
                        >
                            <p className="font-bold text-gray-900 font-mono">
                                {vuln.asset_hostname || `Asset #${vuln.asset_id}`}
                            </p>
                            {vuln.asset?.ip_address && (
                                <p className="text-gray-500 text-sm font-mono">{vuln.asset.ip_address}</p>
                            )}
                        </Link>
                    </div>

                    {/* Assignment Info */}
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                            <UserCircleIcon className="h-5 w-5 text-gray-500" />
                            Assignment
                        </h2>
                        {vuln.assigned_user_name || vuln.assigned_group_name ? (
                            <div className="bg-gray-50 rounded-lg p-4">
                                {vuln.assigned_user_name && (
                                    <p className="text-gray-900 font-medium">
                                        User: {vuln.assigned_user_name}
                                    </p>
                                )}
                                {vuln.assigned_group_name && (
                                    <p className="text-gray-900 font-medium">
                                        Group: {vuln.assigned_group_name}
                                    </p>
                                )}
                            </div>
                        ) : (
                            <p className="text-gray-500 italic">Not assigned</p>
                        )}
                    </div>

                    {/* Detection Sources (Nessus / Wazuh multi-scanner) */}
                    {((vuln.sources && vuln.sources.length > 0) || vuln.nessus_plugin_id || vuln.nessus_vpr_score != null || vuln.ssvc_technical_impact || vuln.ssvc_automatable) && (
                        <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                            <h2 className="text-lg font-bold text-gray-900 mb-4">Detection Sources</h2>
                            {/* Source badges */}
                            <div className="flex flex-wrap gap-1.5 mb-3">
                                {(vuln.sources || []).map(src => {
                                    const cls = src === 'wazuh'
                                        ? 'bg-green-100 text-green-700 border-green-200'
                                        : src === 'nessus'
                                            ? 'bg-purple-100 text-purple-700 border-purple-200'
                                            : 'bg-gray-100 text-gray-600 border-gray-200';
                                    return (
                                        <span key={src} className={`inline-flex items-center rounded border px-2 py-0.5 text-xs font-bold uppercase ${cls}`}>{src}</span>
                                    );
                                })}
                                {vuln.cross_confirmed && (
                                    <span className="inline-flex items-center rounded border border-emerald-200 bg-emerald-100 px-2 py-0.5 text-xs font-bold text-emerald-700"
                                        title="Reported by multiple independent scanners — highest confidence">
                                        ✓ Cross-confirmed
                                    </span>
                                )}
                            </div>
                            <div className="space-y-1.5 text-sm font-mono">
                                {vuln.first_detected_by && (
                                    <div className="flex justify-between text-xs">
                                        <span className="text-gray-500">First detected by</span>
                                        <span className="font-semibold uppercase">{vuln.first_detected_by}</span>
                                    </div>
                                )}
                                {vuln.nessus_plugin_id && (
                                    <div className="flex justify-between text-xs">
                                        <span className="text-gray-500">Nessus Plugin ID</span>
                                        <a
                                            href={`https://www.tenable.com/plugins/nessus/${vuln.nessus_plugin_id}`}
                                            target="_blank"
                                            rel="noopener noreferrer"
                                            className="text-purple-600 hover:underline"
                                        >
                                            #{vuln.nessus_plugin_id}
                                        </a>
                                    </div>
                                )}
                                {vuln.nessus_vpr_score != null && (
                                    <div className="flex justify-between text-xs items-center">
                                        <span className="text-gray-500" title="Tenable's Vulnerability Priority Rating (0–10) — proprietary commercial score">
                                            Tenable VPR
                                        </span>
                                        <span className={`font-bold ${vuln.nessus_vpr_score >= 9 ? 'text-red-600' : vuln.nessus_vpr_score >= 7 ? 'text-orange-500' : vuln.nessus_vpr_score >= 4 ? 'text-yellow-600' : 'text-green-600'}`}>
                                            {vuln.nessus_vpr_score.toFixed(1)} / 10
                                        </span>
                                    </div>
                                )}
                                {(vuln.ssvc_technical_impact || vuln.ssvc_automatable) && (
                                    <div className="pt-2 mt-2 border-t border-gray-100 space-y-1.5">
                                        <p className="text-[10px] uppercase tracking-wider text-gray-400">
                                            SSVC (CISA Vulnrichment)
                                        </p>
                                        {vuln.ssvc_technical_impact && (
                                            <div className="flex justify-between text-xs items-center">
                                                <span className="text-gray-500" title="Whether successful exploitation grants partial or total control over the affected software">
                                                    Technical Impact
                                                </span>
                                                <span className={`font-bold uppercase ${
                                                    vuln.ssvc_technical_impact === 'total' ? 'text-red-600' : 'text-gray-700'
                                                }`}>
                                                    {vuln.ssvc_technical_impact}
                                                </span>
                                            </div>
                                        )}
                                        {vuln.ssvc_automatable && (
                                            <div className="flex justify-between text-xs items-center">
                                                <span className="text-gray-500" title="Whether reliable mass exploitation is mechanically feasible">
                                                    Automatable
                                                </span>
                                                <span className={`font-bold uppercase ${
                                                    vuln.ssvc_automatable === 'yes' ? 'text-red-600' : 'text-gray-700'
                                                }`}>
                                                    {vuln.ssvc_automatable}
                                                </span>
                                            </div>
                                        )}
                                    </div>
                                )}
                            </div>
                        </div>
                    )}

                    {/* Timeline */}
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                            <CalendarIcon className="h-5 w-5 text-gray-500" />
                            Timeline
                        </h2>
                        <div className="space-y-3 text-sm">
                            <div className="flex justify-between">
                                <span className="text-gray-500">Detected:</span>
                                <span className="font-mono text-gray-900">
                                    {vuln.detected_at ? new Date(vuln.detected_at).toLocaleString('de-CH', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }) : 'Unknown'}
                                </span>
                            </div>
                            {vuln.deferred_until && (
                                <div className="flex justify-between">
                                    <span className="text-gray-500">Deferred until:</span>
                                    <span className="font-mono text-gray-900">
                                        {new Date(vuln.deferred_until).toLocaleDateString()}
                                    </span>
                                </div>
                            )}
                        </div>
                    </div>

                    {/* Change History — Revisionssicherheit. Lists every
                        status change for this vuln (manual + auto-patched
                        via scanner sync), who triggered it, when, and the
                        free-text reason captured at the time. */}
                    <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
                        <h2 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
                            <CalendarIcon className="h-5 w-5 text-gray-500" />
                            Change History
                            <span className="text-[10px] uppercase tracking-wider text-gray-400 font-mono">
                                {history.length} {history.length === 1 ? 'entry' : 'entries'}
                            </span>
                        </h2>
                        {history.length === 0 ? (
                            <p className="text-sm text-gray-500 font-mono">No recorded changes yet.</p>
                        ) : (
                            // Cap height + own scrollbar — long histories
                            // (auto-patch entries pile up after multiple
                            // scanner syncs) no longer push everything
                            // else off-screen.
                            <ul className="space-y-3 text-sm max-h-[320px] overflow-y-auto pr-2">
                                {history.map((h) => {
                                    const meta = parseAudit(h.new_value);
                                    const who = h.username || 'System/Auto';
                                    const when = new Date(h.timestamp).toLocaleString('de-CH', {
                                        day: '2-digit', month: '2-digit', year: 'numeric',
                                        hour: '2-digit', minute: '2-digit',
                                    });
                                    return (
                                        <li key={h.id} className="border-l-2 border-gray-200 pl-3">
                                            <div className="flex items-center gap-2 flex-wrap">
                                                <span className="text-[10px] uppercase tracking-wider rounded bg-gray-100 px-1.5 py-0.5 text-gray-600 font-mono">
                                                    {h.event_type}
                                                </span>
                                                {h.old_value && meta.status && (
                                                    <span className="text-xs font-mono text-gray-500">
                                                        {h.old_value} → <strong className="text-gray-900">{meta.status}</strong>
                                                    </span>
                                                )}
                                                {meta.source && (
                                                    <span className="text-[10px] rounded bg-blue-50 text-blue-700 px-1.5 py-0.5 font-mono">
                                                        via {meta.source}
                                                    </span>
                                                )}
                                            </div>
                                            {meta.reason && (
                                                <p className="text-sm text-gray-700 mt-1 italic">&ldquo;{meta.reason}&rdquo;</p>
                                            )}
                                            <p className="text-[11px] text-gray-400 mt-1 font-mono">
                                                {who} · {when}
                                            </p>
                                        </li>
                                    );
                                })}
                            </ul>
                        )}
                    </div>
                </div>
            </div>
        </div>
    );
}
