"use client"

import { useMemo, useState } from "react"
import { Flag } from "@/components/flag"
import { OpsPanel } from "@/components/ops-panel"
import { StatusBadge } from "@/components/status-badge"
import { cn } from "@/lib/utils"
import type { InternetPathViewModel } from "@/lib/dashboard-internet-path"
import { Maximize2Icon, ZoomInIcon, ZoomOutIcon } from "lucide-react"

type Pt = { x: number; y: number }
type ServerKind = "home-router" | "jump-host" | "exit-node"

const W = 1060
const H = 420
const ZOOM_MIN = 0.2
const ZOOM_MAX = 6

const STATUS_STYLE = {
  online: { fill: "#0f2d1f", stroke: "#4ade80", glow: "rgba(74,222,128,0.15)" },
  degraded: { fill: "#2d1e06", stroke: "#fbbf24", glow: "rgba(251,191,36,0.15)" },
  offline: { fill: "#2d0f0f", stroke: "#f87171", glow: "transparent" },
}

const TYPE_STYLE: Record<ServerKind, { label: string; fill: string; r: number }> = {
  "home-router": { label: "HR", fill: "#16a34a", r: 40 },
  "jump-host": { label: "JH", fill: "#7c3aed", r: 34 },
  "exit-node": { label: "EN", fill: "#0369a1", r: 30 },
}

const WAN_COLORS = ["#0ea5e9", "#f97316", "#a855f7", "#ec4899", "#14b8a6"]

function pingColor(ms: number | null) {
  if (ms == null) return "#f87171"
  if (ms < 15) return "#4ade80"
  if (ms < 50) return "#fbbf24"
  return "#fb923c"
}

function edgeBadgePosition(x1: number, y1: number, x2: number, y2: number, t: number, normalPx: number): { mx: number; my: number } {
  const px = x1 + (x2 - x1) * t
  const py = y1 + (y2 - y1) * t
  const dx = x2 - x1
  const dy = y2 - y1
  const len = Math.hypot(dx, dy) || 1
  const nx = -dy / len
  const ny = dx / len
  return { mx: px + nx * normalPx, my: py + ny * normalPx }
}

function ZoomControls({ zoom, onZoomIn, onZoomOut, onFit }: {
  zoom: number
  onZoomIn: () => void
  onZoomOut: () => void
  onFit: () => void
}) {
  return (
    <div className="absolute bottom-4 left-1/2 -translate-x-1/2 z-20 flex items-center gap-0 rounded-xl border border-white/10 bg-black/75 backdrop-blur-md shadow-xl overflow-hidden">
      <button onClick={onZoomOut} className="px-3 py-2 text-white/60 hover:text-white hover:bg-white/5 transition-colors">
        <ZoomOutIcon className="size-3.5" />
      </button>
      <span className="px-3 py-2 text-xs font-mono text-white/70 min-w-[52px] text-center border-x border-white/10 select-none">
        {Math.round(zoom * 100)}%
      </span>
      <button onClick={onZoomIn} className="px-3 py-2 text-white/60 hover:text-white hover:bg-white/5 transition-colors">
        <ZoomInIcon className="size-3.5" />
      </button>
      <div className="w-px h-5 bg-white/10" />
      <button onClick={onFit} className="px-3 py-2 text-white/60 hover:text-white hover:bg-white/5 transition-colors">
        <Maximize2Icon className="size-3.5" />
      </button>
    </div>
  )
}

function PingBadge({
  mx,
  my,
  ping,
  dl,
  ul,
  color,
  monitored,
}: {
  mx: number
  my: number
  ping: number | null
  dl: number | null
  ul: number | null
  color: string
  monitored?: boolean
}) {
  const hasSpeed = dl != null || ul != null
  const dlText = dl != null ? Math.round(dl) : "—"
  const ulText = ul != null ? Math.round(ul) : "—"
  return (
    <g transform={`translate(${mx},${my})`}>
      <rect x="-34" y={-20} width="68" height={hasSpeed ? 42 : 24} rx="4" fill="#060d1a" stroke={color} strokeWidth="0.7" opacity="0.92" />
      <text textAnchor="middle" y={hasSpeed ? "-5" : "4"} fontSize="8.5" fontWeight="600" fill={color} fontFamily="ui-monospace,monospace">
        {ping == null ? "—" : `${ping} мс`}
      </text>
      {hasSpeed && (
        <text textAnchor="middle" y="8" fontSize="7" fill="#64748b" fontFamily="ui-monospace,monospace">
          {`↓${dlText} ↑${ulText}`}
        </text>
      )}
      {monitored && (
        <text textAnchor="middle" y={hasSpeed ? "17" : "14"} fontSize="6" fill="#38bdf8" fontFamily="ui-monospace,monospace">
          mon
        </text>
      )}
    </g>
  )
}

