"use client";

import React, { useEffect, useRef, useState } from "react";
import "./knowledge.css";
import {
  fetchGroups,
  fetchAllSignals,
  Group,
  Signal,
  getSeverityColor,
  parseMetaList,
} from "../lib/api";

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

interface NodeDef {
  id: string;
  label: string;
  x: number; // 0..100 percentage
  y: number; // 0..100 percentage
  size: "core" | "group" | "signal";
  icon: string;
  color: string;
  tooltip: { title: string; lines: string[] };
}

interface EdgeDef {
  from: string;
  to: string;
  dashed?: boolean;
  opacity?: number;
}

// ─── Layout helpers ───────────────────────────────────────────────────────────

const CORE = { x: 52, y: 48 };

/** Evenly distribute groups in a circle around the core */
function groupPositions(count: number) {
  const positions: { x: number; y: number }[] = [];
  for (let i = 0; i < count; i++) {
    const angle = (2 * Math.PI * i) / count - Math.PI / 2;
    const rx = 28; // ellipse horizontal radius (% units)
    const ry = 22; // vertical radius
    positions.push({
      x: CORE.x + rx * Math.cos(angle),
      y: CORE.y + ry * Math.sin(angle),
    });
  }
  return positions;
}

/** Place signal satellites around their parent group node */
function signalPositions(
  parentX: number,
  parentY: number,
  count: number,
  startAngle: number
) {
  const r = 9;
  return Array.from({ length: count }, (_, i) => {
    const angle = startAngle + (2 * Math.PI * i) / count;
    return {
      x: parentX + r * Math.cos(angle),
      y: parentY + r * Math.sin(angle),
    };
  });
}

const SIGNAL_TYPE_ICONS: Record<string, string> = {
  security_concern: "security",
  architecture_decision: "architecture",
  tech_debt: "construction",
  consensus: "check_circle",
  blocker: "block",
  risk: "warning",
  sentiment_spike: "mood",
  knowledge_gap: "help",
  decision: "gavel",
  action_item: "task_alt",
  trend: "trending_up",
  default: "sensors",
};

function getSignalTypeIcon(type: string): string {
  return SIGNAL_TYPE_ICONS[type] ?? SIGNAL_TYPE_ICONS.default;
}

// ─── Node Components ──────────────────────────────────────────────────────────

