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

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

interface MLAnomaly {
  ip: string;
  ja4: string;
  host: string;
  hits: number;
  fuzzing_index: number;
  hit_velocity: number;
  temporal_entropy: number;
  is_fake_navigation: boolean;
  ua_ch_mismatch: boolean;
  sni_host_mismatch: boolean;
  is_ua_rotating: boolean;
  path_diversity_ratio: number;
  anomalous_payload_ratio: number;
  asn_label: string;
  bot_name: string;
  attack_type: string;
}

interface RadarData {
  ip: string;
  fuzzing_score: number;
  velocity_score: number;
  fake_nav_score: number;
  ua_mismatch_score: number;
  sni_mismatch_score: number;
  orphan_score: number;
  path_repetition_score: number;
  payload_anomaly_score: number;
}

interface ScatterPoint {
  ip: string;
  ja4: string;
  fuzzing_index: number;
  hit_velocity: number;
  hits: number;
  attack_type: string;
}

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

function formatNumber(n: number): string {
  return n.toLocaleString(navigator.language || undefined);
}

function attackTypeEmoji(type: string): string {
  switch (type) {
    case 'brute_force': return '🔑';
    case 'flood':       return '🌊';
    case 'scraper':     return '🕷️';
    case 'spoofing':    return '🎭';
    case 'scanner':     return '🔍';
    default:            return '❓';
  }
}

function attackTypeColor(type: string): string {
  switch (type) {
    case 'brute_force': return '#ef4444';
    case 'flood':       return '#3b82f6';
    case 'scraper':     return '#a855f7';
    case 'spoofing':    return '#f97316';
    case 'scanner':     return '#eab308';
    default:            return '#6b7280';
  }
}

function fuzzingBadgeClass(value: number): string {
  if (value >= 200) return 'bg-threat-critical/20 text-threat-critical';
  if (value >= 100) return 'bg-threat-high/20 text-threat-high';
  if (value >= 50)  return 'bg-threat-medium/20 text-threat-medium';
  return 'bg-background-card text-text-secondary';
}

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

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>
  );
}

// ─── Radar Chart (SVG octagonal) ─────────────────────────────────────────────

const RADAR_AXES = [
  { key: 'fuzzing_score',        label: 'Fuzzing',        tip: TIPS.fuzzing       },
  { key: 'velocity_score',       label: 'Vélocité',       tip: TIPS.velocity      },
  { key: 'fake_nav_score',       label: 'Fausse nav',     tip: TIPS.fake_nav      },
  { key: 'ua_mismatch_score',    label: 'UA/CH mismatch', tip: TIPS.ua_mismatch   },
  { key: 'sni_mismatch_score',   label: 'SNI mismatch',   tip: TIPS.sni_mismatch  },
  { key: 'orphan_score',         label: 'Orphan ratio',   tip: TIPS.orphan_ratio  },
  { key: 'path_repetition_score', label: 'Répétition URL', tip: TIPS.path_repetition },
  { key: 'payload_anomaly_score', label: 'Payload anormal', tip: TIPS.payload_anomaly },
] as const;

type RadarKey = typeof RADAR_AXES[number]['key'];

function RadarChart({ data }: { data: RadarData }) {
  const size = 280;
  const cx = size / 2;
  const cy = size / 2;
  const maxR = 100;
  const n = RADAR_AXES.length;

  const angleOf = (i: number) => (i * 2 * Math.PI) / n - Math.PI / 2;

  const pointFor = (i: number, r: number): [number, number] => {
    const a = angleOf(i);
    return [cx + r * Math.cos(a), cy + r * Math.sin(a)];
  };

  // Background rings (at 25%, 50%, 75%, 100%)
  const rings = [25, 50, 75, 100];

  const dataPoints = RADAR_AXES.map((axis, i) => {
    const val = Math.min((data[axis.key as RadarKey] ?? 0), 100);
    return pointFor(i, (val / 100) * maxR);
  });

  const polygonPoints = dataPoints.map(([x, y]) => `${x},${y}`).join(' ');

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className="overflow-visible">
      {/* Background rings */}
      {rings.map((r) => {
        const pts = RADAR_AXES.map((_, i) => {
          const [x, y] = pointFor(i, (r / 100) * maxR);
          return `${x},${y}`;
        }).join(' ');
        return (
          <polygon
            key={r}
            points={pts}
            fill="none"
            stroke="rgba(100,116,139,0.2)"
            strokeWidth="1"
          />
        );
      })}

      {/* Axis lines */}
      {RADAR_AXES.map((_, i) => {
        const [x, y] = pointFor(i, maxR);
        return (
          <line
            key={i}
            x1={cx} y1={cy}
            x2={x} y2={y}
            stroke="rgba(100,116,139,0.35)"
            strokeWidth="1"
          />
        );
      })}

      {/* Data polygon */}
      <polygon
        points={polygonPoints}
        fill="rgba(239,68,68,0.2)"
        stroke="rgba(239,68,68,0.85)"
        strokeWidth="2"
      />

      {/* Data dots */}
      {dataPoints.map(([x, y], i) => (
        <circle key={i} cx={x} cy={y} r="3" fill="rgba(239,68,68,0.9)" />
      ))}

      {/* Axis labels — survolez pour la définition */}
      {RADAR_AXES.map((axis, i) => {
        const [x, y] = pointFor(i, maxR + 18);
        const anchor = x < cx - 5 ? 'end' : x > cx + 5 ? 'start' : 'middle';
        return (
          <text
            key={axis.key}
            x={x}
            y={y}
            textAnchor={anchor}
            fontSize="10"
            fill="rgba(148,163,184,0.9)"
            dominantBaseline="middle"
            style={{ cursor: 'help' }}
          >
            <title>{axis.tip}</title>
            {axis.label}
          </text>
        );
      })}

      {/* Percentage labels on vertical axis */}
      {rings.map((r) => {
        const [, y] = pointFor(0, (r / 100) * maxR);
        return (
          <text key={r} x={cx + 3} y={y} fontSize="8" fill="rgba(100,116,139,0.6)" dominantBaseline="middle">
            {r}
          </text>
        );
      })}
    </svg>
  );
}