function ServerNode({
  pos,
  type,
  name,
  site,
  country,
  status,
  selected,
  onClick,
}: {
  pos: Pt
  type: ServerKind
  name: string
  site: string
  country: string
  status: "online" | "offline" | "degraded"
  selected: boolean
  onClick: () => void
}) {
  const ss = STATUS_STYLE[status]
  const ts = TYPE_STYLE[type]
  return (
    <g transform={`translate(${pos.x},${pos.y})`} style={{ cursor: "pointer" }} onClick={onClick}>
      {status === "online" && (
        <circle r={ts.r + 14} fill={ss.glow} opacity="0.7">
          <animate attributeName="r" values={`${ts.r + 10};${ts.r + 18};${ts.r + 10}`} dur="3s" repeatCount="indefinite" />
          <animate attributeName="opacity" values="0.8;0.15;0.8" dur="3s" repeatCount="indefinite" />
        </circle>
      )}
      {selected && (
        <circle r={ts.r + 10} fill="none" stroke="rgba(255,255,255,0.45)" strokeWidth="1.5" strokeDasharray="4 3" />
      )}
      <circle r={ts.r} fill={ss.fill} stroke={ss.stroke} strokeWidth={selected ? 2.5 : 1.8} />
      <g transform={`translate(${ts.r - 10},-${ts.r - 10})`}>
        <circle r="10" fill={ts.fill} />
        <text textAnchor="middle" y="4" fontSize="6.5" fontWeight="bold" fill="#fff">{ts.label}</text>
      </g>
      <foreignObject x={-110} y={-22} width={220} height={28} style={{ overflow: "visible", pointerEvents: "none" }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 6, width: "100%", height: "100%", fontFamily: "ui-monospace, monospace" }} {...({ xmlns: "http://www.w3.org/1999/xhtml" } as Record<string, string>)}>
          <span style={{ flexShrink: 0, lineHeight: 0 }}>
            <Flag code={country || "UN"} size={16} />
          </span>
          <span style={{ maxWidth: 170, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontWeight: 700, fontSize: 11, color: "#f1f5f9", lineHeight: 1.25 }}>
            {site || name}
          </span>
        </div>
      </foreignObject>
      <text textAnchor="middle" y={ts.r + 18} fontSize="8.5" fill="#94a3b8" fontFamily="ui-monospace,monospace">
        {name}
      </text>
    </g>
  )
}