function CoreNode({ node }: { node: NodeDef }) {
  const [hovered, setHovered] = useState(false);
  return (
    <div
      className="absolute pointer-events-auto cursor-pointer group"
      style={{ left: `${node.x}%`, top: `${node.y}%`, transform: "translate(-50%,-50%)" }}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    >
      <div className="relative">
        <div className="absolute inset-0 bg-violet-500 rounded-full blur-xl opacity-40 group-hover:opacity-70 transition-opacity" />
        <div className="relative w-14 h-14 glass-card rounded-xl neon-border flex items-center justify-center rotate-45 group-hover:scale-110 transition-transform bg-[#19191d]/60">
          <span
            className="material-symbols-outlined text-violet-400 -rotate-45 block"
            style={{ fontVariationSettings: "'FILL' 1" }}
          >
            auto_awesome
          </span>
        </div>
        {hovered && (
          <div className="absolute top-full left-1/2 -translate-x-1/2 mt-4 z-20 w-52 pointer-events-none">
            <div className="glass-card neon-border p-3 rounded-lg shadow-2xl bg-[#09090b]/90">
              <p className="text-[10px] font-mono-data text-violet-400 mb-1">NODE::CORE_AI</p>
              <p className="text-xs font-bold text-zinc-200">{node.tooltip.title}</p>
              <div className="h-[1px] bg-violet-500/20 my-2" />
              {node.tooltip.lines.map((l, i) => (
                <p key={i} className="text-[9px] font-mono-data text-zinc-500">{l}</p>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function GroupNode({ node }: { node: NodeDef }) {
  const [hovered, setHovered] = useState(false);
  return (
    <div
      className="absolute pointer-events-auto cursor-pointer group"
      style={{ left: `${node.x}%`, top: `${node.y}%`, transform: "translate(-50%,-50%)" }}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    >
      <div className="relative">
        <div
          className="absolute inset-0 rounded-full blur-md opacity-30 group-hover:opacity-60 transition-opacity"
          style={{ backgroundColor: node.color }}
        />
        <div
          className="relative w-11 h-11 glass-card rounded-full neon-border flex items-center justify-center group-hover:scale-110 transition-all bg-[#19191d]/60"
        >
          <span className="material-symbols-outlined text-lg" style={{ color: node.color }}>
            {node.icon}
          </span>
        </div>
        <p className="absolute -bottom-6 left-1/2 -translate-x-1/2 text-[8px] font-mono-data text-zinc-500 uppercase tracking-tighter group-hover:text-violet-400 whitespace-nowrap max-w-[80px] overflow-hidden text-ellipsis text-center">
          {node.label}
        </p>
        {hovered && (
          <div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-3 z-20 w-52 pointer-events-none">
            <div className="glass-card neon-border p-3 rounded-lg shadow-2xl bg-[#09090b]/90">
              <p className="text-[10px] font-mono-data mb-1" style={{ color: node.color }}>
                NODE::GROUP
              </p>
              <p className="text-xs font-bold text-zinc-200 mb-2">{node.tooltip.title}</p>
              <div className="h-[1px] bg-violet-500/20 my-2" />
              {node.tooltip.lines.map((l, i) => (
                <p key={i} className="text-[9px] font-mono-data text-zinc-400">{l}</p>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function SignalNode({ node }: { node: NodeDef }) {
  const [hovered, setHovered] = useState(false);
  return (
    <div
      className="absolute pointer-events-auto cursor-pointer"
      style={{ left: `${node.x}%`, top: `${node.y}%`, transform: "translate(-50%,-50%)" }}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    >
      <div className="relative">
        <div
          className="relative w-7 h-7 glass-card rounded-full flex items-center justify-center hover:scale-125 transition-all"
          style={{ border: `1px solid ${node.color}40` }}
        >
          <span className="material-symbols-outlined" style={{ color: node.color, fontSize: "13px" }}>
            {node.icon}
          </span>
        </div>
        {hovered && (
          <div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-20 w-44 pointer-events-none">
            <div className="glass-card p-2.5 rounded-lg shadow-2xl bg-[#09090b]/90" style={{ border: `1px solid ${node.color}30` }}>
              <p className="text-[9px] font-mono-data mb-0.5" style={{ color: node.color }}>
                SIGNAL::{node.tooltip.title.toUpperCase().replace(/ /g, "_")}
              </p>
              {node.tooltip.lines.map((l, i) => (
                <p key={i} className="text-[8px] font-mono-data text-zinc-500 leading-relaxed">{l}</p>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

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

export default function NetworkMap() {
  const [nodes, setNodes] = useState<NodeDef[]>([]);
  const [edges, setEdges] = useState<EdgeDef[]>([]);
  const [loading, setLoading] = useState(true);
  const [totalSignals, setTotalSignals] = useState(0);

  // ── Pan state ──
  const [pan, setPan] = useState({ x: 0, y: 0 });
  const dragging = useRef(false);
  const dragStart = useRef({ x: 0, y: 0, panX: 0, panY: 0 });

  const handleMouseDown = (e: React.MouseEvent) => {
    if ((e.target as HTMLElement).closest(".pointer-events-auto")) return;
    dragging.current = true;
    dragStart.current = { x: e.clientX, y: e.clientY, panX: pan.x, panY: pan.y };
  };

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!dragging.current) return;
    const dx = e.clientX - dragStart.current.x;
    const dy = e.clientY - dragStart.current.y;
    setPan({ x: dragStart.current.panX + dx, y: dragStart.current.panY + dy });
  };

  const handleMouseUp = () => { dragging.current = false; };

  const resetPan = () => setPan({ x: 0, y: 0 });

  useEffect(() => {
    async function build() {
      try {
        const [groups, allGroupSignals] = await Promise.all([
          fetchGroups(),
          fetchAllSignals(),
        ]);

        const sigMap: Record<string, Signal[]> = {};
        allGroupSignals.forEach((g) => {
          sigMap[g.group_id] = g.signals;
        });
        const total = allGroupSignals.reduce((acc, g) => acc + g.signals.length, 0);
        setTotalSignals(total);

        const newNodes: NodeDef[] = [];
        const newEdges: EdgeDef[] = [];

        // Core node
        const coreId = "core_ai";
        newNodes.push({
          id: coreId,
          label: "ThirdEye AI",
          x: CORE.x,
          y: CORE.y,
          size: "core",
          icon: "auto_awesome",
          color: "#A78BFA",
          tooltip: {
            title: "ThirdEye Neural Engine",
            lines: [
              `GROUPS: ${groups.length}`,
              `SIGNALS: ${total}`,
              "STATUS: ACTIVE",
            ],
          },
        });

        // Group nodes
        const gPositions = groupPositions(Math.max(groups.length, 1));

        const LENS_COLORS: Record<string, string> = {
          dev: "#00daf3",
          product: "#A78BFA",
          client: "#ffb300",
          community: "#10b981",
          meet: "#ff6f78",
          unknown: "#6b7280",
        };

        groups.forEach((group, gi) => {
          const pos = gPositions[gi];
          const signals = sigMap[group.group_id] || [];
          const color = LENS_COLORS[group.lens] || LENS_COLORS.unknown;
          const groupId = `group_${group.group_id}`;

          // Count signal types
          const typeCounts: Record<string, number> = {};
          signals.forEach((s) => {
            const t = s.metadata.type;
            typeCounts[t] = (typeCounts[t] || 0) + 1;
          });
          const topTypes = Object.entries(typeCounts)
            .sort(([, a], [, b]) => b - a)
            .slice(0, 3);

          newNodes.push({
            id: groupId,
            label: group.group_name,
            x: pos.x,
            y: pos.y,
            size: "group",
            icon: "group",
            color,
            tooltip: {
              title: group.group_name,
              lines: [
                `LENS: ${group.lens?.toUpperCase() || "UNKNOWN"}`,
                `SIGNALS: ${group.signal_count}`,
                ...topTypes.map(([t, c]) => `${t.replace(/_/g, " ")}: ${c}`),
              ],
            },
          });

          // Edge: core → group
          newEdges.push({ from: coreId, to: groupId, opacity: 0.8 });

          // Signal satellite nodes (top 3 signal types)
          const angleSeed = (gi / Math.max(groups.length, 1)) * Math.PI * 2;
          const sPositions = signalPositions(pos.x, pos.y, topTypes.length, angleSeed);

          topTypes.forEach(([type, count], si) => {
            const sigNodeId = `sig_${gi}_${si}`;
            const severity =
              signals.find((s) => s.metadata.type === type)?.metadata.severity || "low";
            newNodes.push({
              id: sigNodeId,
              label: type,
              x: sPositions[si].x,
              y: sPositions[si].y,
              size: "signal",
              icon: getSignalTypeIcon(type),
              color: getSeverityColor(severity),
              tooltip: {
                title: type.replace(/_/g, " "),
                lines: [`COUNT: ${count}`, `SEVERITY: ${severity.toUpperCase()}`],
              },
            });
            newEdges.push({ from: groupId, to: sigNodeId, dashed: true, opacity: 0.5 });
          });

          // Cross-edges between adjacent groups (every even group connects to next)
          if (gi > 0 && gi % 2 === 0 && groups.length > 2) {
            newEdges.push({
              from: `group_${groups[gi - 1].group_id}`,
              to: groupId,
              dashed: true,
              opacity: 0.2,
            });
          }
        });

        // If no groups yet, show a placeholder set
        if (groups.length === 0) {
          ["dev", "product", "client"].forEach((lens, i) => {
            const pos = gPositions[i] || { x: 30 + i * 20, y: 45 };
            const gId = `placeholder_${lens}`;
            newNodes.push({
              id: gId,
              label: `${lens}_group`,
              x: pos.x,
              y: pos.y,
              size: "group",
              icon: "group_off",
              color: "#3f3f46",
              tooltip: {
                title: `${lens.toUpperCase()} Group`,
                lines: ["No data yet", "Connect Telegram to populate"],
              },
            });
            newEdges.push({ from: coreId, to: gId, dashed: true, opacity: 0.15 });
          });
        }

        setNodes(newNodes);
        setEdges(newEdges);
      } catch {
        // silently fail
      } finally {
        setLoading(false);
      }
    }
    build();
  }, []);

  // Build a quick lookup for node positions
  const nodePos: Record<string, { x: number; y: number }> = {};
  nodes.forEach((n) => { nodePos[n.id] = { x: n.x, y: n.y }; });

  return (
    <div
      className="absolute inset-0 z-0 overflow-hidden"
      style={{ cursor: dragging.current ? "grabbing" : "grab" }}
      onMouseDown={handleMouseDown}
      onMouseMove={handleMouseMove}
      onMouseUp={handleMouseUp}
      onMouseLeave={handleMouseUp}
    >
      {/* Pan hint */}
      {!loading && (pan.x !== 0 || pan.y !== 0) && (
        <button
          className="absolute top-3 left-1/2 -translate-x-1/2 z-30 flex items-center gap-1.5 px-3 py-1 rounded-full bg-black/60 border border-violet-500/30 text-[9px] font-mono-data text-violet-400 hover:text-white hover:bg-violet-900/40 transition-all pointer-events-auto"
          onClick={resetPan}
        >
          <span className="material-symbols-outlined text-[12px]">center_focus_weak</span>
          RESET VIEW
        </button>
      )}

      {/* Pannable graph content */}
      <div
        className="absolute inset-0"
        style={{ transform: `translate(${pan.x}px, ${pan.y}px)`, willChange: "transform" }}
      >
        {/* SVG Edges */}
        <svg className="absolute inset-0 w-full h-full pointer-events-none" style={{ overflow: "visible" }}>
          <defs>
            {/* Strong glow – core edge packets */}
            <filter id="glow-strong" x="-80%" y="-80%" width="260%" height="260%">
              <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur" />
              <feMerge>
                <feMergeNode in="blur" />
                <feMergeNode in="blur" />
                <feMergeNode in="SourceGraphic" />
              </feMerge>
            </filter>
            {/* Subtle glow – secondary edges */}
            <filter id="glow-subtle" x="-60%" y="-60%" width="220%" height="220%">
              <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur" />
              <feMerge>
                <feMergeNode in="blur" />
                <feMergeNode in="SourceGraphic" />
              </feMerge>
            </filter>
          </defs>

          {edges.map((edge, i) => {
            const from = nodePos[edge.from];
            const to   = nodePos[edge.to];
            if (!from || !to) return null;

            const isCoreEdge = !edge.dashed;
            // Speed: 0.7 – 1.3 s per edge, staggered so packets never sync
            const duration   = 0.7 + (i * 0.18) % 0.6;
            const phase      = (t: number) => -(i * t % Math.round(duration * 1000));

            if (isCoreEdge) {
              return (
                <g key={i}>
                  {/* Solid base track */}
                  <line
                    x1={`${from.x}%`} y1={`${from.y}%`}
                    x2={`${to.x}%`}   y2={`${to.y}%`}
                    stroke="rgba(255,255,255,0.12)"
                    strokeWidth="1.5"
                  />
                  {/* Violet ambient trace */}
                  <line
                    x1={`${from.x}%`} y1={`${from.y}%`}
                    x2={`${to.x}%`}   y2={`${to.y}%`}
                    stroke="#A78BFA"
                    strokeWidth="2"
                    opacity="0.45"
                    filter="url(#glow-subtle)"
                  />
                  {/* Packet 1 – bright white, leading */}
                  <line
                    x1={`${from.x}%`} y1={`${from.y}%`}
                    x2={`${to.x}%`}   y2={`${to.y}%`}
                    stroke="#ffffff"
                    strokeWidth="2.5"
                    strokeLinecap="round"
                    strokeDasharray="14 220"
                    opacity="1"
                    filter="url(#glow-strong)"
                    style={{ animation: `data-packet ${duration}s linear infinite`, animationDelay: `${phase(130)}ms` }}
                  />
                  {/* Packet 2 – violet, ~1/3 behind */}
                  <line
                    x1={`${from.x}%`} y1={`${from.y}%`}
                    x2={`${to.x}%`}   y2={`${to.y}%`}
                    stroke="#A78BFA"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeDasharray="10 220"
                    opacity="0.85"
                    filter="url(#glow-strong)"
                    style={{ animation: `data-packet ${duration}s linear infinite`, animationDelay: `${phase(130) - Math.round(duration * 333)}ms` }}
                  />
                  {/* Packet 3 – cyan, ~2/3 behind */}
                  <line
                    x1={`${from.x}%`} y1={`${from.y}%`}
                    x2={`${to.x}%`}   y2={`${to.y}%`}
                    stroke="#00daf3"
                    strokeWidth="1.5"
                    strokeLinecap="round"
                    strokeDasharray="7 220"
                    opacity="0.7"
                    filter="url(#glow-strong)"
                    style={{ animation: `data-packet ${duration}s linear infinite`, animationDelay: `${phase(130) - Math.round(duration * 666)}ms` }}
                  />
                  {/* Packet 4 – white micro dot, fills the gaps */}
                  <line
                    x1={`${from.x}%`} y1={`${from.y}%`}
                    x2={`${to.x}%`}   y2={`${to.y}%`}
                    stroke="#ffffff"
                    strokeWidth="1"
                    strokeLinecap="round"
                    strokeDasharray="4 220"
                    opacity="0.5"
                    filter="url(#glow-subtle)"
                    style={{ animation: `data-packet ${duration * 0.8}s linear infinite`, animationDelay: `${phase(80) - Math.round(duration * 500)}ms` }}
                  />
                </g>
              );
            }

            // ── Secondary / dashed edge (group→signal, cross-group) ──────────
            const dimDuration   = 1.2 + (i % 4) * 0.2;
            const dimPhase      = -(i * 60 % Math.round(dimDuration * 1000));
            return (
              <g key={i}>
                {/* Static dashed connector */}
                <line
                  x1={`${from.x}%`} y1={`${from.y}%`}
                  x2={`${to.x}%`}   y2={`${to.y}%`}
                  stroke="rgba(167,139,250,0.35)"
                  strokeWidth="1"
                  strokeDasharray="3 8"
                  opacity={edge.opacity ?? 0.6}
                />
                {/* Traveling dot 1 */}
                <line
                  x1={`${from.x}%`} y1={`${from.y}%`}
                  x2={`${to.x}%`}   y2={`${to.y}%`}
                  stroke="#A78BFA"
                  strokeWidth="2"
                  strokeLinecap="round"
                  strokeDasharray="6 156"
                  opacity="0.9"
                  filter="url(#glow-subtle)"
                  style={{ animation: `data-packet-dim ${dimDuration}s linear infinite`, animationDelay: `${dimPhase}ms` }}
                />
                {/* Traveling dot 2 – offset by half cycle */}
                <line
                  x1={`${from.x}%`} y1={`${from.y}%`}
                  x2={`${to.x}%`}   y2={`${to.y}%`}
                  stroke="#ffffff"
                  strokeWidth="1.5"
                  strokeLinecap="round"
                  strokeDasharray="4 156"
                  opacity="0.6"
                  filter="url(#glow-subtle)"
                  style={{ animation: `data-packet-dim ${dimDuration}s linear infinite`, animationDelay: `${dimPhase - Math.round(dimDuration * 500)}ms` }}
                />
              </g>
            );
          })}
        </svg>

        {/* Nodes */}
        {!loading && nodes.map((node) => {
          if (node.size === "core") return <CoreNode key={node.id} node={node} />;
          if (node.size === "group") return <GroupNode key={node.id} node={node} />;
          return <SignalNode key={node.id} node={node} />;
        })}

        {/* Signal Count Watermark */}
        {!loading && totalSignals > 0 && (
          <div
            className="absolute bottom-6 left-1/2 -translate-x-1/2 pointer-events-none z-0"
            style={{ opacity: 0.07 }}
          >
            <p className="font-mono-data text-violet-300 text-[64px] font-bold tracking-tight select-none">
              {totalSignals.toLocaleString()}
            </p>
          </div>
        )}
      </div>

      {/* Loading Overlay (outside pan transform) */}
      {loading && (
        <div className="absolute inset-0 flex items-center justify-center pointer-events-none z-20">
          <div className="text-center">
            <span className="material-symbols-outlined text-violet-400 text-4xl animate-spin block mb-2">
              autorenew
            </span>
            <p className="text-[10px] font-mono-data text-zinc-600 uppercase tracking-widest">
              Building knowledge graph...
            </p>
          </div>
        </div>
      )}

      {/* Drag hint (shown once when loaded) */}
      {!loading && pan.x === 0 && pan.y === 0 && (
        <div className="absolute bottom-[140px] left-1/2 -translate-x-1/2 pointer-events-none z-10 opacity-30">
          <p className="text-[8px] font-mono-data text-zinc-500 uppercase tracking-widest flex items-center gap-1">
            <span className="material-symbols-outlined text-[11px]">drag_pan</span>
            drag to pan graph
          </p>
        </div>
      )}
    </div>
  );
}
