import { useCallback, useEffect, useRef, useState } from 'react';
import { api } from '../api/client';
import { useModalAmbientDuck } from '../context/AmbientMusicContext';
import { useWebSocket } from '../hooks/useWebSocket';
import type { Agent, PathTraceHop } from '../types';
import { HelpTip } from '../components/HelpTip';
import './PathTracerPage.css';

// ── types ─────────────────────────────────────────────────────────────────────

interface TraceStatus {
  session_id: string;
  ready: boolean;
  error?: string;
  hops: PathTraceHop[];
}

interface QRData {
  config: string;
  qr_png_b64: string;
}

// ── helpers ───────────────────────────────────────────────────────────────────

function HopStatusBadge({ status }: { status: PathTraceHop['status'] }) {
  return <span className={`pt-hop-status ${status}`}>{status}</span>;
}

// ── QR Modal ──────────────────────────────────────────────────────────────────

function QRModal({
  qr,
  onClose,
  onEnd,
}: {
  qr: QRData;
  onClose: () => void;
  onEnd: () => void;
}) {
  useModalAmbientDuck(true);
  const [copied, setCopied] = useState(false);

  const handleCopy = () => {
    navigator.clipboard.writeText(qr.config).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    });
  };

  const handleDownload = () => {
    const blob = new Blob([qr.config], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'pathtrace.conf';
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div className="pt-modal-backdrop" onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div className="pt-modal">
        <div className="pt-modal-title">⬡ PATH TRACE ACTIVE</div>

        <div className="pt-qr-wrap">
          <img
            className="pt-qr-img"
            src={`data:image/png;base64,${qr.qr_png_b64}`}
            alt="WireGuard QR"
          />
        </div>

        <p className="pt-hint">
          Scan with the <strong>WireGuard</strong> app on your phone,<br />
          or download the .conf file and import it.
        </p>

        <pre className="pt-config-box">{qr.config}</pre>

        <div className="pt-modal-actions">
          <button className="pt-btn pt-btn-primary" onClick={handleCopy}>
            {copied ? '✓ Copied' : 'Copy Config'}
          </button>
          <button className="pt-btn pt-btn-ghost" onClick={handleDownload}>
            Download .conf
          </button>
          <button
            className="pt-btn pt-btn-danger"
            onClick={() => { onEnd(); onClose(); }}
            style={{ marginLeft: 'auto' }}
          >
            End Session
          </button>
        </div>
      </div>
    </div>
  );
}

// ── main component ────────────────────────────────────────────────────────────