// ─── Scatter plot ─────────────────────────────────────────────────────────────

function ScatterPlot({ points }: { points: ScatterPoint[] }) {
  const [tooltip, setTooltip] = useState<{ ip: string; type: string; x: number; y: number } | null>(null);

  const W = 600;
  const H = 200;
  const padL = 40;
  const padB = 30;
  const padT = 10;
  const padR = 20;

  const maxX = 350;
  const maxY = 1;

  const toSvgX = (v: number) => padL + ((v / maxX) * (W - padL - padR));
  const toSvgY = (v: number) => padT + ((1 - v / maxY) * (H - padT - padB));

  // X axis ticks
  const xTicks = [0, 50, 100, 150, 200, 250, 300, 350];
  const yTicks = [0, 0.25, 0.5, 0.75, 1.0];

  return (
    <div className="relative">
      <svg
        width="100%"
        viewBox={`0 0 ${W} ${H}`}
        className="overflow-visible"
        onMouseLeave={() => setTooltip(null)}
      >
        {/* Grid lines */}
        {xTicks.map((v) => (
          <line key={v} x1={toSvgX(v)} y1={padT} x2={toSvgX(v)} y2={H - padB} stroke="rgba(100,116,139,0.15)" strokeWidth="1" />
        ))}
        {yTicks.map((v) => (
          <line key={v} x1={padL} y1={toSvgY(v)} x2={W - padR} y2={toSvgY(v)} stroke="rgba(100,116,139,0.15)" strokeWidth="1" />
        ))}

        {/* X axis */}
        <line x1={padL} y1={H - padB} x2={W - padR} y2={H - padB} stroke="rgba(100,116,139,0.4)" strokeWidth="1" />
        {xTicks.map((v) => (
          <text key={v} x={toSvgX(v)} y={H - padB + 12} textAnchor="middle" fontSize="9" fill="rgba(148,163,184,0.7)">{v}</text>
        ))}
        <text x={(W - padL - padR) / 2 + padL} y={H - 2} textAnchor="middle" fontSize="10" fill="rgba(148,163,184,0.8)" style={{ cursor: 'help' }}>
          <title>{TIPS.fuzzing_index}</title>
          Fuzzing Index →
        </text>

        {/* Y axis */}
        <line x1={padL} y1={padT} x2={padL} y2={H - padB} stroke="rgba(100,116,139,0.4)" strokeWidth="1" />
        {yTicks.map((v) => (
          <text key={v} x={padL - 4} y={toSvgY(v)} textAnchor="end" fontSize="9" fill="rgba(148,163,184,0.7)" dominantBaseline="middle">{v.toFixed(2)}</text>
        ))}

        {/* Data points */}
        {points.map((pt, i) => {
          const x = toSvgX(Math.min(pt.fuzzing_index, maxX));
          const y = toSvgY(Math.min(pt.hit_velocity, maxY));
          const color = attackTypeColor(pt.attack_type);
          return (
            <circle
              key={i}
              cx={x}
              cy={y}
              r={3}
              fill={color}
              fillOpacity={0.75}
              stroke={color}
              strokeWidth="0.5"
              style={{ cursor: 'pointer' }}
              onMouseEnter={() => setTooltip({ ip: pt.ip, type: pt.attack_type, x, y })}
            />
          );
        })}

        {/* Tooltip */}
        {tooltip && (
          <g>
            <rect
              x={Math.min(tooltip.x + 6, W - 120)}
              y={Math.max(tooltip.y - 28, padT)}
              width={110}
              height={28}
              rx={3}
              fill="rgba(15,23,42,0.95)"
              stroke="rgba(100,116,139,0.4)"
              strokeWidth="1"
            />
            <text
              x={Math.min(tooltip.x + 11, W - 115)}
              y={Math.max(tooltip.y - 18, padT + 8)}
              fontSize="9"
              fill="white"
            >
              {tooltip.ip}
            </text>
            <text
              x={Math.min(tooltip.x + 11, W - 115)}
              y={Math.max(tooltip.y - 7, padT + 19)}
              fontSize="9"
              fill="rgba(148,163,184,0.9)"
            >
              {attackTypeEmoji(tooltip.type)} {tooltip.type}
            </text>
          </g>
        )}
      </svg>
    </div>
  );
}

