import { useRef, useCallback, useEffect } from 'react';
import { useControlMode, genConnId } from './useControlMode';
import { bezierPath } from '../ConnectionLine';

/**
 * 포트 연결 드래그 로직 (mockup startPortDrag/finishPortDrag 포팅)
 * output 포트 mousedown → 임시 선 → input 포트 mouseup → 연결 생성
 */
export function usePortDrag(canvasRef: React.RefObject<HTMLDivElement | null>) {
  const { addRuleConnection, ruleConnections } = useControlMode();

  const dragRef = useRef<{
    fromNodeId: string;
    fromPort: string;
    line: SVGPathElement;
    x1: number;
    y1: number;
  } | null>(null);

  const startDrag = useCallback((nodeId: string, port: string, e: React.MouseEvent) => {
    const cv = canvasRef.current;
    if (!cv) return;

    // SVG 확보
    let svg = cv.querySelector('#rule-svg') as SVGSVGElement | null;
    if (!svg) {
      svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      svg.id = 'rule-svg';
      svg.classList.add('ctrl-svg');
      svg.setAttribute('width', '100%');
      svg.setAttribute('height', '100%');
      svg.style.overflow = 'visible';
      cv.appendChild(svg);
    }

    const cr = cv.getBoundingClientRect();
    const portEl = (e.target as HTMLElement).closest('.ctrl-io-port') as HTMLElement;
    if (!portEl) return;
    const pr = portEl.getBoundingClientRect();
    const x1 = pr.left + pr.width / 2 - cr.left + cv.scrollLeft;
    const y1 = pr.top + pr.height / 2 - cr.top + cv.scrollTop;

    const line = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    line.classList.add('rule-temp-line');
    line.setAttribute('d', `M${x1},${y1} L${x1},${y1}`);
    svg.appendChild(line);

    dragRef.current = { fromNodeId: nodeId, fromPort: port, line, x1, y1 };
    cv.classList.add('port-dragging');
    portEl.classList.add('port-active');
  }, [canvasRef]);

  const finishDrag = useCallback((toNodeId: string, toPort: string) => {
    const d = dragRef.current;
    if (!d) return;

    // 같은 노드 연결 방지
    if (d.fromNodeId === toNodeId) {
      cleanup();
      return;
    }
    // ★ [HIGH] port direction validation — output → output 역방향 엣지 차단
    //   from_port 는 in/out/yes/no/pass/fail/approved/rejected 등 (output port 만 허용)
    //   to_port 는 in 만 허용 (input port 도착점)
    //   단 테이블 port 는 양방향 (in/out 둘 다 가능, PortHandle 단일 dot 양방향화)
    //   → 노드 type 으로 분기
    const stateForValidate = useControlMode.getState();
    const fromNodeForVal = stateForValidate.ruleNodes.find((n) => n.id === d.fromNodeId);
    const toNodeForVal   = stateForValidate.ruleNodes.find((n) => n.id === toNodeId);
    // 도착이 action 노드면 to_port 는 'in' 이어야 함 (action 노드는 좌측 in 만 mouseup 받음)
    if (toNodeForVal && toNodeForVal.type !== 'table' && toPort !== 'in') {
      cleanup();
      return;
    }
    // 출발이 action 노드면 from_port 는 in 이 아니어야 함 (action 노드의 in 에서 시작은 의미 없음)
    if (fromNodeForVal && fromNodeForVal.type !== 'table' && d.fromPort === 'in') {
      cleanup();
      return;
    }
    // 중복 방지 — getState() 로 최신 ruleConnections 사용 (render-captured stale 회피)
    const currentConns = stateForValidate.ruleConnections;
    if (currentConns.find((c) =>
      c.from_node_id === d.fromNodeId && c.from_port === d.fromPort && c.to_node_id === toNodeId
    )) {
      cleanup();
      return;
    }

    // Phase 3: edge_type 자동 추론 (위 validation 에서 가져온 노드 재사용)
    //   table → table         = lookup (FK 참조)
    //   table → action        = data-context (테이블 데이터를 노드 입력으로)
    //   action → table        = table-mutation (노드 결과를 테이블에 저장/수정)
    //   action → action       = execution-flow (실행 순서)
    const fromIsTable = fromNodeForVal?.type === 'table';
    const toIsTable   = toNodeForVal?.type === 'table';
    let edgeType: 'data-context' | 'execution-flow' | 'table-mutation' | 'lookup';
    if (fromIsTable && toIsTable)      edgeType = 'lookup';
    else if (fromIsTable && !toIsTable) edgeType = 'data-context';
    else if (!fromIsTable && toIsTable) edgeType = 'table-mutation';
    else                                edgeType = 'execution-flow';

    addRuleConnection({
      id: genConnId(),
      from_node_id: d.fromNodeId,
      from_port: d.fromPort,
      to_node_id: toNodeId,
      to_port: toPort,
      edge_type: edgeType,
    });

    cleanup();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [addRuleConnection]);

  const cleanup = useCallback(() => {
    const d = dragRef.current;
    if (!d) return;
    d.line.remove();
    canvasRef.current?.classList.remove('port-dragging');
    document.querySelectorAll('.port-active').forEach((el) => el.classList.remove('port-active'));
    document.querySelectorAll('.port-hover').forEach((el) => el.classList.remove('port-hover'));
    dragRef.current = null;
  }, [canvasRef]);

  // 마우스 이동/종료 전역 핸들러
  // ★ mouseup 시 e.target 의 closest .ctrl-io-port 를 직접 찾아서 finishDrag 호출
  //    (PortHandle 의 onMouseUp 에 의존하면 race + 6px hit-target 문제로 연결 실패)
  useEffect(() => {
    const onMove = (e: MouseEvent) => {
      const d = dragRef.current;
      if (!d) return;
      const cv = canvasRef.current;
      if (!cv) return;
      const cr = cv.getBoundingClientRect();
      const x2 = e.clientX - cr.left + cv.scrollLeft;
      const y2 = e.clientY - cr.top + cv.scrollTop;
      d.line.setAttribute('d', bezierPath(d.x1, d.y1, x2, y2));

      // 호버 중인 port 강조
      document.querySelectorAll('.ctrl-io-port.port-hover').forEach((el) => el.classList.remove('port-hover'));
      const hoverPort = (e.target as HTMLElement)?.closest?.('.ctrl-io-port') as HTMLElement | null;
      if (hoverPort && hoverPort.dataset.node !== d.fromNodeId) {
        hoverPort.classList.add('port-hover');
      }
    };

    const onUp = (e: MouseEvent) => {
      if (!dragRef.current) return;
      // ① e.target 의 closest 로 port 찾기 (정확히 port 위에서 mouseup 한 경우)
      let portEl = (e.target as HTMLElement | null)?.closest?.('.ctrl-io-port') as HTMLElement | null;
      // ② 못 찾으면 마우스 좌표 주변 20px 내 가장 가까운 port 검색 (port 근처에서 mouseup)
      if (!portEl) {
        const candidates = document.querySelectorAll<HTMLElement>('.ctrl-io-port');
        let best: { el: HTMLElement; dist: number } | null = null;
        candidates.forEach((el) => {
          const r = el.getBoundingClientRect();
          const cx = r.left + r.width / 2, cy = r.top + r.height / 2;
          const dx = e.clientX - cx, dy = e.clientY - cy;
          const dist = Math.sqrt(dx * dx + dy * dy);
          if (dist < 24 && (!best || dist < best.dist)) {
            best = { el, dist };
          }
        });
        if (best) portEl = (best as { el: HTMLElement; dist: number }).el;
      }
      if (portEl) {
        const toNodeId = portEl.dataset.node;
        const toPort = portEl.dataset.port;
        if (toNodeId && toPort) {
          finishDrag(toNodeId, toPort);
          return;
        }
      }
      cleanup();
    };

    document.addEventListener('mousemove', onMove);
    document.addEventListener('mouseup', onUp);
    return () => {
      document.removeEventListener('mousemove', onMove);
      document.removeEventListener('mouseup', onUp);
    };
  }, [canvasRef, cleanup, finishDrag]);

  return { startDrag, finishDrag };
}
