import { useMemo, useRef, useState, useEffect } from 'react';
import { sankey, sankeyLinkHorizontal, sankeyLeft } from 'd3-sankey';

const INK = '#0A0A0A';
const PAPER = '#F4F1EA';
const SIGNAL = '#FF4D1F';
const STAMP = '#FFD93D';
const STATE = '#1A3D2E';
const VOID = '#E5E1D8';

export interface SankeyNodeIn {
  id: string;
  label: string;
  level: 0 | 1 | 2;
  meta?: { code?: string; raw?: string };
}
export interface SankeyLinkIn {
  source: string;
  target: string;
  value: number;
}

interface Props {
  nodes: SankeyNodeIn[];
  links: SankeyLinkIn[];
  height?: number;
}

interface InternalNode extends SankeyNodeIn {
  index: number;
  x0: number; x1: number; y0: number; y1: number;
  value: number;
  sourceLinks: any[];
  targetLinks: any[];
}

function fmtRon(v: number): string {
  if (v >= 1_000_000_000) return `${(v / 1_000_000_000).toFixed(1)} mld`;
  if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)} mil`;
  if (v >= 1_000) return `${(v / 1_000).toFixed(0)}K`;
  return v.toFixed(0);
}

export function Sankey({ nodes, links, height = 720 }: Props) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [width, setWidth] = useState(1200);
  const [hoverNode, setHoverNode] = useState<string | null>(null);
  const [hoverLink, setHoverLink] = useState<number | null>(null);
  const [tooltip, setTooltip] = useState<{ x: number; y: number; html: { title: string; rows: Array<[string, string]> } } | null>(null);
  const [flashed, setFlashed] = useState(false);

  useEffect(() => {
    if (!containerRef.current) return;
    const ro = new ResizeObserver((entries) => {
      for (const e of entries) setWidth(Math.max(640, e.contentRect.width));
    });
    ro.observe(containerRef.current);
    setWidth(containerRef.current.clientWidth);
    return () => ro.disconnect();
  }, []);

  // Flash stamp on first mount
  useEffect(() => {
    setFlashed(true);
    const t = setTimeout(() => setFlashed(false), 600);
    return () => clearTimeout(t);
  }, []);

  const layout = useMemo(() => {
    if (nodes.length === 0 || links.length === 0) return null;
    const idIndex = new Map(nodes.map((n, i) => [n.id, i]));
    const sankeyData = {
      nodes: nodes.map(n => ({ ...n })),
      links: links
        .filter(l => idIndex.has(l.source) && idIndex.has(l.target))
        .map(l => ({ source: idIndex.get(l.source)!, target: idIndex.get(l.target)!, value: l.value })),
    };

    const padding = { top: 20, right: 240, bottom: 20, left: 100 };
    const innerW = width - padding.left - padding.right;
    const innerH = height - padding.top - padding.bottom;

    const sk = sankey<any, any>()
      .nodeId((d: any) => d.index ?? d.id)
      .nodeAlign(sankeyLeft)
      .nodeWidth(18)
      .nodePadding(8)
      .extent([[padding.left, padding.top], [padding.left + innerW, padding.top + innerH]]);

    // attach indexes
    sankeyData.nodes.forEach((n: any, i) => { n.index = i; });
    const result = sk({
      nodes: sankeyData.nodes as any,
      links: sankeyData.links as any,
    });

    return result as { nodes: InternalNode[]; links: any[] };
  }, [nodes, links, width, height]);

  if (!layout) {
    return (
      <div className="w-full bg-paper border-2 border-ink p-12 text-center">
        <div className="font-mono text-xs uppercase tracking-meta text-ink/60">
          Nu există date suficiente pentru fluxul de bani.
        </div>
      </div>
    );
  }

  const linkPath = sankeyLinkHorizontal();

  function nodeFill(level: number, isHovered: boolean): string {
    if (isHovered) return STAMP;
    return INK;
  }

  function linkColor(level: number, isHovered: boolean): string {
    if (isHovered) return STAMP;
    if (level === 0) return SIGNAL;
    return STATE;
  }

  function handleNodeHover(node: InternalNode | null, e?: React.MouseEvent) {
    setHoverNode(node ? node.id : null);
    if (node && e) {
      const rect = containerRef.current?.getBoundingClientRect();
      const left = (rect?.left ?? 0);
      const top = (rect?.top ?? 0);
      setTooltip({
        x: e.clientX - left + 12,
        y: e.clientY - top + 12,
        html: {
          title: node.label.toUpperCase(),
          rows: [
            ['VALOARE', `${fmtRon(node.value)} RON`],
            ['NIVEL', node.level === 0 ? 'JUDEȚ' : node.level === 1 ? 'TIP AUTORITATE' : 'FURNIZOR'],
            ...(node.level === 2 && node.meta?.code ? [['CUI', node.meta.code]] as Array<[string, string]> : []),
          ],
        },
      });
    } else {
      setTooltip(null);
    }
  }

  function handleNodeClick(node: InternalNode) {
    if (node.level === 0 && node.meta?.code && node.meta.code !== 'AL') {
      window.location.href = `/judet/${node.meta.code}`;
    } else if (node.level === 2 && node.meta?.code) {
      window.location.href = `/firma/${node.meta.code}`;
    }
  }

  // For hover highlight: collect connected links/nodes
  const connectedLinks = new Set<number>();
  const connectedNodes = new Set<string>();
  if (hoverNode) {
    layout.links.forEach((l: any, i: number) => {
      if (l.source.id === hoverNode || l.target.id === hoverNode) {
        connectedLinks.add(i);
        connectedNodes.add(l.source.id);
        connectedNodes.add(l.target.id);
      }
    });
  }

  return (
    <div ref={containerRef} className="relative w-full bg-paper border-2 border-ink overflow-hidden" style={{ height }}>
      {/* Header strip */}
      <div className="absolute top-0 left-0 right-0 z-10 border-b-2 border-ink bg-paper px-4 py-2 flex items-center justify-between">
        <div className="font-mono text-[10px] uppercase tracking-meta text-ink/70">
          FLUX BANI · JUDEȚ → TIP AUTORITATE → FIRMĂ
        </div>
        <div className="font-mono text-[10px] uppercase tracking-meta text-ink/50">
          {nodes.length} noduri · {links.length} legături
        </div>
      </div>

      <svg width={width} height={height} className="block" style={{ marginTop: 0 }}>
        {/* Links */}
        <g fill="none">
          {layout.links.map((l: any, i: number) => {
            const isHovered = hoverLink === i || (hoverNode != null && connectedLinks.has(i));
            const dimmed = (hoverNode != null && !connectedLinks.has(i)) || (hoverLink != null && hoverLink !== i);
            return (
              <path
                key={i}
                d={linkPath(l) || ''}
                stroke={linkColor(l.source.level, isHovered)}
                strokeOpacity={dimmed ? 0.12 : isHovered ? 0.85 : 0.42}
                strokeWidth={Math.max(1, l.width)}
                onMouseEnter={(e) => {
                  setHoverLink(i);
                  const rect = containerRef.current?.getBoundingClientRect();
                  const left = rect?.left ?? 0; const top = rect?.top ?? 0;
                  setTooltip({
                    x: e.clientX - left + 12,
                    y: e.clientY - top + 12,
                    html: {
                      title: 'FLUX',
                      rows: [
                        ['DE LA', l.source.label.toUpperCase()],
                        ['CĂTRE', l.target.label.toUpperCase()],
                        ['VALOARE', `${fmtRon(l.value)} RON`],
                      ],
                    },
                  });
                }}
                onMouseMove={(e) => {
                  const rect = containerRef.current?.getBoundingClientRect();
                  setTooltip(t => t ? { ...t, x: e.clientX - (rect?.left ?? 0) + 12, y: e.clientY - (rect?.top ?? 0) + 12 } : t);
                }}
                onMouseLeave={() => { setHoverLink(null); setTooltip(null); }}
                style={{ cursor: 'crosshair' }}
              />
            );
          })}
        </g>

        {/* Nodes */}
        <g>
          {layout.nodes.map((n: InternalNode) => {
            const isHovered = hoverNode === n.id;
            const isConnected = connectedNodes.has(n.id);
            const dimmed = hoverNode != null && !isHovered && !isConnected;
            const w = n.x1 - n.x0;
            const h = Math.max(2, n.y1 - n.y0);
            const navigable = (n.level === 0 && n.meta?.code && n.meta.code !== 'AL') || (n.level === 2 && n.meta?.code);
            return (
              <g
                key={n.id}
                onMouseEnter={(e) => handleNodeHover(n, e)}
                onMouseMove={(e) => handleNodeHover(n, e)}
                onMouseLeave={() => handleNodeHover(null)}
                onClick={() => handleNodeClick(n)}
                style={{ cursor: navigable ? 'pointer' : 'default', opacity: dimmed ? 0.35 : 1 }}
              >
                <rect
                  x={n.x0}
                  y={n.y0}
                  width={w}
                  height={h}
                  fill={flashed ? STAMP : nodeFill(n.level, isHovered)}
                  stroke={INK}
                  strokeWidth={2}
                />
                {/* Label */}
                {h >= 8 && (
                  <text
                    x={n.level === 2 ? n.x1 + 6 : n.x0 - 6}
                    y={(n.y0 + n.y1) / 2}
                    dy="0.32em"
                    textAnchor={n.level === 2 ? 'start' : 'end'}
                    fontFamily='"JetBrains Mono", monospace'
                    fontSize={10}
                    fontWeight={600}
                    fill={INK}
                    style={{ textTransform: 'uppercase', letterSpacing: '0.08em', pointerEvents: 'none' }}
                  >
                    {n.label.length > 28 ? n.label.slice(0, 27) + '…' : n.label}
                  </text>
                )}
                {/* value (only for level 2 if wide enough) */}
                {h >= 14 && n.level === 2 && (
                  <text
                    x={n.x1 + 6}
                    y={(n.y0 + n.y1) / 2 + 11}
                    fontFamily='"JetBrains Mono", monospace'
                    fontSize={9}
                    fill={INK}
                    fillOpacity={0.55}
                    style={{ pointerEvents: 'none' }}
                  >
                    {fmtRon(n.value)} RON
                  </text>
                )}
              </g>
            );
          })}
        </g>
      </svg>

      {/* Tooltip */}
      {tooltip && (
        <div
          className="pointer-events-none absolute z-20 bg-paper border-2 border-ink p-3 font-mono text-[11px] tabular-nums"
          style={{ left: tooltip.x, top: tooltip.y, minWidth: 200 }}
        >
          <div className="font-display font-bold text-sm text-ink mb-1.5 uppercase tracking-tight">
            {tooltip.html.title}
          </div>
          <div className="space-y-1">
            {tooltip.html.rows.map(([k, v], i) => (
              <div key={i} className="flex justify-between gap-3">
                <span className="text-ink/60 uppercase tracking-meta">{k}</span>
                <span className="text-ink font-bold">{v}</span>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}
