import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { Card } from '../components/Card';
import { Badge } from '../components/Badge';
import { ScannerSkeleton } from '../components/Skeleton';
import { useConfig, wpApiFetch, externalApiFetch } from '../hooks/useApi';
import { useNotify } from '../hooks/useNotify';
import type { MonitoredPlugin, Vulnerability, VulnerabilityStatus } from '@cra-compliance/types';

interface InstalledPlugin {
  slug: string;
  name: string;
  version: string;
  author: string;
}

export function Scanner() {
  const config = useConfig();
  const isPremium = config.plan !== 'free';

  if (!isPremium) {
    return <ScannerUpsell />;
  }

  return <PremiumScanner />;
}

function PremiumScanner() {
  const queryClient = useQueryClient();
  const { confirm, NotifyPortal } = useNotify();
  const [showAddPlugin, setShowAddPlugin] = useState(false);
  const [addMode, setAddMode] = useState<'installed' | 'slug'>('installed');
  const [manualSlug, setManualSlug] = useState('');
  const [manualName, setManualName] = useState('');
  const [manualVersion, setManualVersion] = useState('');
  const [selectedPlugins, setSelectedPlugins] = useState<Set<string>>(new Set());
  const [selectedToAdd, setSelectedToAdd] = useState<Set<string>>(new Set());
  const [scanning, setScanning] = useState<Set<string>>(new Set());
  const [statusFilter, setStatusFilter] = useState<'all' | VulnerabilityStatus | 'open_active'>('open_active');
  const [error, setError] = useState<string | null>(null);
  const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(new Set());
  const [copiedSummary, setCopiedSummary] = useState(false);
  const [selectedVulnIds, setSelectedVulnIds] = useState<Set<string>>(new Set());

  const toggleGroup = (key: string) => {
    setCollapsedGroups((prev) => {
      const next = new Set(prev);
      next.has(key) ? next.delete(key) : next.add(key);
      return next;
    });
  };

  // ── Data fetching ────────────────────────────────────────────────────────────

  const pluginsQuery = useQuery<MonitoredPlugin[]>({
    queryKey: ['monitored-plugins'],
    queryFn: async () => {
      const res = await externalApiFetch<{ data: MonitoredPlugin[] }>('/api/plugins');
      return res.data || [];
    },
  });

  const vulnsQuery = useQuery<Vulnerability[]>({
    queryKey: ['vulnerabilities'],
    queryFn: async () => {
      const res = await externalApiFetch<{ data: Vulnerability[] }>('/api/vulnerabilities');
      return res.data || [];
    },
  });

  const installedQuery = useQuery<InstalledPlugin[]>({
    queryKey: ['installed-plugins'],
    queryFn: async () => {
      const res = await wpApiFetch<{ data: InstalledPlugin[] }>('installed-plugins');
      return res.data || [];
    },
  });

  // ── Mutations ────────────────────────────────────────────────────────────────

  const addPluginsMutation = useMutation<void, Error, InstalledPlugin[]>({
    mutationFn: async (toAdd) => {
      await Promise.all(
        toAdd.map((p) =>
          externalApiFetch('/api/plugins', {
            method: 'POST',
            body: JSON.stringify({ slug: p.slug, name: p.name, version: p.version }),
          })
        )
      );
    },
    onSuccess: async () => {
      setSelectedToAdd(new Set());
      setShowAddPlugin(false);
      await queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] });
    },
    onError: (err) => setError(err.message || 'Failed to add plugins'),
  });

  const addManualPluginMutation = useMutation<void, Error, void>({
    mutationFn: async () => {
      const slug = manualSlug.trim().toLowerCase();
      if (!slug) throw new Error('Slug is required');
      if (!/^[a-z0-9-]+$/.test(slug)) throw new Error('Slug must contain only lowercase letters, numbers, and hyphens');
      await externalApiFetch('/api/plugins', {
        method: 'POST',
        body: JSON.stringify({
          slug,
          name: manualName.trim() || slug,
          version: manualVersion.trim() || '0.0.0',
        }),
      });
    },
    onSuccess: async () => {
      setManualSlug('');
      setManualName('');
      setManualVersion('');
      setShowAddPlugin(false);
      await queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] });
    },
    onError: (err) => setError(err.message || 'Failed to add plugin'),
  });

  const removePluginMutation = useMutation<void, Error, string>({
    mutationFn: async (pluginId) => {
      await externalApiFetch('/api/plugins', {
        method: 'DELETE',
        body: JSON.stringify({ plugin_id: pluginId }),
      });
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] });
      await queryClient.invalidateQueries({ queryKey: ['vulnerabilities'] });
    },
    onError: (err) => setError(err.message || 'Failed to remove plugin'),
  });

  const updateVulnMutation = useMutation<void, Error, { id: string; status: VulnerabilityStatus }>({
    mutationFn: async ({ id, status }) => {
      await externalApiFetch('/api/vulnerabilities', {
        method: 'PATCH',
        body: JSON.stringify({ vulnerability_id: id, status }),
      });
    },
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ['vulnerabilities'] });
      await queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] });
    },
    onError: (err) => setError(err.message || 'Failed to update status'),
  });

  const bulkUpdateMutation = useMutation<void, Error, { ids: string[]; status: VulnerabilityStatus }>({
    mutationFn: async ({ ids, status }) => {
      await Promise.all(
        ids.map((id) =>
          externalApiFetch('/api/vulnerabilities', {
            method: 'PATCH',
            body: JSON.stringify({ vulnerability_id: id, status }),
          })
        )
      );
    },
    onSuccess: async () => {
      setSelectedVulnIds(new Set());
      await queryClient.invalidateQueries({ queryKey: ['vulnerabilities'] });
      await queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] });
    },
    onError: (err) => setError(err.message || 'Failed to bulk update'),
  });

  // ── Scan helpers ─────────────────────────────────────────────────────────────

  const doScan = async (pluginId: string) => {
    setScanning((prev) => new Set(prev).add(pluginId));
    setError(null);
    try {
      await externalApiFetch('/api/scan', {
        method: 'POST',
        body: JSON.stringify({ plugin_id: pluginId }),
      });
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] }),
        queryClient.invalidateQueries({ queryKey: ['vulnerabilities'] }),
      ]);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Scan failed');
    } finally {
      setScanning((prev) => { const n = new Set(prev); n.delete(pluginId); return n; });
    }
  };

  const triggerBulkScan = async () => {
    const ids = Array.from(selectedPlugins);
    setScanning(new Set(ids));
    setError(null);
    try {
      await Promise.all(
        ids.map((id) =>
          externalApiFetch('/api/scan', {
            method: 'POST',
            body: JSON.stringify({ plugin_id: id }),
          }).catch(() => null)
        )
      );
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] }),
        queryClient.invalidateQueries({ queryKey: ['vulnerabilities'] }),
      ]);
    } finally {
      setScanning(new Set());
      setSelectedPlugins(new Set());
    }
  };

  const startIncidentForVuln = async (vuln: Vulnerability) => {
    setError(null);
    try {
      const res = await externalApiFetch<{ data: { id: string } }>('/api/dashboard', {
        method: 'POST',
        body: JSON.stringify({
          action: 'incidents_start',
          vulnerability_id: vuln.id,
          plugin_id: vuln.plugin_id,
          actively_exploited: vuln.severity === 'critical' || vuln.severity === 'high',
        }),
      });
      // Store the new incident ID so the Incident Center auto-selects it
      if (res.data?.id) {
        sessionStorage.setItem('cra_selected_incident', res.data.id);
      }
      window.location.hash = '#/incidents';
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to start incident');
    }
  };

  const exportCsv = (vulns: Vulnerability[]) => {
    if (vulns.length === 0) return;
    const headers = ['title', 'severity', 'status', 'cve_id', 'plugin_id', 'fixed_in_version', 'discovered_at'];
    const rows = vulns.map((v) =>
      headers.map((h) => {
        const val = v[h as keyof Vulnerability] ?? '';
        const str = String(val);
        return str.includes(',') || str.includes('"') || str.includes('\n')
          ? `"${str.replace(/"/g, '""')}"` : str;
      }).join(',')
    );
    const csv = [headers.join(','), ...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 = `vulnerabilities-${new Date().toISOString().slice(0, 10)}.csv`;
    a.click();
    URL.revokeObjectURL(url);
  };

  const copyCveSummary = (vulns: Vulnerability[]) => {
    if (vulns.length === 0) return;
    const open = vulns.filter((v) => v.status === 'open' || v.status === 'acknowledged' || v.status === 'in_progress');
    if (open.length === 0) {
      void navigator.clipboard.writeText('No open vulnerabilities.');
      return;
    }
    const lines = open.map((v) => {
      const plugin = pluginById.get(v.plugin_id);
      const cve = v.cve_id ? ` (${v.cve_id})` : '';
      const fix = v.fixed_in_version ? ` - fix: v${v.fixed_in_version}` : ' - no fix yet';
      const pluginName = plugin ? plugin.name : v.plugin_id;
      return `[${v.severity.toUpperCase()}] ${pluginName}: ${v.title}${cve}${fix}`;
    });
    void navigator.clipboard.writeText(lines.join('\n'));
  };

  // ── Derived state ────────────────────────────────────────────────────────────

  const plugins = pluginsQuery.data || [];
  const allVulns = vulnsQuery.data || [];
  const installed = installedQuery.data || [];

  const monitoredSlugs = new Set(plugins.map((p) => p.slug));
  const availableToAdd = installed.filter((p) => !monitoredSlugs.has(p.slug));

  // Map installed versions by slug for version mismatch detection
  const installedVersionBySlug = new Map(installed.map((p) => [p.slug, p.version]));

  const pluginById = new Map(plugins.map((p) => [p.id, p]));

  const filteredVulns = allVulns.filter((v) => {
    if (statusFilter === 'open_active') return v.status === 'open' || v.status === 'acknowledged' || v.status === 'in_progress';
    if (statusFilter === 'all') return true;
    return v.status === statusFilter;
  });

  // Within each group: sort by severity then date desc so newest critical appears first
  const SEVERITY_RANK: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };

  // Group by plugin first (preserving API order), then sort within each group
  const vulnsByPlugin = new Map<string, Vulnerability[]>();
  for (const v of filteredVulns) {
    const list = vulnsByPlugin.get(v.plugin_id) || [];
    list.push(v);
    vulnsByPlugin.set(v.plugin_id, list);
  }
  for (const [, vulns] of vulnsByPlugin) {
    vulns.sort((a, b) => {
      const rankDiff = (SEVERITY_RANK[a.severity] ?? 5) - (SEVERITY_RANK[b.severity] ?? 5);
      if (rankDiff !== 0) return rankDiff;
      return new Date(b.discovered_at ?? 0).getTime() - new Date(a.discovered_at ?? 0).getTime();
    });
  }

  // Sort plugin groups by the most recently discovered vuln in each group (newest first)
  const sortedPluginGroups = Array.from(vulnsByPlugin.entries()).sort(([, aVulns], [, bVulns]) => {
    const aNewest = Math.max(...aVulns.map((v) => new Date(v.discovered_at ?? 0).getTime()));
    const bNewest = Math.max(...bVulns.map((v) => new Date(v.discovered_at ?? 0).getTime()));
    return bNewest - aNewest;
  });

  const isLoading = pluginsQuery.isLoading || vulnsQuery.isLoading;

  const nextScanLabel = (() => {
    const now = new Date();
    const next = new Date(now);
    next.setUTCHours(3, 0, 0, 0);
    if (next <= now) next.setUTCDate(next.getUTCDate() + 1);
    const diffMs = next.getTime() - now.getTime();
    const diffH = Math.floor(diffMs / 3600000);
    const diffM = Math.floor((diffMs % 3600000) / 60000);
    return diffH > 0 ? `in ${diffH}h ${diffM}m` : `in ${diffM}m`;
  })();

  // ── Stats ────────────────────────────────────────────────────────────────────

  const criticalCount = allVulns.filter((v) => v.severity === 'critical' && v.status !== 'resolved' && v.status !== 'false_positive').length;
  const highCount = allVulns.filter((v) => v.severity === 'high' && v.status !== 'resolved' && v.status !== 'false_positive').length;
  const secureCount = plugins.filter((p) => p.status === 'secure').length;
  const vulnerableCount = plugins.filter((p) => p.status === 'vulnerable').length;

  if (isLoading) {
    return <ScannerSkeleton />;
  }

  return (
    <div className="cra-scanner-page">
      <NotifyPortal />
      <div className="cra-page-header">
        <div>
          <h2>Vulnerability Scanner</h2>
          <p className="cra-muted" style={{ margin: 0, fontSize: '13px' }}>
            Next scheduled scan {nextScanLabel} · 3:00 AM UTC daily
          </p>
        </div>
        <button
          className="cra-btn cra-btn-primary cra-btn-sm"
          onClick={() => setShowAddPlugin((v) => !v)}
        >
          + Add Plugin
        </button>
      </div>

      {/* Explainer: what to do with this information */}
      <div className="cra-info-box" style={{ marginBottom: '16px' }}>
        <strong>What to do with vulnerabilities</strong>
        <p style={{ margin: '6px 0 0', fontSize: '13px', color: 'var(--cra-muted)' }}>
          Under the EU Cyber Resilience Act (CRA), you must monitor your plugin for known vulnerabilities and act on them. For each vulnerability found:
        </p>
        <ol style={{ margin: '8px 0 0 18px', fontSize: '13px', color: 'var(--cra-muted)', lineHeight: '1.7' }}>
          <li><strong>Update or patch</strong> the plugin if a fix is available (shown as "Fix: vX.X.X"). Mark it <em>Resolved</em> once done.</li>
          <li><strong>Acknowledge</strong> it if you have reviewed it and it does not affect your deployment (e.g. a feature you don&apos;t use).</li>
          <li><strong>Start an Incident</strong> for critical/high severity vulnerabilities that are actively exploited — CRA Article 14 requires you to report these to your national CSIRT within 24 hours of awareness.</li>
        </ol>
        <p style={{ margin: '8px 0 0', fontSize: '13px', color: 'var(--cra-muted)' }}>
          Historical vulnerabilities in older versions are shown for awareness but are less urgent if you are already on a patched version.
        </p>
      </div>

      {/* Error banner */}
      {error && (
        <div className="cra-alert cra-alert-error" style={{ marginBottom: '16px' }}>
          {error}
          <button
            className="cra-btn-text"
            style={{ marginLeft: '8px', fontSize: '12px' }}
            onClick={() => setError(null)}
          >
            Dismiss
          </button>
        </div>
      )}

      {/* Stats row */}
      {plugins.length > 0 && (
        <div className="cra-scanner-stats">
          <div className="cra-scanner-stat">
            <span className="cra-scanner-stat-value">{plugins.length}</span>
            <span className="cra-scanner-stat-label">Monitored</span>
          </div>
          <div className="cra-scanner-stat cra-scanner-stat-ok">
            <span className="cra-scanner-stat-value">{secureCount}</span>
            <span className="cra-scanner-stat-label">Secure</span>
          </div>
          <div className={`cra-scanner-stat ${vulnerableCount > 0 ? 'cra-scanner-stat-danger' : ''}`}>
            <span className="cra-scanner-stat-value">{vulnerableCount}</span>
            <span className="cra-scanner-stat-label">Vulnerable</span>
          </div>
          {criticalCount > 0 && (
            <div className="cra-scanner-stat cra-scanner-stat-danger">
              <span className="cra-scanner-stat-value">{criticalCount}</span>
              <span className="cra-scanner-stat-label">Critical</span>
            </div>
          )}
          {highCount > 0 && (
            <div className="cra-scanner-stat cra-scanner-stat-warning">
              <span className="cra-scanner-stat-value">{highCount}</span>
              <span className="cra-scanner-stat-label">High</span>
            </div>
          )}
        </div>
      )}

      {/* Add Plugin panel */}
      {showAddPlugin && (
        <Card
          title="Add Plugins to Monitor"
          actions={
            addMode === 'installed' && selectedToAdd.size > 0 ? (
              <button
                className="cra-btn cra-btn-primary cra-btn-sm"
                onClick={() => addPluginsMutation.mutate(availableToAdd.filter((p) => selectedToAdd.has(p.slug)))}
                disabled={addPluginsMutation.isPending}
              >
                {addPluginsMutation.isPending ? 'Adding...' : `Monitor ${selectedToAdd.size} Selected`}
              </button>
            ) : undefined
          }
        >
          <div style={{ display: 'flex', gap: '4px', marginBottom: '14px' }}>
            <button
              className={`cra-btn cra-btn-sm${addMode === 'installed' ? ' cra-btn-primary' : ''}`}
              onClick={() => setAddMode('installed')}
            >
              From installed plugins
            </button>
            <button
              className={`cra-btn cra-btn-sm${addMode === 'slug' ? ' cra-btn-primary' : ''}`}
              onClick={() => setAddMode('slug')}
            >
              Add by slug
            </button>
          </div>

          {addMode === 'installed' ? (
            availableToAdd.length === 0 ? (
              <p className="cra-muted">All installed plugins are already monitored.</p>
            ) : (
              <>
                <div style={{ marginBottom: '10px', display: 'flex', alignItems: 'center', gap: '8px' }}>
                  <input
                    type="checkbox"
                    className="cra-checkbox"
                    checked={selectedToAdd.size === availableToAdd.length}
                    onChange={() =>
                      setSelectedToAdd(
                        selectedToAdd.size === availableToAdd.length
                          ? new Set()
                          : new Set(availableToAdd.map((p) => p.slug))
                      )
                    }
                  />
                  <span className="cra-muted" style={{ fontSize: '13px' }}>
                    Select all ({availableToAdd.length} available)
                  </span>
                </div>
                <div className="cra-plugin-list">
                  {availableToAdd.map((p) => (
                    <div key={p.slug} className="cra-plugin-item">
                      <input
                        type="checkbox"
                        className="cra-checkbox"
                        checked={selectedToAdd.has(p.slug)}
                        onChange={() =>
                          setSelectedToAdd((prev) => {
                            const n = new Set(prev);
                            n.has(p.slug) ? n.delete(p.slug) : n.add(p.slug);
                            return n;
                          })
                        }
                      />
                      <div className="cra-plugin-info">
                        <strong>{p.name}</strong>
                        <span className="cra-muted">v{p.version} · {p.author}</span>
                      </div>
                    </div>
                  ))}
                </div>
              </>
            )
          ) : (
            <div className="cra-form" style={{ maxWidth: '480px' }}>
              <p className="cra-muted" style={{ fontSize: '13px', marginBottom: '12px' }}>
                Add any WordPress.org plugin by its slug. Useful for monitoring plugins your plugin
                depends on, even if they are not installed on this site.
              </p>
              <div className="cra-form-field">
                <label>Plugin Slug <span style={{ color: 'var(--cra-danger)' }}>*</span></label>
                <input
                  className="cra-input"
                  placeholder="e.g. woocommerce"
                  value={manualSlug}
                  onChange={(e) => setManualSlug(e.target.value)}
                />
                <span className="cra-muted" style={{ fontSize: '12px' }}>
                  The slug is the last part of the wordpress.org/plugins/YOUR-SLUG URL.
                </span>
              </div>
              <div className="cra-form-row" style={{ display: 'flex', gap: '10px' }}>
                <div className="cra-form-field" style={{ flex: 2 }}>
                  <label>Display Name</label>
                  <input
                    className="cra-input"
                    placeholder="e.g. WooCommerce (optional)"
                    value={manualName}
                    onChange={(e) => setManualName(e.target.value)}
                  />
                </div>
                <div className="cra-form-field" style={{ flex: 1 }}>
                  <label>Version</label>
                  <input
                    className="cra-input"
                    placeholder="e.g. 8.0.0"
                    value={manualVersion}
                    onChange={(e) => setManualVersion(e.target.value)}
                  />
                </div>
              </div>
              <button
                className="cra-btn cra-btn-primary cra-btn-sm"
                onClick={() => addManualPluginMutation.mutate()}
                disabled={addManualPluginMutation.isPending || !manualSlug.trim()}
                style={{ marginTop: '4px' }}
              >
                {addManualPluginMutation.isPending ? 'Adding...' : 'Add Plugin'}
              </button>
            </div>
          )}
        </Card>
      )}

      {/* Monitored Plugins */}
      <Card
        title={`Monitored Plugins${plugins.length > 0 ? ` (${plugins.length})` : ''}`}
        actions={
          selectedPlugins.size > 0 ? (
            <button
              className="cra-btn cra-btn-primary cra-btn-sm"
              onClick={triggerBulkScan}
              disabled={scanning.size > 0}
            >
              {scanning.size > 0 ? `Scanning ${scanning.size}...` : `Scan ${selectedPlugins.size} Selected`}
            </button>
          ) : (
            <button
              className="cra-btn cra-btn-sm"
              onClick={() => {
                void queryClient.invalidateQueries({ queryKey: ['monitored-plugins'] });
                void queryClient.invalidateQueries({ queryKey: ['vulnerabilities'] });
              }}
            >
              Refresh
            </button>
          )
        }
      >
        {plugins.length === 0 ? (
          <div style={{ textAlign: 'center', padding: '32px 0' }}>
            <p className="cra-muted" style={{ marginBottom: '12px' }}>
              No plugins being monitored yet.
            </p>
            <button className="cra-btn cra-btn-primary cra-btn-sm" onClick={() => setShowAddPlugin(true)}>
              + Add Your First Plugin
            </button>
          </div>
        ) : (
          <>
            <div style={{ marginBottom: '10px', display: 'flex', alignItems: 'center', gap: '8px' }}>
              <input
                type="checkbox"
                className="cra-checkbox"
                checked={selectedPlugins.size === plugins.length}
                onChange={() =>
                  setSelectedPlugins(
                    selectedPlugins.size === plugins.length ? new Set() : new Set(plugins.map((p) => p.id))
                  )
                }
              />
              <span className="cra-muted" style={{ fontSize: '13px' }}>Select all</span>
            </div>
            <div className="cra-plugin-list">
              {plugins.map((plugin) => {
                const pluginVulns = allVulns.filter(
                  (v) => v.plugin_id === plugin.id && v.status !== 'resolved' && v.status !== 'false_positive'
                );
                const isScanning = scanning.has(plugin.id);

                return (
                  <div
                    key={plugin.id}
                    className={`cra-plugin-item ${plugin.status === 'vulnerable' ? 'cra-plugin-item-vulnerable' : ''}`}
                  >
                    <input
                      type="checkbox"
                      className="cra-checkbox"
                      checked={selectedPlugins.has(plugin.id)}
                      onChange={() =>
                        setSelectedPlugins((prev) => {
                          const n = new Set(prev);
                          n.has(plugin.id) ? n.delete(plugin.id) : n.add(plugin.id);
                          return n;
                        })
                      }
                    />
                    <div className="cra-plugin-info">
                      <strong>{plugin.name}</strong>
                      <span className="cra-muted">v{plugin.version} · {plugin.slug}</span>
                      {(() => {
                        const installedV = installedVersionBySlug.get(plugin.slug);
                        if (installedV && installedV !== plugin.version) {
                          return (
                            <span className="cra-version-mismatch" title={`Installed: v${installedV} — update the monitored version to scan the right version`}>
                              ⚠ Monitoring v{plugin.version}, installed v{installedV}
                            </span>
                          );
                        }
                        return null;
                      })()}
                    </div>
                    <div className="cra-plugin-status">
                      <Badge
                        variant={
                          plugin.status === 'secure' ? 'success'
                          : plugin.status === 'vulnerable' ? 'danger'
                          : 'neutral'
                        }
                      >
                        {plugin.status === 'vulnerable'
                          ? `${pluginVulns.length} vuln${pluginVulns.length !== 1 ? 's' : ''}`
                          : plugin.status}
                      </Badge>
                      {plugin.last_scanned_at ? (
                        <span className="cra-muted" style={{ fontSize: '12px' }}>
                          Scanned {timeAgo(plugin.last_scanned_at)}
                        </span>
                      ) : (
                        <span className="cra-muted" style={{ fontSize: '12px' }}>Never scanned</span>
                      )}
                    </div>
                    <div style={{ display: 'flex', gap: '6px' }}>
                      <button
                        className="cra-btn cra-btn-sm"
                        onClick={() => void doScan(plugin.id)}
                        disabled={isScanning || scanning.size > 0}
                        style={{ minWidth: '80px' }}
                      >
                        {isScanning ? 'Scanning…' : 'Scan Now'}
                      </button>
                      <button
                        className="cra-btn cra-btn-sm cra-btn-danger"
                        onClick={async () => {
                          const ok = await confirm({
                            message: `Stop monitoring "${plugin.name}"?`,
                            confirmLabel: 'Stop monitoring',
                            danger: true,
                          });
                          if (ok) void removePluginMutation.mutate(plugin.id);
                        }}
                        title="Stop monitoring"
                        style={{ padding: '4px 8px' }}
                      >
                        ×
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>
          </>
        )}
      </Card>

      {/* Vulnerabilities */}
      <Card
        title={
          filteredVulns.length > 0
            ? `Vulnerabilities (${filteredVulns.length}${statusFilter !== 'all' ? ' shown' : ''})`
            : 'Vulnerabilities'
        }
        actions={
          <div style={{ display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap' }}>
            <select
              className="cra-select cra-select-sm"
              value={statusFilter}
              onChange={(e) => setStatusFilter(e.target.value as typeof statusFilter)}
            >
              <option value="open_active">Active (open / in progress)</option>
              <option value="all">All statuses</option>
              <option value="open">Open</option>
              <option value="acknowledged">Acknowledged</option>
              <option value="in_progress">In Progress</option>
              <option value="resolved">Resolved</option>
              <option value="false_positive">False Positive</option>
            </select>
            {filteredVulns.length > 0 && (
              <>
                <button
                  className="cra-btn cra-btn-sm"
                  onClick={() => {
                    copyCveSummary(filteredVulns);
                    setCopiedSummary(true);
                    setTimeout(() => setCopiedSummary(false), 2000);
                  }}
                  title="Copy a plain-text summary of open CVEs to clipboard"
                >
                  {copiedSummary ? 'Copied!' : 'Copy Summary'}
                </button>
                <button className="cra-btn cra-btn-sm" onClick={() => exportCsv(filteredVulns)}>
                  Export CSV
                </button>
              </>
            )}
          </div>
        }
      >
        {allVulns.length === 0 ? (
          <p className="cra-muted">
            {plugins.length === 0
              ? 'Add plugins to monitor, then run a scan to find vulnerabilities.'
              : 'No vulnerabilities found. Run a scan to check your plugins.'}
          </p>
        ) : filteredVulns.length === 0 ? (
          <p className="cra-muted">No vulnerabilities match the current filter.</p>
        ) : (
          <>
            {/* Bulk action bar */}
            <div className="cra-vuln-bulk-bar">
              <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13 }}>
                <input
                  type="checkbox"
                  className="cra-checkbox"
                  checked={selectedVulnIds.size === filteredVulns.length && filteredVulns.length > 0}
                  onChange={() =>
                    setSelectedVulnIds(
                      selectedVulnIds.size === filteredVulns.length
                        ? new Set()
                        : new Set(filteredVulns.map((v) => v.id))
                    )
                  }
                />
                {selectedVulnIds.size > 0 ? `${selectedVulnIds.size} selected` : 'Select all'}
              </label>
              {selectedVulnIds.size > 0 && (
                <div style={{ display: 'flex', gap: 6 }}>
                  <button
                    className="cra-btn cra-btn-sm"
                    disabled={bulkUpdateMutation.isPending}
                    onClick={() => void bulkUpdateMutation.mutate({ ids: Array.from(selectedVulnIds), status: 'acknowledged' })}
                  >
                    Acknowledge ({selectedVulnIds.size})
                  </button>
                  <button
                    className="cra-btn cra-btn-sm"
                    disabled={bulkUpdateMutation.isPending}
                    onClick={() => void bulkUpdateMutation.mutate({ ids: Array.from(selectedVulnIds), status: 'resolved' })}
                  >
                    Mark Resolved ({selectedVulnIds.size})
                  </button>
                  <button
                    className="cra-btn cra-btn-sm"
                    disabled={bulkUpdateMutation.isPending}
                    onClick={() => setSelectedVulnIds(new Set())}
                  >
                    Clear
                  </button>
                </div>
              )}
            </div>
            <div className="cra-vuln-list">
              {sortedPluginGroups.map(([pluginId, vulns]) => {
                const plugin = pluginById.get(pluginId);
                const criticalCount = vulns.filter((v) => v.severity === 'critical').length;
                const highCount = vulns.filter((v) => v.severity === 'high').length;
                const isCollapsed = collapsedGroups.has(pluginId);
                return (
                  <div key={pluginId} className="cra-vuln-group">
                    {plugin && (
                      <button
                        type="button"
                        className="cra-vuln-group-header cra-vuln-group-toggle"
                        onClick={() => toggleGroup(pluginId)}
                        aria-expanded={!isCollapsed}
                      >
                        <div>
                          <strong>{plugin.name}</strong>
                          <span className="cra-muted" style={{ marginLeft: '8px' }}>v{plugin.version}</span>
                        </div>
                        <div style={{ display: 'flex', gap: '6px', alignItems: 'center' }}>
                          {criticalCount > 0 && (
                            <span className="cra-vuln-tag cra-vuln-tag-critical">{criticalCount} critical</span>
                          )}
                          {highCount > 0 && (
                            <span className="cra-vuln-tag cra-vuln-tag-high">{highCount} high</span>
                          )}
                          <span className="cra-muted" style={{ fontSize: '12px' }}>
                            {vulns.length} {vulns.length === 1 ? 'vuln' : 'vulns'}
                          </span>
                          <span className={`cra-vuln-chevron${isCollapsed ? ' cra-vuln-chevron--collapsed' : ''}`} aria-hidden="true">▾</span>
                        </div>
                      </button>
                    )}
                    {!isCollapsed && vulns.map((vuln) => (
                      <VulnRow
                        key={vuln.id}
                        vuln={vuln}
                        selected={selectedVulnIds.has(vuln.id)}
                        onSelect={(id) =>
                          setSelectedVulnIds((prev) => {
                            const next = new Set(prev);
                            next.has(id) ? next.delete(id) : next.add(id);
                            return next;
                          })
                        }
                        onStatusChange={(status) => void updateVulnMutation.mutate({ id: vuln.id, status })}
                        onStartIncident={() => void startIncidentForVuln(vuln)}
                        busy={updateVulnMutation.isPending || bulkUpdateMutation.isPending}
                      />
                    ))}
                  </div>
                );
              })}
            </div>
          </>
        )}
      </Card>
    </div>
  );
}

interface VulnRowProps {
  vuln: Vulnerability;
  selected: boolean;
  onSelect: (id: string) => void;
  onStatusChange: (status: VulnerabilityStatus) => void;
  onStartIncident: () => void;
  busy: boolean;
}

function VulnRow({ vuln, selected, onSelect, onStatusChange, onStartIncident, busy }: VulnRowProps) {
  const severityVariant = vuln.severity === 'critical' ? 'danger'
    : vuln.severity === 'high' ? 'warning'
    : vuln.severity === 'medium' ? 'warning'
    : 'info';

  const actionHint = vuln.fixed_in_version
    ? `Update to v${vuln.fixed_in_version} then mark Resolved`
    : vuln.severity === 'critical' || vuln.severity === 'high'
    ? 'No fix yet — start an incident if actively exploited; otherwise acknowledge'
    : 'No fix available — acknowledge if reviewed and acceptable risk';

  return (
    <div className={`cra-vuln-item cra-vuln-${vuln.severity}${selected ? ' cra-vuln-selected' : ''}`}>
      <div className="cra-vuln-header">
        <input
          type="checkbox"
          className="cra-checkbox"
          checked={selected}
          onChange={() => onSelect(vuln.id)}
          style={{ flexShrink: 0 }}
        />
        <Badge variant={severityVariant}>{vuln.severity.toUpperCase()}</Badge>
        <span className="cra-vuln-title">{vuln.title}</span>
      </div>
      <div className="cra-vuln-meta">
        {vuln.cve_id && (
          <a
            href={`https://nvd.nist.gov/vuln/detail/${vuln.cve_id}`}
            target="_blank"
            rel="noopener noreferrer"
            className="cra-vuln-tag cra-vuln-tag-link"
            title="View on NVD"
          >
            {vuln.cve_id}
          </a>
        )}
        {vuln.cvss_score != null && <span className="cra-vuln-tag">CVSS {vuln.cvss_score}</span>}
        {vuln.fixed_in_version
          ? <span className="cra-vuln-tag cra-vuln-tag-fix">Fix: v{vuln.fixed_in_version}</span>
          : <span className="cra-vuln-tag cra-vuln-tag-nofix">No fix yet</span>}
      </div>
      <p className="cra-vuln-hint">{actionHint}</p>
      <div className="cra-vuln-actions">
        <select
          className="cra-select cra-select-sm"
          value={vuln.status}
          onChange={(e) => onStatusChange(e.target.value as VulnerabilityStatus)}
          disabled={busy}
        >
          <option value="open">Open</option>
          <option value="acknowledged">Acknowledged</option>
          <option value="in_progress">In Progress</option>
          <option value="resolved">Resolved</option>
          <option value="false_positive">False Positive</option>
        </select>
        {vuln.status !== 'resolved' && vuln.status !== 'false_positive' && (
          <button
            className="cra-btn cra-btn-sm cra-btn-danger"
            onClick={onStartIncident}
            title="Create a CRA Article 14 incident report for this vulnerability"
          >
            Report Incident
          </button>
        )}
      </div>
    </div>
  );
}

function ScannerUpsell() {
  return (
    <div className="cra-scanner-page">
      <div className="cra-page-header">
        <h2>Vulnerability Scanner</h2>
        <p>Automated daily scanning of your WordPress plugins against the WPScan CVE database.</p>
      </div>

      <div className="cra-upsell-hero">
        <div className="cra-upsell-hero-text">
          <h3>Know about vulnerabilities before your users do</h3>
          <p>
            The EU Cyber Resilience Act (CRA) requires you to actively monitor your plugin for known
            vulnerabilities and act on them promptly. Article 13 obliges you to track CVEs; Article 14
            requires you to report actively-exploited vulnerabilities to your national CSIRT within 24 hours.
            The Scanner automates the monitoring so you are never caught off-guard.
          </p>
        </div>
        <div className="cra-upsell-hero-cta">
          <a
            href="https://www.resiliencewp.com/pricing"
            target="_blank"
            rel="noopener noreferrer"
            className="cra-btn cra-btn-primary cra-btn-lg"
          >
            Upgrade to unlock Scanner
          </a>
          <p className="cra-muted" style={{ fontSize: '12px', marginTop: 6, textAlign: 'center' }}>
            Basic from $19/month
          </p>
        </div>
      </div>

      <div className="cra-upsell-features">
        <div className="cra-upsell-feature-card">
          <div className="cra-upsell-feature-icon cra-upsell-icon-blue">&#9876;</div>
          <h4>Daily CVE scans via WPScan</h4>
          <p>
            Every 24 hours, your monitored plugins are checked against the WPScan vulnerability database —
            the same source used by security researchers and hosting providers worldwide. You are notified
            the same day a new CVE is published that affects your plugin.
          </p>
        </div>
        <div className="cra-upsell-feature-card">
          <div className="cra-upsell-feature-icon cra-upsell-icon-amber">&#9888;</div>
          <h4>Instant email alerts on new findings</h4>
          <p>
            Critical and high-severity vulnerabilities trigger an immediate email alert so you can start
            your CRA Article 14 response clock. Your 24-hour early warning deadline starts the moment you
            become aware — the Scanner makes sure that moment is as early as possible.
          </p>
        </div>
        <div className="cra-upsell-feature-card">
          <div className="cra-upsell-feature-icon cra-upsell-icon-green">&#10003;</div>
          <h4>Per-vulnerability workflow</h4>
          <p>
            Each finding gets its own status: <strong>Open → Acknowledged → In Progress → Resolved</strong>.
            Acknowledging shows regulators you reviewed it; resolving closes the loop. The full audit
            trail is exportable as evidence for CSIRT submissions.
          </p>
        </div>
        <div className="cra-upsell-feature-card">
          <div className="cra-upsell-feature-icon cra-upsell-icon-red">&#9872;</div>
          <h4>One-click incident escalation</h4>
          <p>
            When a vulnerability is actively exploited, escalate directly to the Incident Center — your
            CRA Article 14 notification drafts are pre-filled with the CVE ID, CVSS score, and impact
            details. You go from "Scanner found it" to "CSIRT notified" in minutes.
          </p>
        </div>
        <div className="cra-upsell-feature-card">
          <div className="cra-upsell-feature-icon cra-upsell-icon-purple">&#128203;</div>
          <h4>Compliance-ready CSV export</h4>
          <p>
            Export your full vulnerability history as a CSV for audits, insurance questionnaires, or
            enterprise customer due-diligence requests. Shows exactly which CVEs you found, when, and
            how you handled them — the paper trail CRA auditors look for.
          </p>
        </div>
        <div className="cra-upsell-feature-card">
          <div className="cra-upsell-feature-icon cra-upsell-icon-blue">&#128269;</div>
          <h4>Monitor any WordPress.org plugin</h4>
          <p>
            Not just your own plugin — monitor every plugin your product depends on or bundles.
            If a dependency has a CVE, you need to know. Add plugins by slug to track the entire
            supply chain that falls under your CRA responsibility.
          </p>
        </div>
      </div>

      <div className="cra-upsell-cra-box">
        <h4>Which CRA articles does this help with?</h4>
        <div className="cra-upsell-articles">
          <div className="cra-upsell-article">
            <span className="cra-upsell-article-tag">Article 13</span>
            <span>Manufacturers must monitor for vulnerabilities during the expected product lifetime and address them without undue delay.</span>
          </div>
          <div className="cra-upsell-article">
            <span className="cra-upsell-article-tag">Article 14</span>
            <span>Actively exploited vulnerabilities must be reported to ENISA/national CSIRTs within 24 hours of awareness.</span>
          </div>
          <div className="cra-upsell-article">
            <span className="cra-upsell-article-tag">Annex I</span>
            <span>Products must be delivered without known exploitable vulnerabilities and document their security properties.</span>
          </div>
        </div>
      </div>

      <div className="cra-upsell-plans">
        <div className="cra-upsell-plan">
          <div className="cra-upsell-plan-name">Basic</div>
          <div className="cra-upsell-plan-price">$19<span>/month</span></div>
          <ul className="cra-upsell-plan-features">
            <li>5 plugins monitored</li>
            <li>Daily vulnerability scans</li>
            <li>Email alerts on new CVEs</li>
            <li>Vulnerability status workflow</li>
            <li>CSV export</li>
            <li>Incident Center access</li>
          </ul>
          <a href="https://www.resiliencewp.com/pricing" target="_blank" rel="noopener noreferrer" className="cra-btn cra-btn-sm" style={{ display: 'block', textAlign: 'center' }}>
            Get Basic
          </a>
        </div>
        <div className="cra-upsell-plan cra-upsell-plan-featured">
          <div className="cra-upsell-plan-badge">Most popular</div>
          <div className="cra-upsell-plan-name">Pro</div>
          <div className="cra-upsell-plan-price">$45<span>/month</span></div>
          <ul className="cra-upsell-plan-features">
            <li>20 plugins monitored</li>
            <li>Daily vulnerability scans</li>
            <li>Email alerts on new CVEs</li>
            <li>Vulnerability status workflow</li>
            <li>CSV export + evidence packs</li>
            <li>Incident Center access</li>
            <li>Dashboard compliance score</li>
            <li>Priority support</li>
          </ul>
          <a href="https://www.resiliencewp.com/pricing" target="_blank" rel="noopener noreferrer" className="cra-btn cra-btn-primary cra-btn-sm" style={{ display: 'block', textAlign: 'center' }}>
            Get Pro
          </a>
        </div>
      </div>
    </div>
  );
}

function timeAgo(dateStr: string): string {
  const diff = Date.now() - new Date(dateStr).getTime();
  const mins = Math.floor(diff / 60000);
  if (mins < 60) return `${mins}m ago`;
  const hrs = Math.floor(mins / 60);
  if (hrs < 24) return `${hrs}h ago`;
  return `${Math.floor(hrs / 24)}d ago`;
}
