/**
 * Threats Page
 * Threat analytics and intel listing
 */

const ThreatsPage = {
    data: null,
    categories: [],
    autoRefreshInterval: null,
    autoRefreshEnabled: false,
    selectedIds: new Set(),
    sortColumn: 'first_seen',
    sortDirection: 'desc',
    filters: {
        page: 1,
        page_size: 20,
        threat_type: '',
        min_risk: 0,
    },

    async render(container) {
        container.textContent = '';
        this.selectedIds.clear();

        if (window.Header) Header.setPageInfo('Threat Monitor', 'All LLM requests analyzed for threats');

        // Filters bar (will be populated after loading categories)
        const filtersBar = document.createElement('div');
        filtersBar.className = 'filters-bar';
        filtersBar.id = 'threats-filters';
        container.appendChild(filtersBar);

        // Content area
        const content = document.createElement('div');
        content.id = 'threats-content';
        container.appendChild(content);

        // Load data first, then build filters from available categories
        await this.loadData();
        this.buildFiltersBar();
    },

    buildFiltersBar() {
        const bar = document.getElementById('threats-filters');
        if (!bar) return;

        bar.textContent = '';

        // Threat type filter - populated from database categories
        const typeGroup = document.createElement('div');
        typeGroup.className = 'filter-group';

        const typeLabel = document.createElement('label');
        typeLabel.textContent = 'Type';
        typeGroup.appendChild(typeLabel);

        const typeSelect = document.createElement('select');
        typeSelect.className = 'filter-select';
        typeSelect.id = 'threat-type-filter';

        // Default option
        const defaultOption = document.createElement('option');
        defaultOption.value = '';
        defaultOption.textContent = 'All Types';
        typeSelect.appendChild(defaultOption);

        // Add categories from data
        const uniqueTypes = this.getUniqueCategories();
        uniqueTypes.forEach(type => {
            const option = document.createElement('option');
            option.value = type;
            option.textContent = this.formatCategoryLabel(type);
            if (type === this.filters.threat_type) {
                option.selected = true;
            }
            typeSelect.appendChild(option);
        });

        typeSelect.addEventListener('change', (e) => {
            this.filters.threat_type = e.target.value;
            this.filters.page = 1;
            this.loadData();
        });

        typeGroup.appendChild(typeSelect);
        bar.appendChild(typeGroup);

        // Min risk filter
        const riskGroup = document.createElement('div');
        riskGroup.className = 'filter-group';

        const riskLabel = document.createElement('label');
        riskLabel.textContent = 'Min Risk';
        riskGroup.appendChild(riskLabel);

        const riskSelect = document.createElement('select');
        riskSelect.className = 'filter-select';

        const risks = [
            { value: 0, label: 'All' },
            { value: 40, label: 'Medium+' },
            { value: 60, label: 'High+' },
            { value: 80, label: 'Critical' },
        ];

        risks.forEach(risk => {
            const option = document.createElement('option');
            option.value = risk.value;
            option.textContent = risk.label;
            if (risk.value === this.filters.min_risk) {
                option.selected = true;
            }
            riskSelect.appendChild(option);
        });

        riskSelect.addEventListener('change', (e) => {
            this.filters.min_risk = parseInt(e.target.value, 10);
            this.filters.page = 1;
            this.loadData();
        });

        riskGroup.appendChild(riskSelect);
        bar.appendChild(riskGroup);

        // Spacer to push buttons to right
        const spacer = document.createElement('div');
        spacer.className = 'filter-spacer';
        bar.appendChild(spacer);

        // Delete Selected button (hidden by default)
        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'btn btn-danger';
        deleteBtn.id = 'delete-selected-btn';
        deleteBtn.style.display = 'none';
        deleteBtn.textContent = 'Delete Selected (0)';
        const self = this;
        deleteBtn.onclick = function() {
            self.confirmDeleteSelected();
        };
        bar.appendChild(deleteBtn);

        // Auto-refresh toggle — compact toolbar style so it reads as a
        // utility action, not a page-level primary button.
        const refreshBtn = document.createElement('button');
        refreshBtn.className = 'btn btn-secondary btn-compact auto-refresh-btn' + (this.autoRefreshEnabled ? ' active' : '');
        refreshBtn.textContent = '↻ Auto Refresh';
        refreshBtn.title = 'Auto refresh every 30 seconds';
        refreshBtn.addEventListener('click', () => {
            this.toggleAutoRefresh();
            refreshBtn.classList.toggle('active', this.autoRefreshEnabled);
        });
        bar.appendChild(refreshBtn);

        // Export buttons — matched compact size. The CSV icon comes first
        // because it's the more common action on this page.
        const exportCsvBtn = document.createElement('button');
        exportCsvBtn.className = 'btn btn-secondary btn-compact';
        exportCsvBtn.textContent = 'Export CSV';
        exportCsvBtn.title = 'Download threats as CSV';
        exportCsvBtn.addEventListener('click', () => this.exportToCSV());
        bar.appendChild(exportCsvBtn);

        const exportPdfBtn = document.createElement('button');
        exportPdfBtn.className = 'btn btn-secondary btn-compact';
        exportPdfBtn.textContent = 'Export PDF';
        exportPdfBtn.title = 'Download threat report as PDF';
        exportPdfBtn.addEventListener('click', () => this.exportToPDF());
        bar.appendChild(exportPdfBtn);
    },

    async exportToCSV() {
        // Always fetch fresh so the export doesn't depend on what's currently
        // paginated in the table. Applies the active filters so exported rows
        // match what the user is filtering.
        let items = [];
        try {
            const params = Object.assign({}, this.filters || {}, { page: 1, page_size: 5000 });
            const data = await API.getThreats(params);
            items = (data && (data.items || data.threats)) || [];
        } catch (e) {
            items = (this.data && (this.data.items || this.data.threats)) || [];
        }

        if (items.length === 0) {
            alert('No threats to export.');
            return;
        }

        const headers = [
            'id', 'created_at', 'is_threat', 'threat_type', 'risk_score',
            'confidence', 'action_taken', 'source_identifier', 'text_preview', 'matched_rules'
        ];
        const esc = (v) => {
            if (v === null || v === undefined) return '';
            const s = String(v);
            if (s.includes('"') || s.includes(',') || s.includes('\n')) {
                return '"' + s.replace(/"/g, '""') + '"';
            }
            return s;
        };
        const rows = items.map(t => {
            const rules = (t.matched_rules || []).map(r => r.rule_id || r.rule_name || '').join('; ');
            return [
                t.id, t.created_at, t.is_threat, t.threat_type, t.risk_score,
                t.confidence, t.action_taken, t.source_identifier, (t.text_preview || '').slice(0, 500),
                rules,
            ].map(esc).join(',');
        });
        const csv = headers.join(',') + '\n' + rows.join('\n');
        const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `securevector-threats-${new Date().toISOString().slice(0, 10)}.csv`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    },

    updateDeleteButton() {
        const btn = document.getElementById('delete-selected-btn');
        if (!btn) return;

        const count = this.selectedIds.size;
        if (count > 0) {
            btn.style.display = 'inline-flex';
            btn.textContent = `Delete Selected (${count})`;
        } else {
            btn.style.display = 'none';
        }
        const tbl = document.getElementById('threats-data-table');
        if (tbl) tbl.classList.toggle('has-selection', count > 0);
    },

    toggleSelectAll(checked) {
        const threats = this.data?.items || [];
        if (checked) {
            threats.forEach(t => this.selectedIds.add(t.id));
        } else {
            this.selectedIds.clear();
        }

        // Update all checkboxes
        document.querySelectorAll('.threat-checkbox').forEach(cb => {
            cb.checked = checked;
        });

        this.updateDeleteButton();
    },

    toggleSelect(id, checked) {
        if (checked) {
            this.selectedIds.add(id);
        } else {
            this.selectedIds.delete(id);
        }

        // Update select-all checkbox state
        const selectAllCb = document.getElementById('select-all-checkbox');
        if (selectAllCb) {
            const threats = this.data?.items || [];
            selectAllCb.checked = threats.length > 0 && this.selectedIds.size === threats.length;
            selectAllCb.indeterminate = this.selectedIds.size > 0 && this.selectedIds.size < threats.length;
        }

        this.updateDeleteButton();
    },

    confirmDeleteSelected() {
        const count = this.selectedIds.size;

        if (count === 0) {
            alert('No records selected');
            return;
        }

        // Use native confirm for reliability
        const confirmed = confirm(`Delete ${count} selected record${count !== 1 ? 's' : ''}?\n\nThis action cannot be undone.`);

        if (confirmed) {
            this.deleteSelectedRecords();
        }
    },

    async deleteSelectedRecords() {
        try {
            const ids = Array.from(this.selectedIds);
            const response = await fetch('/api/threat-intel', {
                method: 'DELETE',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ ids: ids })
            });

            if (!response.ok) {
                throw new Error('Failed to delete records');
            }

            const result = await response.json();
            if (window.Toast) Toast.success(`Deleted ${result.deleted} record${result.deleted !== 1 ? 's' : ''}`);
            this.selectedIds.clear();
            this.filters.page = 1;
            await this.loadData();
            this.buildFiltersBar();
        } catch (error) {
            console.error('Failed to delete records:', error);
            if (window.Toast) Toast.error('Failed to delete records');
        }
    },

    toggleAutoRefresh() {
        this.autoRefreshEnabled = !this.autoRefreshEnabled;
        if (this.autoRefreshEnabled) {
            this.autoRefreshInterval = setInterval(() => {
                this.loadData();
            }, getPollInterval());
            const _sec = Math.round(getPollInterval() / 1000);
            if (window.Toast) Toast.info(`Auto refresh enabled (${_sec}s)`);
        } else {
            if (this.autoRefreshInterval) {
                clearInterval(this.autoRefreshInterval);
                this.autoRefreshInterval = null;
            }
            if (window.Toast) Toast.info('Auto refresh disabled');
        }
    },

    exportToPDF() {
        const threats = this.data?.items || [];
        if (threats.length === 0) {
            if (window.Toast) Toast.warning('No threats to export');
            return;
        }
        const pdfContent = this.generatePDFContent(threats);
        const blob = new Blob([pdfContent], { type: 'text/html' });
        const url = URL.createObjectURL(blob);
        const printWindow = window.open(url, '_blank');
        if (printWindow) {
            printWindow.onload = function() {
                setTimeout(() => {
                    printWindow.print();
                    URL.revokeObjectURL(url);
                }, 500);
            };
        }
    },

    generatePDFContent(threats) {
        const escapeHtml = (text) => {
            if (!text) return '';
            return String(text).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
        };
        let rows = '';
        threats.forEach(threat => {
            const riskClass = threat.risk_score >= 80 ? 'risk-high' : threat.risk_score >= 40 ? 'risk-medium' : 'risk-low';
            const content = escapeHtml((threat.text_preview || threat.text_content || '').substring(0, 100));
            const llmStatus = threat.llm_reviewed ? (threat.llm_agrees ? 'Confirmed' : 'Disputed') : 'Not Reviewed';
            const date = threat.created_at ? new Date(threat.created_at).toLocaleDateString() : '-';
            rows += '<tr><td>' + content + '</td><td>' + escapeHtml(threat.threat_type || 'No Threat Detected') + '</td><td class="' + riskClass + '">' + threat.risk_score + '%</td><td>' + llmStatus + '</td><td>' + date + '</td></tr>';
        });
        let details = '';
        threats.filter(t => t.risk_score >= 60).forEach(threat => {
            const riskClass = threat.risk_score >= 80 ? 'risk-high' : 'risk-medium';
            details += '<div class="threat"><div class="threat-header"><strong>' + escapeHtml(threat.threat_type || 'No Threat Detected') + '</strong><span class="' + riskClass + '">' + threat.risk_score + '% Risk</span></div>';
            details += '<p><span class="label">Content:</span> ' + escapeHtml(threat.text_content || threat.text_preview || '') + '</p>';
            if (threat.llm_reviewed) {
                details += '<div class="llm-section"><strong>LLM Analysis (' + escapeHtml(threat.llm_model_used || 'AI') + '):</strong><br>' + escapeHtml(threat.llm_explanation || threat.llm_reasoning || 'No explanation') + '<br><em>Recommendation: ' + escapeHtml(threat.llm_recommendation || 'N/A') + '</em></div>';
            }
            details += '</div>';
        });
        return '<!DOCTYPE html><html><head><title>SecureVector Threat Report</title><style>body{font-family:Arial,sans-serif;padding:20px}h1{color:#1a1a2e;border-bottom:2px solid #5eadb8;padding-bottom:10px}h2{color:#16213e;margin-top:30px}.threat{border:1px solid #ddd;padding:15px;margin:10px 0;border-radius:8px}.threat-header{display:flex;justify-content:space-between;margin-bottom:10px}.risk-high{color:#ef4444;font-weight:bold}.risk-medium{color:#f59e0b;font-weight:bold}.risk-low{color:#22c55e;font-weight:bold}.label{color:#666;font-size:12px}.llm-section{background:#f5f5f5;padding:10px;margin-top:10px;border-radius:4px}table{width:100%;border-collapse:collapse;margin-top:20px}th,td{border:1px solid #ddd;padding:8px;text-align:left}th{background:#1a1a2e;color:white}.summary{background:#e8f4f8;padding:15px;border-radius:8px;margin-bottom:20px}</style></head><body><h1>SecureVector Threat Report</h1><p>Generated: ' + new Date().toLocaleString() + '</p><div class="summary"><strong>Summary:</strong> ' + threats.length + ' threats<br>Critical: ' + threats.filter(t => t.risk_score >= 80).length + ' | High: ' + threats.filter(t => t.risk_score >= 60 && t.risk_score < 80).length + ' | Medium: ' + threats.filter(t => t.risk_score >= 40 && t.risk_score < 60).length + ' | Low: ' + threats.filter(t => t.risk_score < 40).length + '</div><table><thead><tr><th>Content</th><th>Type</th><th>Risk</th><th>LLM</th><th>Date</th></tr></thead><tbody>' + rows + '</tbody></table><h2>High Risk Details</h2>' + details + '</body></html>';
    },

    getUniqueCategories() {
        // Get unique threat types from loaded data
        const items = this.data?.items || [];
        const types = new Set();

        items.forEach(item => {
            if (item.threat_type) {
                types.add(item.threat_type);
            }
        });

        return Array.from(types).sort();
    },

    formatCategoryLabel(category) {
        // Convert snake_case to Title Case
        if (!category) return 'No Threat Detected';
        return category
            .split('_')
            .map(word => word.charAt(0).toUpperCase() + word.slice(1))
            .join(' ');
    },

    async loadData() {
        const content = document.getElementById('threats-content');
        if (!content) return;

        content.textContent = '';

        // Loading state
        const loading = document.createElement('div');
        loading.className = 'loading-container';
        const spinner = document.createElement('div');
        spinner.className = 'spinner';
        loading.appendChild(spinner);
        content.appendChild(loading);

        try {
            this.data = await API.getThreats(this.filters);
            this.renderContent(content);
        } catch (error) {
            this.renderError(content, error);
        }
    },

    renderContent(container) {
        container.textContent = '';

        const threats = this.data.items || this.data.threats || [];

        if (threats.length === 0) {
            this.renderEmptyState(container);
            return;
        }

        // Summary stats bar
        const statsBar = document.createElement('div');
        statsBar.className = 'threats-stats-bar';
        statsBar.style.cssText = 'display:flex;gap:24px;padding:12px 16px;background:var(--bg-card);border:1px solid var(--border-default);border-radius:8px;margin-bottom:16px;font-size:13px;';

        // Total records
        const recordsStat = document.createElement('div');
        recordsStat.innerHTML = '<span style="color:var(--text-secondary)">Records:</span> <strong>' + (this.data.total || threats.length) + '</strong>';
        statsBar.appendChild(recordsStat);

        // Total AI Analysis reviewed
        const llmReviewed = threats.filter(t => t.llm_reviewed).length;
        const llmStat = document.createElement('div');
        const llmLabel = document.createElement('span');
        llmLabel.style.color = 'var(--text-secondary)';
        llmLabel.textContent = 'AI Analysis Reviewed:';
        llmStat.appendChild(llmLabel);
        const llmVal = document.createElement('strong');
        llmVal.textContent = ' ' + llmReviewed;
        llmStat.appendChild(llmVal);
        statsBar.appendChild(llmStat);

        // Total AI Analysis tokens used
        const totalTokens = threats.reduce((sum, t) => sum + (t.llm_tokens_used || 0), 0);
        const tokensStat = document.createElement('div');
        const tokLabel = document.createElement('span');
        tokLabel.style.color = 'var(--text-secondary)';
        tokLabel.textContent = 'AI Analysis Tokens:';
        tokensStat.appendChild(tokLabel);
        const tokVal = document.createElement('strong');
        tokVal.style.color = 'var(--accent-primary)';
        tokVal.textContent = ' ' + totalTokens.toLocaleString();
        tokensStat.appendChild(tokVal);
        statsBar.appendChild(tokensStat);

        // High risk count
        const highRisk = threats.filter(t => t.risk_score >= 60).length;
        const riskStat = document.createElement('div');
        riskStat.innerHTML = '<span style="color:var(--text-secondary)">High Risk:</span> <strong style="color:var(--danger)">' + highRisk + '</strong>';
        statsBar.appendChild(riskStat);

        container.appendChild(statsBar);

        // Threats table
        const self = this;
        const threatsDt = new DataTable({
            columns: [
                { key: 'indicator', label: 'Content', sortable: true, render: (_, threat) => {
                    const code = document.createElement('code');
                    code.className = 'indicator';
                    const text = threat.indicator || threat.name || threat.text_preview || threat.text || 'Unknown';
                    code.textContent = text.length > 60 ? text.substring(0, 60) + '...' : text;
                    code.title = text;
                    return code;
                }},
                { key: 'threat_type', label: 'Type', sortable: true, render: (_, threat) => {
                    const wrap = document.createDocumentFragment();
                    const threatType = threat.threat_type || 'No Threat Detected';
                    const isOutput = threatType.startsWith('output_');
                    if (isOutput) {
                        const lbl = document.createElement('span');
                        lbl.className = 'output-scan-label'; lbl.textContent = 'OUTPUT';
                        wrap.appendChild(lbl);
                    }
                    const badge = document.createElement('span');
                    badge.className = 'type-badge' + (isOutput ? ' output-scan' : '');
                    badge.textContent = isOutput ? threatType.replace('output_', '') : threatType;
                    wrap.appendChild(badge);
                    return wrap;
                }},
                { key: 'risk_score', label: 'Risk Score', sortable: true, defaultDir: 'desc', render: (_, threat) => {
                    const wrap = document.createDocumentFragment();
                    const row = document.createElement('div');
                    row.style.cssText = 'display: flex; align-items: center; gap: 8px;';
                    const badge = document.createElement('span');
                    badge.className = 'risk-badge risk-' + self.getRiskLevel(threat.risk_score);
                    badge.textContent = (threat.risk_score || 0) + '%';
                    row.appendChild(badge);
                    const pct = Math.min(threat.risk_score || 0, 100);
                    const barColor = pct >= 70 ? '#ef4444' : pct >= 40 ? '#f59e0b' : '#10b981';
                    const bar = document.createElement('div');
                    bar.style.cssText = 'width: 40px; height: 4px; border-radius: 2px; background: var(--bg-tertiary); overflow: hidden; flex-shrink: 0;';
                    const fill = document.createElement('div');
                    fill.style.cssText = `height: 100%; border-radius: 2px; background: ${barColor}; width: ${pct}%;`;
                    bar.appendChild(fill); row.appendChild(bar); wrap.appendChild(row);
                    if (threat.llm_reviewed) {
                        const llm = document.createElement('span'); llm.className = 'llm-badge'; llm.textContent = 'LLM';
                        llm.title = 'Reviewed by ' + (threat.llm_model_used || 'LLM'); wrap.appendChild(llm);
                        if (threat.llm_tokens_used > 0) {
                            const tok = document.createElement('span'); tok.className = 'tokens-badge';
                            tok.textContent = threat.llm_tokens_used.toLocaleString() + ' tokens'; wrap.appendChild(tok);
                        }
                    }
                    return wrap;
                }},
                { key: 'user_agent', label: 'Client', sortable: true, render: (_, threat) => {
                    const name = self.parseUserAgent(threat.user_agent);
                    if (name) {
                        const b = document.createElement('span'); b.className = 'client-badge';
                        b.textContent = name; b.title = threat.user_agent || ''; return b;
                    }
                    return '-';
                }},
                { key: 'first_seen', label: 'Time', sortable: true, defaultDir: 'desc', render: (_, threat) =>
                    self.formatDate(threat.first_seen || threat.created_at)
                },
                { key: 'action_taken', label: 'Action', render: (_, threat) => {
                    const action = threat.action_taken || 'logged';
                    const ab = document.createElement('span');
                    ab.className = 'action-badge action-' + action;
                    ab.textContent = action.charAt(0).toUpperCase() + action.slice(1);
                    return ab;
                }},
            ],
            data: threats,
            selectable: true,
            rowActions: [
                { icon: '\u{1F441}', title: 'View details', onClick: (t) => self.showThreatDetails(t) },
            ],
            bulkActions: [
                { label: 'Delete', className: 'btn btn-sm btn-danger', onClick: (ids) => self.bulkDelete(ids) },
            ],
            idField: 'id',
            sortKey: this.sortColumn,
            sortDir: this.sortDirection,
            customSort: (data, key, dir) => {
                const d = dir === 'asc' ? 1 : -1;
                return data.sort((a, b) => {
                    let va, vb;
                    if (key === 'indicator') {
                        va = (a.indicator || a.name || a.text_preview || a.text || '').toLowerCase();
                        vb = (b.indicator || b.name || b.text_preview || b.text || '').toLowerCase();
                    } else if (key === 'risk_score') {
                        return ((a.risk_score || 0) - (b.risk_score || 0)) * d;
                    } else if (key === 'first_seen') {
                        return (new Date(a.first_seen || a.created_at || 0).getTime() - new Date(b.first_seen || b.created_at || 0).getTime()) * d;
                    } else {
                        va = (a[key] || '').toString().toLowerCase();
                        vb = (b[key] || '').toString().toLowerCase();
                    }
                    if (va < vb) return -1 * d;
                    if (va > vb) return 1 * d;
                    return 0;
                });
            },
            onSort: (key, dir) => {
                self.sortColumn = key; self.sortDirection = dir;
                self.renderContent(document.getElementById('threats-content'));
            },
            onRowClick: (threat) => self.showThreatDetails(threat),
            onSelectChange: (ids) => {
                self.selectedIds = ids;
                self.updateDeleteButton();
            },
            tableId: 'threats-data-table',
            emptyText: 'No threats detected.',
        });
        threatsDt.selectedIds = new Set(this.selectedIds);
        container.appendChild(threatsDt.el);

        // Pagination
        if (this.data.total_pages > 1) {
            const pagination = this.createPagination();
            container.appendChild(pagination);
        }

        // Update delete button visibility
        this.updateDeleteButton();
    },

    createPagination() {
        const pagination = document.createElement('div');
        pagination.className = 'pagination';

        const prevBtn = document.createElement('button');
        prevBtn.className = 'btn btn-small';
        prevBtn.textContent = 'Previous';
        prevBtn.disabled = this.filters.page <= 1;
        prevBtn.addEventListener('click', () => {
            this.filters.page--;
            this.loadData();
        });
        pagination.appendChild(prevBtn);

        const pageInfo = document.createElement('span');
        pageInfo.className = 'page-info';
        pageInfo.textContent = 'Page ' + this.filters.page + ' of ' + (this.data.total_pages || 1);
        pagination.appendChild(pageInfo);

        const nextBtn = document.createElement('button');
        nextBtn.className = 'btn btn-small';
        nextBtn.textContent = 'Next';
        nextBtn.disabled = this.filters.page >= (this.data.total_pages || 1);
        nextBtn.addEventListener('click', () => {
            this.filters.page++;
            this.loadData();
        });
        pagination.appendChild(nextBtn);

        return pagination;
    },

    showThreatDetails(threat) {
        const content = document.createElement('div');
        content.className = 'threat-details';

        // Risk badge at top
        const riskHeader = document.createElement('div');
        riskHeader.className = 'threat-detail-risk';
        const riskBadge = document.createElement('span');
        riskBadge.className = 'risk-badge risk-' + this.getRiskLevel(threat.risk_score);
        riskBadge.textContent = (threat.risk_score || 0) + '% Risk';
        riskHeader.appendChild(riskBadge);
        const typeBadge = document.createElement('span');
        typeBadge.className = 'type-badge';
        typeBadge.textContent = threat.threat_type || 'No Threat Detected';
        typeBadge.style.marginLeft = '8px';
        riskHeader.appendChild(typeBadge);
        content.appendChild(riskHeader);

        // LLM Review Analytics (if LLM review was performed) - at top for visibility
        if (threat.llm_reviewed) {
            const llmSection = document.createElement('div');
            llmSection.className = 'threat-detail-section llm-review-section llm-expandable';

            // Clickable header for expand/collapse
            const llmHeader = document.createElement('div');
            llmHeader.className = 'detail-section-label llm-section-header llm-toggle';
            llmHeader.style.cursor = 'pointer';

            const llmIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            llmIcon.setAttribute('viewBox', '0 0 24 24');
            llmIcon.setAttribute('fill', 'none');
            llmIcon.setAttribute('stroke', 'currentColor');
            llmIcon.setAttribute('stroke-width', '2');
            llmIcon.setAttribute('class', 'llm-icon');
            const llmPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            llmPath.setAttribute('d', 'M12 2a10 10 0 1 0 10 10H12V2zM12 12l6-6');
            llmIcon.appendChild(llmPath);
            llmHeader.appendChild(llmIcon);

            const llmTitle = document.createElement('span');
            llmTitle.textContent = 'LLM Review';
            llmHeader.appendChild(llmTitle);

            // Model badge
            if (threat.llm_model_used) {
                const modelBadge = document.createElement('span');
                modelBadge.className = 'llm-model-badge';
                modelBadge.textContent = threat.llm_model_used;
                llmHeader.appendChild(modelBadge);
            }

            // Expand/collapse arrow
            const expandArrow = document.createElement('span');
            expandArrow.className = 'llm-expand-arrow';
            expandArrow.textContent = '▼';
            llmHeader.appendChild(expandArrow);

            llmSection.appendChild(llmHeader);

            // Collapsible content wrapper
            const llmContent = document.createElement('div');
            llmContent.className = 'llm-content expanded';

            // LLM Verdict
            const verdictRow = document.createElement('div');
            verdictRow.className = 'llm-verdict-row';

            const verdictLabel = document.createElement('span');
            verdictLabel.className = 'llm-verdict-label';
            verdictLabel.textContent = 'LLM Verdict:';
            verdictRow.appendChild(verdictLabel);

            const verdictBadge = document.createElement('span');
            verdictBadge.className = 'llm-verdict-badge ' + (threat.llm_agrees ? 'agrees' : 'disagrees');
            verdictBadge.textContent = threat.llm_agrees ? 'Agrees with Detection' : 'Disagrees';
            verdictRow.appendChild(verdictBadge);

            llmContent.appendChild(verdictRow);

            // LLM Confidence
            if (threat.llm_confidence !== undefined && threat.llm_confidence > 0) {
                const confRow = document.createElement('div');
                confRow.className = 'llm-stat-row';

                const confLabel = document.createElement('span');
                confLabel.className = 'llm-stat-label';
                confLabel.textContent = 'LLM Confidence';
                confRow.appendChild(confLabel);

                const confValue = document.createElement('span');
                confValue.className = 'llm-stat-value';
                confValue.textContent = Math.round(threat.llm_confidence * 100) + '%';
                confRow.appendChild(confValue);

                llmContent.appendChild(confRow);
            }

            // Risk Adjustment
            if (threat.llm_risk_adjustment && threat.llm_risk_adjustment !== 0) {
                const adjRow = document.createElement('div');
                adjRow.className = 'llm-stat-row';

                const adjLabel = document.createElement('span');
                adjLabel.className = 'llm-stat-label';
                adjLabel.textContent = 'Risk Adjustment';
                adjRow.appendChild(adjLabel);

                const adjValue = document.createElement('span');
                adjValue.className = 'llm-stat-value ' + (threat.llm_risk_adjustment > 0 ? 'risk-up' : 'risk-down');
                adjValue.textContent = (threat.llm_risk_adjustment > 0 ? '+' : '') + threat.llm_risk_adjustment + '%';
                adjRow.appendChild(adjValue);

                llmContent.appendChild(adjRow);
            }

            // Tokens Used
            if (threat.llm_tokens_used && threat.llm_tokens_used > 0) {
                const tokensRow = document.createElement('div');
                tokensRow.className = 'llm-stat-row';

                const tokensLabel = document.createElement('span');
                tokensLabel.className = 'llm-stat-label';
                tokensLabel.textContent = 'Tokens Used';
                tokensRow.appendChild(tokensLabel);

                const tokensValue = document.createElement('span');
                tokensValue.className = 'llm-stat-value';
                tokensValue.textContent = threat.llm_tokens_used.toLocaleString();
                tokensRow.appendChild(tokensValue);

                llmContent.appendChild(tokensRow);
            }

            // LLM Recommendation
            if (threat.llm_recommendation) {
                const recBox = document.createElement('div');
                recBox.className = 'llm-recommendation-box';

                const recLabel = document.createElement('div');
                recLabel.className = 'llm-recommendation-label';
                recLabel.textContent = 'Recommended Action';
                recBox.appendChild(recLabel);

                const recText = document.createElement('div');
                recText.className = 'llm-recommendation-text';
                recText.textContent = threat.llm_recommendation;
                recBox.appendChild(recText);

                llmContent.appendChild(recBox);
            }

            // LLM Reasoning
            if (threat.llm_reasoning || threat.llm_explanation) {
                const reasoningBox = document.createElement('div');
                reasoningBox.className = 'llm-reasoning-box';

                const reasoningLabel = document.createElement('div');
                reasoningLabel.className = 'llm-reasoning-label';
                reasoningLabel.textContent = 'LLM Analysis';
                reasoningBox.appendChild(reasoningLabel);

                const reasoningText = document.createElement('div');
                reasoningText.className = 'llm-reasoning-text';
                reasoningText.textContent = threat.llm_reasoning || threat.llm_explanation;
                reasoningBox.appendChild(reasoningText);

                llmContent.appendChild(reasoningBox);
            }

            // Save button
            const saveRow = document.createElement('div');
            saveRow.className = 'llm-save-row';
            const saveBtn = document.createElement('button');
            saveBtn.className = 'btn btn-primary llm-save-btn';
            saveBtn.textContent = 'Save Analysis';
            saveBtn.addEventListener('click', () => {
                // Copy analysis to clipboard
                const analysisText = [
                    'LLM Review: ' + (threat.llm_model_used || 'Unknown'),
                    'Verdict: ' + (threat.llm_agrees ? 'Agrees' : 'Disagrees'),
                    'Confidence: ' + Math.round((threat.llm_confidence || 0) * 100) + '%',
                    'Recommendation: ' + (threat.llm_recommendation || 'N/A'),
                    'Analysis: ' + (threat.llm_reasoning || threat.llm_explanation || 'N/A'),
                ].join('\n');
                navigator.clipboard.writeText(analysisText).then(() => {
                    saveBtn.textContent = 'Copied!';
                    setTimeout(() => { saveBtn.textContent = 'Save Analysis'; }, 2000);
                });
            });
            saveRow.appendChild(saveBtn);
            llmContent.appendChild(saveRow);

            llmSection.appendChild(llmContent);

            // Toggle expand/collapse
            llmHeader.addEventListener('click', () => {
                const isExpanded = llmContent.classList.contains('expanded');
                llmContent.classList.toggle('expanded');
                expandArrow.textContent = isExpanded ? '▶' : '▼';
            });

            content.appendChild(llmSection);
        }

        // Content preview — show Context and Prompt separately when available
        const textContent = threat.text_content || threat.text_preview || threat.indicator || threat.name || '';
        const contextText = threat.metadata && threat.metadata.context_text;

        if (contextText) {
            // Show Context section (injected by plugins / platform metadata)
            const ctxSection = document.createElement('div');
            ctxSection.className = 'threat-detail-section';

            const ctxLabel = document.createElement('div');
            ctxLabel.className = 'detail-section-label';
            ctxLabel.textContent = 'Context (injected by plugin)';
            ctxSection.appendChild(ctxLabel);

            const ctxBox = document.createElement('div');
            ctxBox.className = 'threat-detail-text';
            ctxBox.style.cssText = 'opacity: 0.7; font-size: 12px;';
            ctxBox.textContent = contextText;
            ctxSection.appendChild(ctxBox);

            content.appendChild(ctxSection);
        }

        if (textContent) {
            const textSection = document.createElement('div');
            textSection.className = 'threat-detail-section';

            const textLabel = document.createElement('div');
            textLabel.className = 'detail-section-label';
            textLabel.textContent = contextText ? 'Prompt (scanned)' : 'Analyzed Content';
            textSection.appendChild(textLabel);

            const textBox = document.createElement('div');
            textBox.className = 'threat-detail-text';
            textBox.textContent = textContent;
            textSection.appendChild(textBox);

            content.appendChild(textSection);
        }

        // Details grid
        const detailsSection = document.createElement('div');
        detailsSection.className = 'threat-detail-section';

        const detailsLabel = document.createElement('div');
        detailsLabel.className = 'detail-section-label';
        detailsLabel.textContent = 'Details';
        detailsSection.appendChild(detailsLabel);

        const fields = [
            { label: 'Confidence', value: (threat.confidence || 0) + '%' },
            { label: 'First Seen', value: this.formatDate(threat.first_seen || threat.created_at) },
            { label: 'Processing Time', value: (threat.processing_time_ms || 0) + 'ms' },
            { label: 'Source', value: threat.source_identifier || 'Local' },
            { label: 'Client', value: this.parseUserAgent(threat.user_agent) },
            // Per-machine attribution: the hashed device_id tells a SOC which
            // laptop saw this threat when the same n8n/agent account is used
            // across a fleet. Null for pre-v21 rows — skip in that case.
            { label: 'Device', value: threat.device_id || null, mono: true, tooltip: 'Stable per-device identifier (SHA-256-hashed from the OS machine UUID). Survives app reinstall on the same hardware.' },
        ];

        const grid = document.createElement('div');
        grid.className = 'detail-grid';

        fields.forEach(field => {
            if (!field.value) return;

            const row = document.createElement('div');
            row.className = 'detail-row';

            const label = document.createElement('span');
            label.className = 'detail-label';
            label.textContent = field.label;
            row.appendChild(label);

            const value = document.createElement('span');
            value.className = 'detail-value';
            if (field.mono) {
                value.style.fontFamily = 'monospace';
                value.style.fontSize = '12px';
            }
            if (field.tooltip) {
                value.title = field.tooltip;
            }
            value.textContent = field.value;
            row.appendChild(value);

            grid.appendChild(row);
        });

        detailsSection.appendChild(grid);
        content.appendChild(detailsSection);

        // Matched rules
        if (threat.matched_rules && threat.matched_rules.length > 0) {
            const rulesSection = document.createElement('div');
            rulesSection.className = 'threat-detail-section';

            const rulesLabel = document.createElement('div');
            rulesLabel.className = 'detail-section-label';
            rulesLabel.textContent = 'Matched Rules (' + threat.matched_rules.length + ')';
            rulesSection.appendChild(rulesLabel);

            const rulesList = document.createElement('div');
            rulesList.className = 'matched-rules-list';

            threat.matched_rules.forEach(rule => {
                const ruleItem = document.createElement('div');
                ruleItem.className = 'matched-rule-item';

                const ruleName = document.createElement('div');
                ruleName.className = 'matched-rule-name';
                ruleName.textContent = rule.rule_name || rule.name || rule.rule_id || 'Unknown Rule';
                ruleItem.appendChild(ruleName);

                if (rule.category) {
                    const ruleCat = document.createElement('span');
                    ruleCat.className = 'matched-rule-cat';
                    ruleCat.textContent = rule.category;
                    ruleItem.appendChild(ruleCat);
                }

                rulesList.appendChild(ruleItem);
            });

            rulesSection.appendChild(rulesList);
            content.appendChild(rulesSection);
        }

        // Use side drawer instead of modal
        SideDrawer.show({
            title: 'Threat Details',
            content: content,
        });
    },

    getRiskLevel(score) {
        if (score >= 80) return 'critical';
        if (score >= 60) return 'high';
        if (score >= 40) return 'medium';
        return 'low';
    },

    formatDate(dateStr) {
        if (!dateStr) return '-';
        try {
            const date = new Date(dateStr);
            return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
        } catch (e) {
            return dateStr;
        }
    },

    parseUserAgent(userAgent) {
        if (!userAgent) return null;
        // Extract friendly client name from user agent
        if (userAgent.includes('SecureVector-Proxy') || userAgent.includes('OpenClaw')) return 'OpenClaw';
        if (userAgent.includes('LangGraph')) return 'LangGraph';
        if (userAgent.includes('LangChain')) return 'LangChain';
        if (userAgent.includes('Claude')) return 'Claude';
        if (userAgent.includes('python-requests')) return 'Python Requests';
        if (userAgent.includes('curl')) return 'cURL';
        if (userAgent.includes('Chrome')) {
            const match = userAgent.match(/Chrome\/([\d.]+)/);
            return match ? 'Chrome ' + match[1].split('.')[0] : 'Chrome';
        }
        if (userAgent.includes('Firefox')) {
            const match = userAgent.match(/Firefox\/([\d.]+)/);
            return match ? 'Firefox ' + match[1].split('.')[0] : 'Firefox';
        }
        if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) return 'Safari';
        if (userAgent.includes('Edge')) return 'Edge';
        // Return first 30 chars if unknown
        return userAgent.substring(0, 30) + (userAgent.length > 30 ? '...' : '');
    },

    renderEmptyState(container) {
        const empty = document.createElement('div');
        empty.className = 'empty-state';

        // Icon
        const iconWrapper = document.createElement('div');
        iconWrapper.className = 'empty-state-icon';
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('viewBox', '0 0 24 24');
        svg.setAttribute('fill', 'none');
        svg.setAttribute('stroke', 'currentColor');
        svg.setAttribute('stroke-width', '1.5');
        const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path.setAttribute('d', 'M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z');
        svg.appendChild(path);
        iconWrapper.appendChild(svg);
        empty.appendChild(iconWrapper);

        const title = document.createElement('div');
        title.className = 'empty-state-title';
        title.textContent = 'No Threat Analytics';
        empty.appendChild(title);

        const text = document.createElement('p');
        text.className = 'empty-state-text';
        text.textContent = 'No threats have been detected yet. Start the proxy from Integrations and route traffic through SecureVector to begin detecting threats.';
        empty.appendChild(text);

        const btn = document.createElement('button');
        btn.className = 'btn btn-primary';
        btn.textContent = 'Get Started';
        btn.addEventListener('click', () => {
            if (window.Sidebar) {
                Sidebar._pendingScroll = 'section-getting-started';
                Sidebar.navigate('guide');
            }
        });
        empty.appendChild(btn);

        container.appendChild(empty);
    },

    renderError(container, error) {
        container.textContent = '';

        const errorDiv = document.createElement('div');
        errorDiv.className = 'error-state';

        const message = document.createElement('p');
        message.textContent = 'Failed to load threats';
        errorDiv.appendChild(message);

        const retry = document.createElement('button');
        retry.className = 'btn btn-primary';
        retry.textContent = 'Retry';
        retry.addEventListener('click', () => this.loadData());
        errorDiv.appendChild(retry);

        container.appendChild(errorDiv);
    },
};

window.ThreatsPage = ThreatsPage;
