import { useCallback } from 'react';

/**
 * 트리 확산 애니메이션용 위치 계산 + 타이밍 (mockup calcFlowPositions 포팅)
 *
 * 카드 우측에서 depth별로 트리 형태 배치
 * depth별 시간 지연으로 선 → 노드 순차 등장
 */

interface FlowEdge {
  from: string;
  to: string;
  type: string;
  label: string;
}

/**
 * BFS로 카드에서 도달 가능한 전체 체인 계산
 * ★ 양방향 탐색: outgoing (from===cur) + incoming (to===cur)
 * → inbound 관계도 놓치지 않음
 */
export function buildFlowChain(
  rootKey: string,
  allEdges: FlowEdge[]
): { edges: FlowEdge[]; depths: Record<string, number> } {
  const reachable = new Set([rootKey]);
  const queue = [rootKey];

  while (queue.length) {
    const cur = queue.shift()!;
    // ★ outgoing: from === cur
    allEdges
      .filter((e) => e.from === cur)
      .forEach((e) => {
        if (!reachable.has(e.to)) {
          reachable.add(e.to);
          queue.push(e.to);
        }
      });
    // ★ incoming: to === cur (양방향 탐색)
    allEdges
      .filter((e) => e.to === cur)
      .forEach((e) => {
        if (!reachable.has(e.from)) {
          reachable.add(e.from);
          queue.push(e.from);
        }
      });
  }

  const edges = allEdges.filter((e) => reachable.has(e.from) && reachable.has(e.to));

  // depth 계산 (양방향)
  const depths: Record<string, number> = { [rootKey]: 0 };
  const q2 = [rootKey];
  while (q2.length) {
    const cur = q2.shift()!;
    // outgoing
    edges
      .filter((e) => e.from === cur)
      .forEach((e) => {
        if (depths[e.to] === undefined) {
          depths[e.to] = depths[cur] + 1;
          q2.push(e.to);
        }
      });
    // incoming
    edges
      .filter((e) => e.to === cur)
      .forEach((e) => {
        if (depths[e.from] === undefined) {
          depths[e.from] = depths[cur] + 1;
          q2.push(e.from);
        }
      });
  }

  return { edges, depths };
}

/**
 * 카드 우측에 테이블 노드를 트리 형태로 배치
 */
export function calcFlowPositions(
  cardRight: number,
  cardCenterY: number,
  canvasHeight: number,
  depths: Record<string, number>
): Record<string, { x: number; y: number }> {
  const startX = cardRight + 80;

  // depth별 노드 그룹핑 (CARD: 제외)
  const depthNodes: Record<number, string[]> = {};
  Object.entries(depths).forEach(([name, d]) => {
    if (name.startsWith('CARD:')) return;
    if (!depthNodes[d]) depthNodes[d] = [];
    depthNodes[d].push(name);
  });

  const maxD = Math.max(1, ...Object.keys(depthNodes).map(Number));
  const colGap = Math.max(270, Math.min(350, (1200 - startX - 230) / maxD));
  const rowGap = 240;

  const pos: Record<string, { x: number; y: number }> = {};
  Object.entries(depthNodes).forEach(([dStr, nodes]) => {
    const di = parseInt(dStr);
    const totalH = nodes.length * rowGap;
    const startY = Math.max(20, (canvasHeight - totalH) / 2);
    nodes.forEach((name, i) => {
      pos[name] = {
        x: startX + (di - 1) * colGap,
        y: startY + i * rowGap,
      };
    });
  });

  return pos;
}

/**
 * depth별 애니메이션 타이밍 계산
 * 선 → 노드 순서로 연쇄 등장
 */
export function calcAnimationTimings(
  edges: FlowEdge[],
  depths: Record<string, number>
): { edge: FlowEdge; lineDelay: number; nodeDelay: number }[] {
  const STEP = 500;
  const NODE_D = 350;

  // 엣지를 depth별 그룹핑
  const depthEdges: Record<number, FlowEdge[]> = {};
  edges.forEach((edge) => {
    const fd = depths[edge.from] ?? 0;
    const d = fd + 1;
    if (!depthEdges[d]) depthEdges[d] = [];
    depthEdges[d].push(edge);
  });

  const result: { edge: FlowEdge; lineDelay: number; nodeDelay: number }[] = [];
  const maxDepth = Math.max(0, ...Object.keys(depthEdges).map(Number));

  for (let d = 1; d <= maxDepth; d++) {
    const edgesAtDepth = depthEdges[d] || [];
    const base = 300 + (d - 1) * STEP;
    edgesAtDepth.forEach((edge, i) => {
      result.push({
        edge,
        lineDelay: base + i * 120,
        nodeDelay: base + i * 120 + NODE_D,
      });
    });
  }

  return result;
}

/**
 * useFlowAnimation — 흐름 표시 관리 훅
 */
export function useFlowAnimation() {
  const showFlow = useCallback(
    (
      cardId: string,
      sourceTable: string,
      relations: Record<string, any>[],
      cardRect: { right: number; centerY: number },
      canvasHeight: number
    ) => {
      // 1. 엣지 구성: 카드 → 소스 테이블 + relations
      const rootKey = `CARD:${cardId}`;
      const allEdges: FlowEdge[] = [
        { from: rootKey, to: sourceTable, type: 'source', label: '데이터 소스' },
      ];

      relations.forEach((rel) => {
        const type = rel.relation_type ?? rel.RELATION_TYPE ?? 'auto';
        const label = rel.label ?? rel.LABEL ?? `${rel.source_table ?? rel.SOURCE_TABLE} → ${rel.target_table ?? rel.TARGET_TABLE}`;
        const from = rel.source_table ?? rel.SOURCE_TABLE;
        const to = rel.target_table ?? rel.TARGET_TABLE;
        if (from && to) {
          allEdges.push({ from, to, type, label });
        }
      });

      // 2. BFS 체인 + depth 계산
      const { edges, depths } = buildFlowChain(rootKey, allEdges);

      // 3. 위치 계산
      const positions = calcFlowPositions(
        cardRect.right,
        cardRect.centerY,
        canvasHeight,
        depths
      );

      // 4. 애니메이션 타이밍
      const timings = calcAnimationTimings(edges, depths);

      return { edges, depths, positions, timings };
    },
    []
  );

  return { showFlow };
}