// ─── Anomalies DataTable ─────────────────────────────────────────────────────

function AnomaliesTable({
  anomalies,
  selectedIP,
  onRowClick,
}: {
  anomalies: MLAnomaly[];
  selectedIP: string | null;
  onRowClick: (row: MLAnomaly) => void;
}) {
  const columns = useMemo((): Column<MLAnomaly>[] => [
    {
      key: 'ip',
      label: 'IP',
      render: (v: string, row: MLAnomaly) => (
        <span className={`font-mono text-xs ${selectedIP === row.ip ? 'text-accent-primary' : 'text-text-primary'}`}>
          {v}
        </span>
      ),
    },
    {
      key: 'host',
      label: 'Host',
      render: (v: string) => (
        <span className="text-text-secondary max-w-[120px] truncate block" title={v}>
          {v || '—'}
        </span>
      ),
    },
    {
      key: 'hits',
      label: 'Hits',
      align: 'right',
      render: (v: number) => formatNumber(v),
    },
    {
      key: 'fuzzing_index',
      label: 'Fuzzing',
      tooltip: TIPS.fuzzing_index,
      align: 'right',
      render: (v: number) => (
        <span className={`px-1.5 py-0.5 rounded text-xs font-semibold ${fuzzingBadgeClass(v)}`}>
          {Math.round(v)}
        </span>
      ),
    },
    {
      key: 'attack_type',
      label: 'Type',
      tooltip: 'Type d\'attaque détecté : Brute Force 🔑, Flood 🌊, Scraper 🕷️, Spoofing 🎭, Scanner 🔍',
      render: (v: string) => (
        <span title={v} className="text-sm">{attackTypeEmoji(v)}</span>
      ),
    },
    {
      key: '_signals',
      label: 'Signaux',
      tooltip: '⚠️ UA/CH mismatch · 🎭 Fausse navigation · 🔄 UA rotatif · 🌐 SNI mismatch',
      sortable: false,
      render: (_: unknown, row: MLAnomaly) => (
        <span className="flex gap-0.5">
          {row.ua_ch_mismatch && <span title="UA/CH mismatch">⚠️</span>}
          {row.is_fake_navigation && <span title="Fausse navigation">🎭</span>}
          {row.is_ua_rotating && <span title="UA rotatif">🔄</span>}
          {row.sni_host_mismatch && <span title="SNI mismatch">🌐</span>}
        </span>
      ),
    },
  ], [selectedIP]);

  return (
    <div className="overflow-auto max-h-[500px]">
      <DataTable
        data={anomalies}
        columns={columns}
        rowKey="ip"
        defaultSortKey="fuzzing_index"
        onRowClick={onRowClick}
        emptyMessage="Aucune anomalie détectée"
        compact
      />
    </div>
  );
}

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

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

  const [anomalies, setAnomalies] = useState<MLAnomaly[]>([]);
  const [anomaliesLoading, setAnomaliesLoading] = useState(true);
  const [anomaliesError, setAnomaliesError] = useState<string | null>(null);

  const [scatter, setScatter] = useState<ScatterPoint[]>([]);
  const [scatterLoading, setScatterLoading] = useState(true);
  const [scatterError, setScatterError] = useState<string | null>(null);

  const [selectedIP, setSelectedIP] = useState<string | null>(null);
  const [radarData, setRadarData] = useState<RadarData | null>(null);
  const [radarLoading, setRadarLoading] = useState(false);
  const [radarError, setRadarError] = useState<string | null>(null);

  useEffect(() => {
    const fetchAnomalies = async () => {
      try {
        const res = await fetch('/api/ml/top-anomalies?limit=50');
        if (!res.ok) throw new Error('Erreur chargement des anomalies');
        const data: { items: MLAnomaly[] } = await res.json();
        setAnomalies(data.items ?? []);
      } catch (err) {
        setAnomaliesError(err instanceof Error ? err.message : 'Erreur inconnue');
      } finally {
        setAnomaliesLoading(false);
      }
    };
    const fetchScatter = async () => {
      try {
        const res = await fetch('/api/ml/scatter?limit=200');
        if (!res.ok) throw new Error('Erreur chargement du scatter');
        const data: { points: ScatterPoint[] } = await res.json();
        setScatter(data.points ?? []);
      } catch (err) {
        setScatterError(err instanceof Error ? err.message : 'Erreur inconnue');
      } finally {
        setScatterLoading(false);
      }
    };
    fetchAnomalies();
    fetchScatter();
  }, []);

  const loadRadar = async (ip: string) => {
    if (selectedIP === ip) {
      setSelectedIP(null);
      setRadarData(null);
      return;
    }
    setSelectedIP(ip);
    setRadarLoading(true);
    setRadarError(null);
    try {
      const res = await fetch(`/api/ml/ip/${encodeURIComponent(ip)}/radar`);
      if (!res.ok) throw new Error('Erreur chargement du radar');
      const data: RadarData = await res.json();
      setRadarData(data);
    } catch (err) {
      setRadarError(err instanceof Error ? err.message : 'Erreur inconnue');
    } finally {
      setRadarLoading(false);
    }
  };

  return (
    <div className="p-6 space-y-6 animate-fade-in">
      {/* Header */}
      <div>
        <h1 className="text-2xl font-bold text-text-primary">🤖 Analyse Features ML</h1>
        <p className="text-text-secondary mt-1">
          Visualisation des features ML pour la détection d'anomalies comportementales.
        </p>
      </div>

      {/* Main two-column layout */}
      <div className="flex gap-6 flex-col lg:flex-row">
        {/* Left: anomalies table */}
        <div className="flex-1 min-w-0">
          <div className="bg-background-secondary rounded-lg border border-border overflow-hidden">
            <div className="px-4 py-3 border-b border-border">
              <h2 className="text-text-primary font-semibold text-sm">Top anomalies</h2>
            </div>
            {anomaliesLoading ? (
              <LoadingSpinner />
            ) : anomaliesError ? (
              <div className="p-4"><ErrorMessage message={anomaliesError} /></div>
            ) : (
              <AnomaliesTable
                anomalies={anomalies}
                selectedIP={selectedIP}
                onRowClick={(row) => loadRadar(row.ip)}
              />
            )}
          </div>
        </div>

        {/* Right: Radar chart */}
        <div className="lg:w-80 xl:w-96">
          <div className="bg-background-secondary rounded-lg border border-border p-4 h-full flex flex-col">
            <h2 className="text-text-primary font-semibold text-sm mb-3">
              Radar ML {selectedIP ? <span className="text-accent-primary font-mono text-xs">— {selectedIP}</span> : ''}
            </h2>
            {!selectedIP ? (
              <div className="flex-1 flex items-center justify-center text-text-disabled text-sm text-center">
                Cliquez sur une IP<br />pour afficher le radar
              </div>
            ) : radarLoading ? (
              <div className="flex-1 flex items-center justify-center">
                <LoadingSpinner />
              </div>
            ) : radarError ? (
              <ErrorMessage message={radarError} />
            ) : radarData ? (
              <>
                <div className="flex justify-center">
                  <RadarChart data={radarData} />
                </div>
                <button
                  onClick={() => navigate(`/investigation/${selectedIP}`)}
                  className="mt-3 w-full text-xs bg-accent-primary/10 text-accent-primary px-3 py-2 rounded hover:bg-accent-primary/20 transition-colors"
                >
                  🔍 Investiguer {selectedIP}
                </button>
              </>
            ) : null}
          </div>
        </div>
      </div>

      {/* Scatter plot */}
      <div className="bg-background-secondary rounded-lg border border-border p-6">
        <h2 className="text-text-primary font-semibold mb-4">Nuage de points — Fuzzing Index × Vélocité</h2>
        {scatterLoading ? (
          <LoadingSpinner />
        ) : scatterError ? (
          <ErrorMessage message={scatterError} />
        ) : (
          <>
            <ScatterPlot points={scatter} />
            {/* Legend */}
            <div className="flex flex-wrap gap-4 mt-3 text-xs text-text-secondary">
              {['brute_force', 'flood', 'scraper', 'spoofing', 'scanner'].map((type) => (
                <span key={type} className="flex items-center gap-1.5">
                  <span
                    style={{ backgroundColor: attackTypeColor(type), display: 'inline-block', width: '10px', height: '10px', borderRadius: '50%' }}
                  />
                  {attackTypeEmoji(type)} {type}
                </span>
              ))}
            </div>
          </>
        )}
      </div>
    </div>
  );
}
