import React, { useMemo, useCallback, useEffect, useRef, useState } from 'react';
import {
  ReactFlow,
  Background,
  MiniMap,
  useEdgesState,
  useNodesState,
  addEdge,
  MarkerType,
  Handle,
  Position,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { IconZoomIn, IconZoomOut, IconMaximize, IconMinimize, IconSearch, IconX, IconRefresh } from '@tabler/icons-react';
import Tooltip from './components/Tooltip.jsx';

function GraphView({ servers, connections, onCreateConnection }) {
  const flowRef = useRef(null);
  const instanceRef = useRef(null);
  const containerRef = useRef(null);
  const [isFullscreen, setIsFullscreen] = useState(false);
  const [highlightedNodeId, setHighlightedNodeId] = useState(null);
  const [selectedNodeId, setSelectedNodeId] = useState(null);
  const [searchTerm, setSearchTerm] = useState('');
  const [showSearch, setShowSearch] = useState(false);
  const STORAGE_KEY = 'graph-layout-servers-v1';

  const getTunnelStyle = useCallback((tunnelType) => {
    const map = {
      GRE: { color: '#206bc4', dash: '0', width: 2.5 },
      IPSec: { color: '#f59f00', dash: '6,4', width: 2.5 },
      WireGuard: { color: '#2fb344', dash: '0', width: 3.2 },
      OpenVPN: { color: '#be4bdb', dash: '3,3', width: 2.5 },
    };
    return map[tunnelType] || { color: '#667382', dash: '5,5', width: 2 };
  }, []);

  const getCountryColor = useCallback((country) => {
    const colors = {
      RU: '#dc2626',
      US: '#2563eb',
      DE: '#059669',
      SE: '#7c3aed',
      NL: '#ea580c',
      SG: '#0891b2',
    };
    return colors[country] || '#6b7280';
  }, []);

  const computeGridPosition = useCallback((index, total) => {
    const cols = Math.ceil(Math.sqrt(total));
    const row = Math.floor(index / cols);
    const col = index % cols;
    const spacingX = 280;
    const spacingY = 180;
    return { x: 80 + col * spacingX, y: 80 + row * spacingY };
  }, []);

  const initialNodesData = useMemo(() => {
    // Базовая сетка
    const baseNodes = (servers || []).map((s, i) => ({
      id: String(s.ip),
      type: 'server',
      position: computeGridPosition(i, servers.length),
      data: { server: s },
    }));

    // Переопределяем позиции из localStorage, если есть
    if (typeof window !== 'undefined') {
      try {
        const raw = window.localStorage.getItem(STORAGE_KEY);
        if (raw) {
          const saved = JSON.parse(raw) || {};
          return baseNodes.map((n) => {
            const savedPos = saved[n.id];
            if (savedPos && typeof savedPos.x === 'number' && typeof savedPos.y === 'number') {
              return { ...n, position: { x: savedPos.x, y: savedPos.y } };
            }
            return n;
          });
        }
      } catch {
        // игнорируем проблемы с localStorage
      }
    }

    return baseNodes;
  }, [servers, computeGridPosition]);

  const [nodes, setNodes, onNodesChangeInternal] = useNodesState(initialNodesData);

  // Обёртка над onNodesChange: обновляем состояние и сохраняем позиции в localStorage
  const onNodesChange = useCallback(
    (changes) => {
      onNodesChangeInternal(changes);
      // Сохраняем только позиции
      setNodes((current) => {
        if (typeof window !== 'undefined') {
          try {
            const layout = {};
            current.forEach((n) => {
              if (n.position) {
                layout[n.id] = { x: n.position.x, y: n.position.y };
              }
            });
            window.localStorage.setItem(STORAGE_KEY, JSON.stringify(layout));
          } catch {
            // ignore
          }
        }
        return current;
      });
    },
    [onNodesChangeInternal, setNodes]
  );

  useEffect(() => {
    setNodes(initialNodesData);
  }, [initialNodesData, setNodes]);

  // Подсветка связей: вычисляем какие связи связаны с выделенным/выбранным узлом
  // ВАЖНО: должно быть ПЕРЕД initialEdgesData, чтобы использоваться там
  const highlightedEdges = useMemo(() => {
    const nodeId = selectedNodeId || highlightedNodeId;
    if (!nodeId) return new Set();
    const related = new Set();
    (connections || []).forEach((c, idx) => {
      if (String(c.from) === nodeId || String(c.to) === nodeId) {
        related.add(`${c.from}-${c.to}-${idx}`);
      }
    });
    return related;
  }, [selectedNodeId, highlightedNodeId, connections]);

  // Счётчик связей для каждого сервера
  // ВАЖНО: должно быть ПЕРЕД nodeTypes, чтобы использоваться там
  const connectionCounts = useMemo(() => {
    const counts = {};
    (servers || []).forEach((s) => {
      const ip = String(s.ip);
      counts[ip] = (connections || []).filter((c) => String(c.from) === ip || String(c.to) === ip).length;
    });
    return counts;
  }, [servers, connections]);

  const initialEdgesData = useMemo(() => {
    return (connections || []).map((c, idx) => {
      const style = getTunnelStyle(c.tunnelType);
      const baseLabel = c.tunnelType || 'TUNNEL';
      const ipLabel = c.ipA && c.ipB ? `${c.ipA} ⇄ ${c.ipB}` : '';
      const edgeId = `${c.from}-${c.to}-${idx}`;
      const isHighlighted = highlightedEdges.has(edgeId);
      return {
        id: edgeId,
        source: String(c.from),
        target: String(c.to),
        label: ipLabel ? `${baseLabel} · ${ipLabel}` : baseLabel,
        type: 'smoothstep',
        style: {
          stroke: style.color,
          strokeWidth: isHighlighted ? style.width * 1.5 : style.width,
          strokeDasharray: style.dash,
          opacity: highlightedNodeId || selectedNodeId ? (isHighlighted ? 1 : 0.25) : 0.9,
          filter: isHighlighted ? 'drop-shadow(0 0 4px ' + style.color + ')' : 'none',
        },
        labelBgPadding: [6, 4],
        labelBgBorderRadius: 999,
        labelStyle: {
          fontSize: 11,
          fontWeight: 500,
          fill: '#0f172a',
        },
        className: c.tunnelType ? `edge-tunnel-${String(c.tunnelType).toLowerCase()}` : 'edge-tunnel-default',
        markerStart: { type: MarkerType.ArrowClosed, color: style.color, width: 16, height: 16 },
        markerEnd: { type: MarkerType.ArrowClosed, color: style.color, width: 16, height: 16 },
        animated: false,
      };
    });
  }, [connections, getTunnelStyle, highlightedEdges, highlightedNodeId, selectedNodeId]);

  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdgesData);

  useEffect(() => {
    setEdges(initialEdgesData);
  }, [initialEdgesData, setEdges]);

  // Поиск сервера: фильтруем по IP, DNS, провайдеру
  const searchResults = useMemo(() => {
    if (!searchTerm.trim()) return [];
    const term = searchTerm.toLowerCase();
    return (servers || []).filter((s) => 
      String(s.ip).toLowerCase().includes(term) ||
      String(s.dns || '').toLowerCase().includes(term) ||
      String(s.provider || '').toLowerCase().includes(term)
    );
  }, [searchTerm, servers]);

  // Фокус на найденный сервер
  const focusNode = useCallback((nodeId) => {
    if (!instanceRef.current || !nodeId) return;
    try {
      instanceRef.current.fitView({ 
        nodes: [{ id: nodeId }], 
        padding: 0.3, 
        duration: 400 
      });
      setSelectedNodeId(nodeId);
      setTimeout(() => setSelectedNodeId(null), 2000);
    } catch {}
  }, []);

  // Сброс раскладки: очищаем localStorage и пересоздаём ноды
  const resetLayout = useCallback(() => {
    if (typeof window !== 'undefined') {
      try {
        window.localStorage.removeItem(STORAGE_KEY);
      } catch {}
    }
    setNodes((current) => {
      return current.map((n, i) => ({
        ...n,
        position: computeGridPosition(i, current.length),
      }));
    });
    setTimeout(() => {
      if (instanceRef.current) {
        try {
          instanceRef.current.fitView({ padding: 0.2 });
        } catch {}
      }
    }, 100);
  }, [setNodes, computeGridPosition]);

  const onConnect = useCallback(
    (params) => {
      // Делегируем создание связи в родителя, чтобы сохранить единую логику хранения
      if (!params?.source || !params?.target || params.source === params.target) return;
      if (onCreateConnection) {
        onCreateConnection({ from: params.source, to: params.target });
      }
    },
    [onCreateConnection]
  );

  const nodeTypes = useMemo(
    () => ({
      server: ({ id, data }) => {
        const s = data.server || {};
        const countryColor = getCountryColor(s.country);
        const getFlagEmoji = (code) => {
          if (!code) return '';
          const map = { SWE: 'SE', UK: 'GB' };
          const ccRaw = String(code).trim().toUpperCase();
          const cc = (map[ccRaw] || ccRaw).slice(0, 2);
          if (cc.length !== 2) return ccRaw;
          return cc.replace(/./g, (ch) => String.fromCodePoint(127397 + ch.charCodeAt()));
        };
        const flag = getFlagEmoji(s.country);
        const isHighlighted = highlightedNodeId === id;
        const isSelected = selectedNodeId === id;
        const connCount = connectionCounts[id] || 0;
        const tooltipContent = (
          <div style={{ fontSize: '12px', lineHeight: '1.5' }}>
            <div><strong>IP:</strong> {s.ip}</div>
            <div><strong>DNS:</strong> {s.dns}</div>
            <div><strong>Провайдер:</strong> {s.provider}</div>
            <div><strong>Страна:</strong> {s.country}</div>
            <div><strong>Туннель:</strong> {s.tunnel}</div>
            {s.gateway && <div><strong>Шлюз:</strong> {s.gateway}</div>}
            <div style={{ marginTop: '4px', paddingTop: '4px', borderTop: '1px solid rgba(255,255,255,0.2)' }}>
              <strong>Связей:</strong> {connCount}
            </div>
          </div>
        );
        return (
          <Tooltip content={tooltipContent} position="top" delay={300}>
            <div
              className={`card shadow-sm${isHighlighted || isSelected ? ' border-primary' : ''}`}
              style={{
                width: 200,
                borderRadius: 12,
                border: `2px solid ${isSelected ? '#206bc4' : isHighlighted ? '#206bc4' : countryColor}`,
                overflow: 'hidden',
                background: '#fff',
                boxShadow: isSelected
                  ? '0 0 0 2px rgba(32,107,196,0.2), 0 12px 28px rgba(15,23,42,0.3)'
                  : isHighlighted
                  ? '0 0 0 1px rgba(32,107,196,0.15), 0 10px 24px rgba(15,23,42,0.25)'
                  : '0 4px 12px rgba(15,23,42,0.12)',
                transform: isSelected ? 'translateY(-3px) scale(1.02)' : isHighlighted ? 'translateY(-2px)' : 'translateY(0)',
                transition: 'box-shadow 120ms ease-out, transform 120ms ease-out, border-color 120ms ease-out',
                cursor: 'pointer',
              }}
              onMouseEnter={() => setHighlightedNodeId(id)}
              onMouseLeave={() => setHighlightedNodeId((prev) => (prev === id ? null : prev))}
              onClick={() => {
                if (selectedNodeId === id) {
                  setSelectedNodeId(null);
                } else {
                  setSelectedNodeId(id);
                }
              }}
            >
            {/* Точка входа соединений */}
            <Handle type="target" position={Position.Left} style={{ background: countryColor }} />
            <div className="px-2 py-1 d-flex align-items-center" style={{ background: '#f8fafc', borderBottom: '1px solid #eef2f7' }}>
              <div className="d-flex align-items-center" style={{ gap: 6 }}>
                <span style={{ fontSize: 16, lineHeight: '1' }}>{flag}</span>
                <span
                  className="badge"
                  style={{
                    background: '#fff',
                    color: '#475569',
                    border: `1px solid ${countryColor}`,
                    borderRadius: 8,
                    fontSize: 11,
                  }}
                >
                  {String(s.country || '').toUpperCase().slice(0, 3)}
                </span>
              </div>
              <div className="ms-2 text-truncate" style={{ fontWeight: 700, color: '#1f2937', fontSize: 13 }}>{s.dns}</div>
              {connCount > 0 && (
                <span
                  className="badge ms-auto"
                  style={{
                    background: isSelected ? '#206bc4' : '#e0e7ff',
                    color: isSelected ? '#fff' : '#206bc4',
                    fontSize: 10,
                    fontWeight: 600,
                    minWidth: '20px',
                    height: '18px',
                    display: 'inline-flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                  }}
                  title={`${connCount} ${connCount === 1 ? 'связь' : connCount < 5 ? 'связи' : 'связей'}`}
                >
                  {connCount}
                </span>
              )}
            </div>
            <div className="px-2 py-2" style={{ lineHeight: 1.2 }}>
              <div style={{ fontSize: 12, color: '#334155' }}>{s.ip}</div>
              <div style={{ fontSize: 10, color: '#6b7280' }}>{s.provider}</div>
            </div>
            {/* Точка исхода соединений */}
            <Handle type="source" position={Position.Right} style={{ background: countryColor }} />
          </div>
          </Tooltip>
        );
      },
    }),
    [getCountryColor, highlightedNodeId, selectedNodeId, connectionCounts]
  );

  const onInit = useCallback((inst) => {
    instanceRef.current = inst;
    // Автоподгон при инициализации
    requestAnimationFrame(() => {
      try {
        inst.fitView({ padding: 0.2, includeHiddenNodes: true, minZoom: 0.2, maxZoom: 2 });
      } catch {}
    });
  }, []);

  useEffect(() => {
    if (!instanceRef.current) return;
    // Подгон при изменении данных
    const i = instanceRef.current;
    const t = setTimeout(() => {
      try {
        i.fitView({ padding: 0.2, includeHiddenNodes: true, minZoom: 0.2, maxZoom: 2 });
      } catch {}
    }, 50);
    return () => clearTimeout(t);
  }, [servers, connections]);

  // Трек полноэкранного режима и авто-fit после входа/выхода
  useEffect(() => {
    const handler = () => {
      const fs = Boolean(document.fullscreenElement);
      setIsFullscreen(fs);
      if (instanceRef.current) {
        setTimeout(() => {
          try {
            instanceRef.current.fitView({ padding: 0.2 });
          } catch {}
        }, 60);
      }
    };
    document.addEventListener('fullscreenchange', handler);
    return () => document.removeEventListener('fullscreenchange', handler);
  }, []);

  if (!servers || servers.length === 0) {
    return (
      <div className="text-center py-5">
        <div className="text-muted">
          <h4>Нет серверов для отображения</h4>
          <p>Добавьте серверы, чтобы увидеть граф связей</p>
        </div>
      </div>
    );
  }

  return (
    <div
      ref={containerRef}
      style={{
        width: '100%',
        height: isFullscreen ? '100vh' : 500,
        border: '1px solid #e5e7eb',
        borderRadius: 8,
        overflow: 'hidden',
        position: 'relative',
        background: '#f8fafc',
      }}
    >
      <ReactFlow
        ref={flowRef}
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        nodeTypes={nodeTypes}
        fitView
        defaultEdgeOptions={{
          type: 'smoothstep',
        }}
        onInit={onInit}
        style={{ width: '100%', height: '100%', background: '#f8fafc' }}
      >
        <Background variant="dots" gap={20} size={1} color="#e5e7eb" />
        <MiniMap
          nodeColor={(n) => getCountryColor(n.data?.server?.country)}
          nodeStrokeWidth={2}
          maskColor="rgba(0,0,0,0.05)"
        />
      </ReactFlow>
      {/* Поиск сервера */}
      {showSearch && (
        <div className="position-absolute" style={{ left: 10, top: 10, zIndex: 10, pointerEvents: 'auto', minWidth: 280 }}>
          <div className="card shadow-lg" style={{ borderRadius: 8 }}>
            <div className="card-body p-2">
              <div className="input-icon">
                <span className="input-icon-addon">
                  <IconSearch size={16} />
                </span>
                <input
                  type="text"
                  className="form-control form-control-sm"
                  placeholder="Поиск по IP, DNS, провайдеру..."
                  value={searchTerm}
                  onChange={(e) => setSearchTerm(e.target.value)}
                  autoFocus
                />
                <button
                  type="button"
                  className="btn btn-ghost-secondary btn-icon btn-sm"
                  style={{ position: 'absolute', right: '4px', top: '50%', transform: 'translateY(-50%)' }}
                  onClick={() => {
                    setShowSearch(false);
                    setSearchTerm('');
                  }}
                  aria-label="Закрыть поиск"
                >
                  <IconX size={14} />
                </button>
              </div>
              {searchTerm.trim() && searchResults.length > 0 && (
                <div className="mt-2" style={{ maxHeight: '200px', overflowY: 'auto' }}>
                  {searchResults.map((s) => (
                    <button
                      key={s.ip}
                      type="button"
                      className="btn btn-ghost-secondary btn-sm w-100 text-start mb-1"
                      onClick={() => {
                        focusNode(String(s.ip));
                        setShowSearch(false);
                        setSearchTerm('');
                      }}
                      style={{ fontSize: '12px' }}
                    >
                      <div className="fw-bold">{s.dns}</div>
                      <div className="text-muted small">{s.ip} · {s.provider}</div>
                    </button>
                  ))}
                </div>
              )}
              {searchTerm.trim() && searchResults.length === 0 && (
                <div className="mt-2 text-muted small text-center">Ничего не найдено</div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* Своя панель управления: Поиск, -, +, Fit, Reset, Fullscreen */}
      <div className="position-absolute" style={{ right: 10, top: 10, zIndex: 10, pointerEvents: 'auto' }}>
        <div className="btn-group btn-group-sm">
          <Tooltip content="Поиск сервера" position="left">
            <button
              type="button"
              className="btn btn-outline-secondary btn-icon"
              onClick={() => setShowSearch(!showSearch)}
              aria-label="Поиск сервера"
            >
              <IconSearch size={16} />
            </button>
          </Tooltip>
          <Tooltip content="Сбросить раскладку" position="left">
            <button
              type="button"
              className="btn btn-outline-secondary btn-icon"
              onClick={resetLayout}
              aria-label="Сбросить раскладку"
            >
              <IconRefresh size={16} />
            </button>
          </Tooltip>
          <Tooltip content="Уменьшить масштаб" position="left">
            <button
              type="button"
              className="btn btn-outline-secondary btn-icon"
              onClick={() => instanceRef.current?.zoomOut?.()}
              aria-label="Уменьшить масштаб"
            >
              <IconZoomOut size={16} />
            </button>
          </Tooltip>
          <Tooltip content="Увеличить масштаб" position="left">
            <button
              type="button"
              className="btn btn-outline-secondary btn-icon"
              onClick={() => instanceRef.current?.zoomIn?.()}
              aria-label="Увеличить масштаб"
            >
              <IconZoomIn size={16} />
            </button>
          </Tooltip>
          <Tooltip content="Подогнать граф к окну" position="left">
            <button
              type="button"
              className="btn btn-outline-secondary"
              onClick={() => instanceRef.current?.fitView?.({ padding: 0.2 })}
              aria-label="Подогнать граф к окну"
            >
              Fit
            </button>
          </Tooltip>
          <Tooltip content={isFullscreen ? 'Выйти из полноэкранного режима' : 'Во весь экран'} position="left">
            <button
              type="button"
              className="btn btn-outline-secondary btn-icon"
              onClick={() => {
                const el = containerRef.current;
                if (!el) return;
                if (!document.fullscreenElement) {
                  el.requestFullscreen?.();
                } else {
                  document.exitFullscreen?.();
                }
              }}
              aria-label={isFullscreen ? 'Выйти из полноэкранного режима' : 'Во весь экран'}
            >
              {isFullscreen ? <IconMinimize size={16} /> : <IconMaximize size={16} />}
            </button>
          </Tooltip>
        </div>
      </div>
    </div>
  );
}

export default GraphView;