import { useState, useEffect, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import DataTable, { Column } from './ui/DataTable';

// ─── Types ────────────────────────────────────────────────────────────────────

interface TcpSpoofingOverview {
  total_entries: number;
  unique_ips: number;
  no_tcp_data: number;
  with_tcp_data: number;
  linux_fingerprint: number;
  windows_fingerprint: number;
  ttl_distribution: { ttl: number; count: number; ips: number }[];
  window_size_distribution: { window_size: number; count: number }[];
}

interface TcpSpoofingItem {
  ip: string;
  ja4: string;
  tcp_ttl: number;
  tcp_window_size: number;
  first_ua: string;
  suspected_os: string;
  declared_os: string;
  spoof_flag: boolean;
}

interface OsMatrixEntry {
  suspected_os: string;
  declared_os: string;
  count: number;
  is_spoof: boolean;
}

type ActiveTab = 'detections' | 'matrix';

// ─── Helpers ──────────────────────────────────────────────────────────────────

function formatNumber(n: number): string {
  return n.toLocaleString('fr-FR');
}

function ttlColor(ttl: number): string {
  if (ttl === 0) return 'text-threat-critical';
  if (ttl < 48 || ttl > 200) return 'text-threat-critical';
  if (ttl < 60 || (ttl > 70 && ttl <= 80)) return 'text-threat-medium';
  if (ttl >= 60 && ttl <= 70) return 'text-threat-low';
  return 'text-text-secondary';
}

// ─── Sub-components ───────────────────────────────────────────────────────────

function StatCard({ label, value, accent }: { label: string; value: string | number; accent?: string }) {
  return (
    <div className="bg-background-secondary rounded-lg p-4 flex flex-col gap-1 border border-border">
      <span className="text-text-secondary text-sm">{label}</span>
      <span className={`text-2xl font-bold ${accent ?? 'text-text-primary'}`}>{value}</span>
    </div>
  );
}

function LoadingSpinner() {
  return (
    <div className="flex items-center justify-center py-12">
      <div className="w-8 h-8 border-2 border-accent-primary border-t-transparent rounded-full animate-spin" />
    </div>
  );
}

function ErrorMessage({ message }: { message: string }) {
  return (
    <div className="bg-threat-critical/10 border border-threat-critical/30 rounded-lg p-4 text-threat-critical">
      ⚠️ {message}
    </div>
  );
}

// ─── Detections DataTable ─────────────────────────────────────────────────────

function TcpDetectionsTable({
  items,
  navigate,
}: {
  items: TcpSpoofingItem[];
  navigate: (path: string) => void;
}) {
  const columns = useMemo((): Column<TcpSpoofingItem>[] => [
    {
      key: 'ip',
      label: 'IP',
      render: (v: string) => <span className="font-mono text-xs text-text-primary">{v}</span>,
    },
    {
      key: 'ja4',
      label: 'JA4',
      render: (v: string) => (
        <span className="font-mono text-xs text-text-secondary">
          {v ? `${v.slice(0, 14)}…` : '—'}
        </span>
      ),
    },
    {
      key: 'tcp_ttl',
      label: 'TTL observé',
      align: 'right',
      render: (v: number) => (
        <span className={`font-mono font-semibold ${ttlColor(v)}`}>{v}</span>
      ),
    },
    {
      key: 'tcp_window_size',
      label: 'Fenêtre TCP',
      align: 'right',
      render: (v: number) => (
        <span className="text-text-secondary text-xs">{formatNumber(v)}</span>
      ),
    },
    {
      key: 'suspected_os',
      label: 'OS suspecté',
      render: (v: string) => <span className="text-text-primary text-xs">{v || '—'}</span>,
    },
    {
      key: 'declared_os',
      label: 'OS déclaré',
      render: (v: string) => <span className="text-text-secondary text-xs">{v || '—'}</span>,
    },
    {
      key: 'spoof_flag',
      label: 'Spoof',
      sortable: false,
      render: (v: boolean) =>
        v ? (
          <span className="bg-threat-critical/20 text-threat-critical text-xs px-2 py-0.5 rounded-full">
            🚨 Spoof
          </span>
        ) : null,
    },
    {
      key: '_actions',
      label: '',
      sortable: false,
      render: (_: unknown, row: TcpSpoofingItem) => (
        <button
          onClick={(e) => { e.stopPropagation(); navigate(`/investigation/${row.ip}`); }}
          className="text-xs bg-accent-primary/10 text-accent-primary px-3 py-1 rounded hover:bg-accent-primary/20 transition-colors"
        >
          Investiguer
        </button>
      ),
    },
  ], [navigate]);

  return (
    <DataTable
      data={items}
      columns={columns}
      rowKey="ip"
      defaultSortKey="tcp_ttl"
      emptyMessage="Aucune détection"
      compact
    />
  );
}

// ─── Main Component ───────────────────────────────────────────────────────────

export function TcpSpoofingView() {
  const navigate = useNavigate();

  const [activeTab, setActiveTab] = useState<ActiveTab>('detections');

  const [spoofOnly, setSpoofOnly] = useState(false);

  const [overview, setOverview] = useState<TcpSpoofingOverview | null>(null);
  const [overviewLoading, setOverviewLoading] = useState(true);
  const [overviewError, setOverviewError] = useState<string | null>(null);

  const [items, setItems] = useState<TcpSpoofingItem[]>([]);
  const [itemsLoading, setItemsLoading] = useState(true);
  const [itemsError, setItemsError] = useState<string | null>(null);

  const [matrix, setMatrix] = useState<OsMatrixEntry[]>([]);
  const [matrixLoading, setMatrixLoading] = useState(false);
  const [matrixError, setMatrixError] = useState<string | null>(null);
  const [matrixLoaded, setMatrixLoaded] = useState(false);

  const [filterText, setFilterText] = useState('');

  useEffect(() => {
    const fetchOverview = async () => {
      setOverviewLoading(true);
      try {
        const res = await fetch('/api/tcp-spoofing/overview');
        if (!res.ok) throw new Error('Erreur chargement overview');
        const data: TcpSpoofingOverview = await res.json();
        setOverview(data);
      } catch (err) {
        setOverviewError(err instanceof Error ? err.message : 'Erreur inconnue');
      } finally {
        setOverviewLoading(false);
      }
    };
    fetchOverview();
  }, []);

  useEffect(() => {
    const fetchItems = async () => {
      setItemsLoading(true);
      setItemsError(null);
      try {
        const params = new URLSearchParams({ limit: '200' });
        if (spoofOnly) params.set('spoof_only', 'true');
        const res = await fetch(`/api/tcp-spoofing/list?${params}`);
        if (!res.ok) throw new Error('Erreur chargement des détections');
        const data: { items: TcpSpoofingItem[]; total: number } = await res.json();
        setItems(data.items ?? []);
      } catch (err) {
        setItemsError(err instanceof Error ? err.message : 'Erreur inconnue');
      } finally {
        setItemsLoading(false);
      }
    };
    fetchItems();
  }, [spoofOnly]);

  const loadMatrix = async () => {
    if (matrixLoaded) return;
    setMatrixLoading(true);
    try {
      const res = await fetch('/api/tcp-spoofing/matrix');
      if (!res.ok) throw new Error('Erreur chargement matrice OS');
      const data: { matrix: OsMatrixEntry[] } = await res.json();
      setMatrix(data.matrix ?? []);
      setMatrixLoaded(true);
    } catch (err) {
      setMatrixError(err instanceof Error ? err.message : 'Erreur inconnue');
    } finally {
      setMatrixLoading(false);
    }
  };

  const handleTabChange = (tab: ActiveTab) => {
    setActiveTab(tab);
    if (tab === 'matrix') loadMatrix();
  };

  const filteredItems = items.filter(
    (item) =>
      (!spoofOnly || item.spoof_flag) &&
      (!filterText ||
        item.ip.includes(filterText) ||
        item.suspected_os.toLowerCase().includes(filterText.toLowerCase()) ||
        item.declared_os.toLowerCase().includes(filterText.toLowerCase()))
  );

  // Build matrix axes
  const suspectedOSes = [...new Set(matrix.map((e) => e.suspected_os))].sort();
  const declaredOSes = [...new Set(matrix.map((e) => e.declared_os))].sort();
  const matrixMax = matrix.reduce((m, e) => Math.max(m, e.count), 1);

  function matrixCellColor(count: number): string {
    if (count === 0) return 'bg-background-card';
    const ratio = count / matrixMax;
    if (ratio >= 0.75) return 'bg-threat-critical/80';
    if (ratio >= 0.5) return 'bg-threat-high/70';
    if (ratio >= 0.25) return 'bg-threat-medium/60';
    return 'bg-threat-low/40';
  }

  const tabs: { id: ActiveTab; label: string }[] = [
    { id: 'detections', label: '📋 Détections' },
    { id: 'matrix', label: '📊 Matrice OS' },
  ];

  return (
    <div className="p-6 space-y-6 animate-fade-in">
      {/* Header */}
      <div>
        <h1 className="text-2xl font-bold text-text-primary">🧬 Spoofing TCP/OS</h1>
        <p className="text-text-secondary mt-1">
          Détection des incohérences entre TTL/fenêtre TCP et l'OS déclaré.
        </p>
      </div>

      {/* Stat cards */}
      {overviewLoading ? (
        <LoadingSpinner />
      ) : overviewError ? (
        <ErrorMessage message={overviewError} />
      ) : overview ? (
        <>
          <div className="grid grid-cols-4 gap-4">
            <StatCard label="Total entrées" value={formatNumber(overview.total_entries)} accent="text-text-primary" />
            <StatCard label="Avec données TCP" value={formatNumber(overview.with_tcp_data)} accent="text-threat-medium" />
            <StatCard label="Fingerprint Linux" value={formatNumber(overview.linux_fingerprint)} accent="text-threat-low" />
            <StatCard label="Fingerprint Windows" value={formatNumber(overview.windows_fingerprint)} accent="text-accent-primary" />
          </div>
          <div className="bg-background-card border border-border rounded-lg px-4 py-3 text-sm text-text-secondary flex items-center gap-2">
            <span className="text-threat-medium">⚠️</span>
            <span>
              <strong className="text-text-primary">{formatNumber(overview.no_tcp_data)}</strong> entrées sans données TCP (TTL=0, passées par proxy/CDN) — exclues de l'analyse de corrélation.
            </span>
          </div>
        </>
      ) : null}

      {/* Tabs */}
      <div className="flex gap-2 border-b border-border">
        {tabs.map((tab) => (
          <button
            key={tab.id}
            onClick={() => handleTabChange(tab.id)}
            className={`px-4 py-2 text-sm font-medium transition-colors ${
              activeTab === tab.id
                ? 'text-accent-primary border-b-2 border-accent-primary'
                : 'text-text-secondary hover:text-text-primary'
            }`}
          >
            {tab.label}
          </button>
        ))}
      </div>

      {/* Détections tab */}
      {activeTab === 'detections' && (
        <>
          <div className="flex gap-3 items-center">
            <input
              type="text"
              placeholder="Filtrer par IP ou OS..."
              value={filterText}
              onChange={(e) => setFilterText(e.target.value)}
              className="bg-background-card border border-border rounded-lg px-3 py-2 text-sm text-text-primary placeholder-text-disabled focus:outline-none focus:border-accent-primary w-72"
            />
            <label className="flex items-center gap-2 text-sm text-text-secondary cursor-pointer select-none">
              <input
                type="checkbox"
                checked={spoofOnly}
                onChange={(e) => setSpoofOnly(e.target.checked)}
                className="accent-accent-primary"
              />
              Spoofs uniquement (TTL corrélé + OS mismatch)
            </label>
          </div>
          <div className="bg-background-secondary rounded-lg border border-border overflow-hidden">
            {itemsLoading ? (
              <LoadingSpinner />
            ) : itemsError ? (
              <div className="p-4"><ErrorMessage message={itemsError} /></div>
            ) : (
              <TcpDetectionsTable items={filteredItems} navigate={navigate} />
            )}
          </div>
        </>
      )}

      {/* Matrice OS tab */}
      {activeTab === 'matrix' && (
        <div className="bg-background-secondary rounded-lg border border-border p-6">
          {matrixLoading ? (
            <LoadingSpinner />
          ) : matrixError ? (
            <ErrorMessage message={matrixError} />
          ) : matrix.length === 0 ? (
            <p className="text-text-secondary text-sm">Aucune donnée disponible.</p>
          ) : (
            <div className="overflow-auto">
              <h2 className="text-text-primary font-semibold mb-4">OS Suspecté × OS Déclaré</h2>
              <table className="text-xs border-collapse">
                <thead>
                  <tr>
                    <th className="px-3 py-2 text-text-secondary text-left border border-border bg-background-card">
                      Suspecté \ Déclaré
                    </th>
                    {declaredOSes.map((os) => (
                      <th key={os} className="px-3 py-2 text-text-secondary text-center border border-border bg-background-card max-w-[80px]">
                        <span className="block truncate w-20" title={os}>{os}</span>
                      </th>
                    ))}
                    <th className="px-3 py-2 text-text-secondary text-center border border-border bg-background-card">Total</th>
                  </tr>
                </thead>
                <tbody>
                  {suspectedOSes.map((sos) => {
                    const rowEntries = declaredOSes.map((dos) => {
                      const entry = matrix.find((e) => e.suspected_os === sos && e.declared_os === dos);
                      return entry?.count ?? 0;
                    });
                    const rowTotal = rowEntries.reduce((s, v) => s + v, 0);
                    return (
                      <tr key={sos}>
                        <td className="px-3 py-2 text-text-primary border border-border bg-background-card font-medium max-w-[120px]">
                          <span className="block truncate w-28" title={sos}>{sos}</span>
                        </td>
                        {rowEntries.map((count, ci) => {
                          const dos = declaredOSes[ci];
                          const entry = matrix.find((e) => e.suspected_os === sos && e.declared_os === dos);
                          const isSpoofCell = entry?.is_spoof ?? false;
                          return (
                            <td
                              key={ci}
                              className={`px-3 py-2 text-center border border-border font-mono ${
                                isSpoofCell && count > 0
                                  ? 'bg-threat-critical/25 text-threat-critical font-bold'
                                  : matrixCellColor(count) + (count > 0 ? ' text-text-primary' : ' text-text-disabled')
                              }`}
                              title={isSpoofCell ? '🚨 OS mismatch confirmé' : undefined}
                            >
                              {count > 0 ? (isSpoofCell ? `🚨 ${formatNumber(count)}` : formatNumber(count)) : '—'}
                            </td>
                          );
                        })}
                        <td className="px-3 py-2 text-center border border-border font-semibold text-text-primary bg-background-card">
                          {formatNumber(rowTotal)}
                        </td>
                      </tr>
                    );
                  })}
                  <tr>
                    <td className="px-3 py-2 text-text-secondary border border-border bg-background-card font-semibold">Total</td>
                    {declaredOSes.map((dos) => {
                      const colTotal = matrix
                        .filter((e) => e.declared_os === dos)
                        .reduce((s, e) => s + e.count, 0);
                      return (
                        <td key={dos} className="px-3 py-2 text-center border border-border font-semibold text-text-primary bg-background-card">
                          {formatNumber(colTotal)}
                        </td>
                      );
                    })}
                    <td className="px-3 py-2 text-center border border-border font-semibold text-accent-primary bg-background-card">
                      {formatNumber(matrix.reduce((s, e) => s + e.count, 0))}
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
          )}
        </div>
      )}
    </div>
  );
}