export function InternetPathMapCard({ model }: { model: InternetPathViewModel | null }) {
  const [zoom, setZoom] = useState(1)
  const [pan, setPan] = useState({ x: 0, y: 0 })
  const [isDragging, setIsDragging] = useState(false)
  const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(null)
  const [selectedNode, setSelectedNode] = useState<"home" | "jh" | "en" | "wan" | null>("home")

  const mapData = useMemo(() => {
    if (!model) return null
    const hop = model.currentHop ?? model.primaryHop ?? (
      model.activeWanUplink && model.fallbackJumpHost && model.fallbackExitNode
        ? {
            home: model.homeRouter,
            wan: model.activeWanUplink,
            jumpHost: model.fallbackJumpHost,
            exitNode: model.fallbackExitNode,
            wanJhMetrics: {
              pingMs: null,
              dlMbps: null,
              ulMbps: null,
              fromMonitoring: false,
            },
            jhExitMetrics: {
              pingMs: null,
              dlMbps: null,
              ulMbps: null,
              fromMonitoring: false,
            },
          }
        : null
    )
    if (!hop) return null
    const axisY = 220
    const homePos = { x: 180, y: axisY }
    const wanPos = { x: 400, y: axisY }
    const jhPos = { x: 660, y: axisY }
    const enPos = { x: 900, y: axisY }
    const directPos = { x: 900, y: axisY + 110 }
    const pathDiff =
      model.primaryPath &&
      model.currentPath &&
      (model.primaryPath.wanId !== model.currentPath.wanId || model.primaryPath.jhId !== model.currentPath.jhId || model.primaryPath.exitId !== model.currentPath.exitId)
    return { hop, homePos, wanPos, jhPos, enPos, directPos, pathDiff, directWan: model.directWan }
  }, [model])

  function onWheel(e: React.WheelEvent<SVGSVGElement>) {
    e.preventDefault()
    const rect = e.currentTarget.getBoundingClientRect()
    const px = e.clientX - rect.left
    const py = e.clientY - rect.top
    const worldX = (px - pan.x) / zoom
    const worldY = (py - pan.y) / zoom
    const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1
    const next = Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, zoom * factor))
    setZoom(next)
    setPan({ x: px - worldX * next, y: py - worldY * next })
  }

  return (
    <OpsPanel
      title="Internet path map"
      description="Основной и текущий путь трафика HomeRouter → Internet"
      headerRight={
          <StatusBadge
            status={
              model?.pathState === "healthy"
                ? "online"
                : model?.pathState === "failover"
                  ? "degraded"
                  : "offline"
            }
          />
      }
      contentClassName="px-5 pb-4"
    >
        {!model && (
          <div className="h-[240px] rounded-md border border-dashed border-border grid place-items-center text-sm text-muted-foreground">
            Недостаточно данных для построения маршрута
          </div>
        )}
        {model && mapData && (
          <div
            className="relative rounded-lg border border-[#1f2a3d] bg-gradient-to-b from-[#0a1424] to-[#060d17] overflow-hidden overscroll-contain"
            onWheelCapture={(e) => {
              // Когда курсор над картой, колесо управляет только картой (без прокрутки страницы).
              e.preventDefault()
              e.stopPropagation()
            }}
          >
            <svg
              viewBox={`0 0 ${W} ${H}`}
              className={cn("w-full h-[320px] select-none", isDragging ? "cursor-grabbing" : "cursor-grab")}
              onMouseDown={(e) => {
                setIsDragging(true)
                setDragStart({ x: e.clientX - pan.x, y: e.clientY - pan.y })
              }}
              onMouseMove={(e) => {
                if (!isDragging || !dragStart) return
                setPan({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y })
              }}
              onMouseUp={() => { setIsDragging(false); setDragStart(null) }}
              onMouseLeave={() => { setIsDragging(false); setDragStart(null) }}
              onWheel={onWheel}
            >
              <g transform={`translate(${pan.x} ${pan.y}) scale(${zoom})`}>
                <line x1={mapData.homePos.x} y1={mapData.homePos.y} x2={mapData.wanPos.x} y2={mapData.wanPos.y} stroke={WAN_COLORS[0]} strokeWidth="2.2" opacity="0.75" />
                <line
                  x1={mapData.wanPos.x}
                  y1={mapData.wanPos.y}
                  x2={mapData.jhPos.x}
                  y2={mapData.jhPos.y}
                  stroke={mapData.pathDiff ? "#fbbf24" : "#4ade80"}
                  strokeWidth={3.2}
                />
                <line
                  x1={mapData.jhPos.x}
                  y1={mapData.jhPos.y}
                  x2={mapData.enPos.x}
                  y2={mapData.enPos.y}
                  stroke={mapData.pathDiff ? "#fbbf24" : "#4ade80"}
                  strokeWidth={3.2}
                />
                {mapData.directWan.enabled && (
                  <line
                    x1={mapData.wanPos.x}
                    y1={mapData.wanPos.y}
                    x2={mapData.directPos.x}
                    y2={mapData.directPos.y}
                    stroke="#38bdf8"
                    strokeWidth="2.4"
                    opacity="0.9"
                  />
                )}

                <g transform={`translate(${mapData.wanPos.x},${mapData.wanPos.y})`} onClick={() => setSelectedNode("wan")} style={{ cursor: "pointer" }}>
                  <circle r={24} fill={`${WAN_COLORS[0]}1a`} stroke={WAN_COLORS[0]} strokeWidth="2" />
                  <path d="M -5 2 Q 0 -5 5 2" fill="none" stroke={WAN_COLORS[0]} strokeWidth="1.5" strokeLinecap="round" />
                  <path d="M -8 5 Q 0 -10 8 5" fill="none" stroke={WAN_COLORS[0]} strokeWidth="1" strokeLinecap="round" opacity="0.6" />
                  <circle cx="0" cy="4" r="2" fill={WAN_COLORS[0]} />
                  <text textAnchor="middle" y="36" fontSize="8" fontWeight="700" fill={WAN_COLORS[0]} fontFamily="ui-monospace,monospace">
                    {mapData.hop.wan.name}
                  </text>
                </g>

                <ServerNode
                  pos={mapData.homePos}
                  type="home-router"
                  name={mapData.hop.home.name}
                  site={mapData.hop.home.site}
                  country={mapData.hop.home.country}
                  status={mapData.hop.home.status}
                  selected={selectedNode === "home"}
                  onClick={() => setSelectedNode("home")}
                />
                {mapData.directWan.enabled && (
                  <g transform={`translate(${mapData.directPos.x},${mapData.directPos.y})`}>
                    <circle r={22} fill="#08243a" stroke="#38bdf8" strokeWidth="1.8" />
                    <text textAnchor="middle" y="4" fontSize="10" fontWeight="700" fill="#38bdf8">NET</text>
                    <text textAnchor="middle" y="34" fontSize="8" fill="#7dd3fc" fontFamily="ui-monospace,monospace">
                      {mapData.directWan.provider ?? "Direct WAN"}
                    </text>
                  </g>
                )}
                <ServerNode
                  pos={mapData.jhPos}
                  type="jump-host"
                  name={mapData.hop.jumpHost.name}
                  site={mapData.hop.jumpHost.site}
                  country={mapData.hop.jumpHost.country}
                  status={mapData.hop.jumpHost.status}
                  selected={selectedNode === "jh"}
                  onClick={() => setSelectedNode("jh")}
                />
                <ServerNode
                  pos={mapData.enPos}
                  type="exit-node"
                  name={mapData.hop.exitNode.name}
                  site={mapData.hop.exitNode.site}
                  country={mapData.hop.exitNode.country}
                  status={mapData.hop.exitNode.status}
                  selected={selectedNode === "en"}
                  onClick={() => setSelectedNode("en")}
                />

                <PingBadge
                  {...edgeBadgePosition(mapData.wanPos.x, mapData.wanPos.y, mapData.jhPos.x, mapData.jhPos.y, 0.52, -24)}
                  ping={mapData.hop.wanJhMetrics.pingMs}
                  dl={mapData.hop.wanJhMetrics.dlMbps}
                  ul={mapData.hop.wanJhMetrics.ulMbps}
                  color={pingColor(mapData.hop.wanJhMetrics.pingMs)}
                  monitored={mapData.hop.wanJhMetrics.fromMonitoring}
                />
                <PingBadge
                  {...edgeBadgePosition(mapData.jhPos.x, mapData.jhPos.y, mapData.enPos.x, mapData.enPos.y, 0.5, -24)}
                  ping={mapData.hop.jhExitMetrics.pingMs}
                  dl={mapData.hop.jhExitMetrics.dlMbps}
                  ul={mapData.hop.jhExitMetrics.ulMbps}
                  color={pingColor(mapData.hop.jhExitMetrics.pingMs)}
                  monitored={mapData.hop.jhExitMetrics.fromMonitoring}
                />
                {mapData.directWan.enabled && (
                  <PingBadge
                    {...edgeBadgePosition(mapData.wanPos.x, mapData.wanPos.y, mapData.directPos.x, mapData.directPos.y, 0.55, -22)}
                    ping={null}
                    dl={null}
                    ul={null}
                    color="#38bdf8"
                    monitored={false}
                  />
                )}
              </g>
            </svg>
            <ZoomControls
              zoom={zoom}
              onZoomOut={() => setZoom((z) => Math.max(ZOOM_MIN, z * 0.9))}
              onZoomIn={() => setZoom((z) => Math.min(ZOOM_MAX, z * 1.1))}
              onFit={() => { setZoom(1); setPan({ x: 0, y: 0 }) }}
            />
          </div>
        )}
        {model && !mapData && (
          <div className="h-[240px] rounded-md border border-dashed border-border grid place-items-center text-sm text-muted-foreground">
            Нет полного набора узлов для визуализации пути
          </div>
        )}
        {model && (
          <div className="mt-3 grid grid-cols-1 md:grid-cols-2 gap-2 text-xs">
            <div className={cn("rounded-md border p-2", model.pathState === "failover" ? "border-amber-500/40 bg-amber-500/5" : "border-emerald-500/40 bg-emerald-500/5")}>
              <p className="font-medium">Primary path</p>
              <p className="text-muted-foreground mt-1">{model.primaryPath?.reason ?? "Не определен"}</p>
            </div>
            <div className={cn("rounded-md border p-2", model.pathState === "failover" ? "border-amber-500/40 bg-amber-500/5" : "border-emerald-500/40 bg-emerald-500/5")}>
              <p className="font-medium">Current path</p>
              <p className="text-muted-foreground mt-1">{model.currentPath?.reason ?? "Не определен"}</p>
            </div>
            {model.directWan.enabled && (
              <div className="rounded-md border p-2 border-sky-500/40 bg-sky-500/5 md:col-span-2">
                <p className="font-medium">Direct WAN path</p>
                <p className="text-muted-foreground mt-1">
                  {`gateway: ${model.directWan.gateway ?? "—"} · iface: ${model.directWan.iface ?? "—"} · dhcp ip: ${model.directWan.leasedIp ?? "—"} · isp: ${model.directWan.provider ?? "—"}`}
                </p>
              </div>
            )}
          </div>
        )}
    </OpsPanel>
  )
}