export default function PathTracerPage() {
  const { agents: wsAgents } = useWebSocket();
  const [restAgents, setRestAgents] = useState<Agent[]>([]);
  const [selected, setSelected] = useState<string[]>([]); // ordered chain
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const [sessionID, setSessionID] = useState('');
  const [hops, setHops] = useState<PathTraceHop[]>([]);
  const [tracing, setTracing] = useState(false);
  const [qr, setQR] = useState<QRData | null>(null);
  const [showQR, setShowQR] = useState(false);

  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);

  // Use WebSocket agents; fall back to REST on mount if WebSocket hasn't populated yet.
  const agents = wsAgents.length > 0 ? wsAgents : restAgents;

  useEffect(() => {
    api.listAgents().then(setRestAgents).catch(() => {});
  }, []);

  // Stop polling on unmount.
  useEffect(() => () => { if (pollRef.current) clearInterval(pollRef.current); }, []);

  const toggleAgent = (id: string, offline: boolean) => {
    if (offline) return;
    if (tracing) return; // don't let selection change while tracing
    setSelected((prev) => {
      if (prev.includes(id)) return prev.filter((x) => x !== id);
      if (prev.length >= 3) return prev; // max 3 hops
      return [...prev, id];
    });
  };

  const handleTrace = useCallback(async () => {
    if (selected.length === 0) return;
    setError('');
    setLoading(true);
    setTracing(true);
    setHops([]);
    setQR(null);
    try {
      const res = await api.startTrace(selected);
      setSessionID(res.session_id);
      setHops(res.hops);
      startPolling(res.session_id);
    } catch (e: unknown) {
      setError(e instanceof Error ? e.message : 'Trace failed');
      setTracing(false);
    } finally {
      setLoading(false);
    }
  }, [selected]);

  const startPolling = (sid: string) => {
    if (pollRef.current) clearInterval(pollRef.current);
    pollRef.current = setInterval(async () => {
      try {
        const status: TraceStatus = await api.getTraceStatus(sid);
        setHops(status.hops);
        if (status.error) {
          setError(status.error);
          clearInterval(pollRef.current!);
          pollRef.current = null;
          setTracing(false);
          return;
        }
        if (status.ready) {
          try {
            const qrData = await api.getTraceQR(sid);
            clearInterval(pollRef.current!);
            pollRef.current = null;
            setQR(qrData);
            setShowQR(true);
          } catch (e: unknown) {
            setError(e instanceof Error ? e.message : 'Failed to load QR config');
          }
          return;
        }
      } catch {
        // Ignore transient status poll errors
      }
    }, 2000);
  };

  const handleEndSession = useCallback(async () => {
    if (!sessionID) return;
    try {
      await api.deleteTrace(sessionID);
    } catch {
      // best-effort
    }
    if (pollRef.current) { clearInterval(pollRef.current); pollRef.current = null; }
    setSessionID('');
    setHops([]);
    setTracing(false);
    setQR(null);
    setSelected([]);
    setError('');
  }, [sessionID]);

  const isWindows = (a: Agent) =>
    !!(a.platform?.toLowerCase().includes('win') || a.platform?.toLowerCase().includes('windows'));

  const onlineAgents = agents.filter((a) => a.status === 'online');
  const offlineAgents = agents.filter((a) => a.status !== 'online');

  const allHopsReady = hops.length > 0 && hops.every((h) => h.status === 'ready');

  return (
    <div className="pathtrace-page operator-deck-page">
      {/* Header */}
      <div className="pt-header">
        <div>
          <div className="pt-title">⬡ Path Tracer <HelpTip field="pt_path_tracer" /></div>
          <div className="pt-subtitle">
            Build an on-demand multi-hop WireGuard VPN — select up to 3 agents, click TRACE.
          </div>
        </div>
      </div>

      {error && <div className="pt-error-banner">⚠ {error}</div>}

      {tracing && !allHopsReady && !error && (
        <div className="pt-info-banner">
          <span className="pt-spinner" />
          Orchestrating tunnel — waiting for agents to configure WireGuard&hellip;
        </div>
      )}

      <div className="pt-body">
        {/* Left: agent selection */}
        <div>
          <div className="pt-section-label">
            Online agents &mdash; click to add to chain (max 3) <HelpTip field="pt_agent_chain" />
          </div>
          <div className="pt-section-panel">
            {onlineAgents.length === 0 && (
              <div className="pt-chain-empty">No online agents found.</div>
            )}
            <div className="pt-agent-grid">
              {onlineAgents.map((a) => {
                const idx = selected.indexOf(a.id);
                const isSelected = idx >= 0;
                const winOnly = isWindows(a);
                return (
                  <div
                    key={a.id}
                    className={`pt-agent-card${isSelected ? ' selected' : ''}`}
                    onClick={() => winOnly ? toggleAgent(a.id, false) : undefined}
                    title={!winOnly ? 'WireGuard Path Tracer requires a Windows agent' : undefined}
                    style={!winOnly ? { opacity: 0.5, cursor: 'not-allowed' } : undefined}
                  >
                    {isSelected && (
                      <span className="pt-agent-card-order">{idx + 1}</span>
                    )}
                    <div className="pt-agent-name">
                      <span className="pt-agent-status-dot online" />
                      {a.name}
                    </div>
                    <div className="pt-agent-ip">{a.ip || '—'}</div>
                    {!winOnly && (
                      <div style={{ fontSize: '0.6rem', color: '#ff8800', fontFamily: 'monospace', marginTop: '0.15rem' }}>
                        non-Windows
                      </div>
                    )}
                  </div>
                );
              })}
              {offlineAgents.map((a) => (
                <div key={a.id} className="pt-agent-card offline">
                  <div className="pt-agent-name">
                    <span className="pt-agent-status-dot offline" />
                    {a.name}
                  </div>
                  <div className="pt-agent-ip">offline</div>
                </div>
              ))}
            </div>
          </div>
        </div>

        {/* Right: chain + controls */}
        <div className="pt-sidebar">
          {/* Chain visualizer */}
          <div className="pt-chain-panel">
            <div className="pt-chain-title">VPN Chain</div>
            {selected.length === 0 ? (
              <div className="pt-chain-empty">No hops selected yet.</div>
            ) : (
              <div className="pt-chain-row">
                {/* Phone icon */}
                <div className="pt-chain-hop" style={{ marginBottom: '0.15rem' }}>
                  <span style={{ fontSize: '0.7rem', color: '#888', fontFamily: 'monospace' }}>
                    📱 Your Phone
                  </span>
                </div>

                {selected.map((id, i) => {
                  const agent = agents.find((a) => a.id === id);
                  const hop = hops.find((h) => h.agent_id === id);
                  return (
                    <div key={id}>
                      <div className="pt-chain-arrow">▼</div>
                      <div className="pt-chain-hop">
                        <div className="pt-chain-hop-badge">{i + 1}</div>
                        <span className="pt-chain-hop-name">
                          {agent?.name ?? id.slice(0, 8)}
                        </span>
                        {hop && <HopStatusBadge status={hop.status} />}
                      </div>
                      {hop?.external_ip && (
                        <div style={{ fontSize: '0.6rem', color: '#00ffaa66', paddingLeft: '30px', fontFamily: 'monospace' }}>
                          {hop.external_ip}:{hop.port}
                        </div>
                      )}
                      {hop?.error && (
                        <div style={{ fontSize: '0.6rem', color: '#ff5050', paddingLeft: '30px', fontFamily: 'monospace' }}>
                          {hop.error}
                        </div>
                      )}
                    </div>
                  );
                })}

                <div className="pt-chain-arrow">▼</div>
                <div className="pt-chain-hop">
                  <span style={{ fontSize: '0.7rem', color: '#888', fontFamily: 'monospace' }}>
                    🌐 Internet
                  </span>
                </div>
              </div>
            )}
          </div>

          {/* Controls */}
          <div className="pt-actions">
            {!tracing && (
              <button
                className="pt-btn pt-btn-primary"
                disabled={selected.length === 0 || loading}
                onClick={handleTrace}
              >
                {loading ? <><span className="pt-spinner" />Building…</> : '⬡ TRACE'}
              </button>
            )}

            {tracing && allHopsReady && qr && (
              <button className="pt-btn pt-btn-primary" onClick={() => setShowQR(true)}>
                Show QR Code
              </button>
            )}

            {tracing && (
              <button className="pt-btn pt-btn-danger" onClick={handleEndSession}>
                End Session
              </button>
            )}

            {!tracing && selected.length > 0 && (
              <button className="pt-btn pt-btn-ghost" onClick={() => setSelected([])}>
                Clear
              </button>
            )}
          </div>

          {/* Max hop hint */}
          {selected.length >= 3 && !tracing && (
            <div className="pt-hint">Max 3 hops reached.</div>
          )}

          {allHopsReady && (
            <div className="pt-info-banner">
              ✓ All hops ready — tunnel is active.
            </div>
          )}
        </div>
      </div>

      {/* QR Modal */}
      {showQR && qr && (
        <QRModal
          qr={qr}
          onClose={() => setShowQR(false)}
          onEnd={handleEndSession}
        />
      )}
    </div>
  );
}
