'use client';

import { useState, useEffect, useRef, useCallback } from 'react';
import { useControlMode, CTRL_NODE_TYPES } from './hooks/useControlMode';
import { useFlowAnimation } from './hooks/useFlowAnimation';
import { getMetaFields, getMetaRelations } from '@/lib/api/meta';
import { getBusinessRuleList, getBusinessRuleInfo } from '@/lib/api/businessRule';
import { TableNode } from './TableNode';
import { ControlNode } from './ControlNode';
import { ConnectionSvg, FlowLine, FlowBadge, bezierPath } from './ConnectionLine';
import type { FieldConfig } from '@/types/invyone-component';

interface FlowViewerProps {
  cards: Record<string, any>[];
  canvasRef: React.RefObject<HTMLDivElement | null>;
  dashboardId: string;
}

/** 저장된 룰 그래프 (노드+연결선, 별도 오버레이) */
interface RuleOverlay {
  ruleName: string;
  nodes: Record<string, any>[];
  connections: Record<string, any>[];
}

/**
 * 룰 노드의 포트 위치 계산 (RuleBuilder.portPos와 동일 로직)
 * - table 노드: width 200, 포트 in=좌측, out=우측 (y+18)
 * - control 노드: width 160, in=좌측 (y+40), out=우측 (다중 포트 분배)
 */
function computePortPos(node: Record<string, any>, port: string): { x: number; y: number } | null {
  if (!node) return null;
  const nx = node.x ?? 0;
  const ny = node.y ?? 0;

  if (node.type === 'table') {
    if (port === 'in') return { x: nx, y: ny + 18 };
    return { x: nx + 200, y: ny + 18 };
  }

  // 제어 노드
  if (port === 'in') return { x: nx, y: ny + 40 };

  // output 포트 — 타입별 위치
  const def = (CTRL_NODE_TYPES as Record<string, any>)[node.type];
  const outPorts = def?.out || [{ port: 'out', label: '→', cls: '' }];
  const idx = outPorts.findIndex((p: Record<string, any>) => p.port === port);
  const total = outPorts.length;
  const nodeH = 80;
  const centerY = ny + nodeH / 2;
  const gap = 8;
  const startY = centerY - ((total - 1) * gap) / 2;

  return { x: nx + 160, y: startY + (idx >= 0 ? idx : 0) * gap };
}

/** 테이블 메타 캐시 */
const metaCache: Record<string, { label: string; icon: string; columns: FieldConfig[] }> = {};

async function loadTableMeta(tableName: string) {
  if (metaCache[tableName]) return metaCache[tableName];
  try {
    const meta = await getMetaFields(tableName);
    const result = {
      label: meta.table_label ?? tableName,
      icon: '🏢',
      columns: (meta.fields ?? []).filter((f: FieldConfig) => !f.system).slice(0, 8),
    };
    metaCache[tableName] = result;
    return result;
  } catch {
    return { label: tableName, icon: '🏢', columns: [] };
  }
}

export function FlowViewer({ cards, canvasRef, dashboardId }: FlowViewerProps) {
  const {
    activeFlowCardId,
    flowEdges,
    tablePositions,
    setActiveFlowCard,
    setSelectedCardId,
    setFlowEdges,
    setTablePositions,
  } = useControlMode();

  const { showFlow } = useFlowAnimation();
  const [tableMetas, setTableMetas] = useState<Record<string, { label: string; icon: string; columns: FieldConfig[] }>>({});
  const [animTimings, setAnimTimings] = useState<{ edge: Record<string, any>; lineDelay: number; nodeDelay: number }[]>([]);
  const [revealedNodes, setRevealedNodes] = useState<Set<string>>(new Set());
  const [ruleOverlays, setRuleOverlays] = useState<RuleOverlay[]>([]);
  const animRef = useRef<ReturnType<typeof setTimeout>[]>([]);

  // 카드 클릭 → 흐름 표시 + 카드 선택 (selectedCardId 동기화)
  const handleCardClick = useCallback(async (cardId: string) => {
    // 같은 카드 클릭 → 닫기
    if (activeFlowCardId === cardId) {
      clearFlow();
      setSelectedCardId(null);
      return;
    }

    setSelectedCardId(cardId);

    const card = cards.find((c) => (c.card_id ?? c.CARD_ID) === cardId);
    if (!card) return;

    const sourceTable = card.primary_table ?? card.PRIMARY_TABLE;
    if (!sourceTable) return;

    // 카드 위치 계산
    const cv = canvasRef.current;
    if (!cv) return;
    const cardEl = cv.querySelector(`[data-card-id="${cardId}"]`) as HTMLElement;
    if (!cardEl) return;

    const cardRight = cardEl.offsetLeft + cardEl.offsetWidth;
    const cardCenterY = cardEl.offsetTop + cardEl.offsetHeight / 2;
    const canvasHeight = cv.clientHeight;

    // ★ 2소스 분리 조회: table_relationships (구조) + business_rules (자동화)
    let relations: Record<string, any>[] = [];
    try { relations = await getMetaRelations(sourceTable); } catch { /* 빈 배열 사용 */ }

    // ★ 현재 대시보드의 활성 비즈니스 룰 조회 → 별도 오버레이 (BFS에 합치지 않음)
    // ★ 단, sourceTable과 관련된 룰만 표시 (해당 테이블 노드를 포함하는 룰)
    const overlays: RuleOverlay[] = [];
    try {
      const rulesRes = await getBusinessRuleList(dashboardId);
      const ruleList = (rulesRes?.list ?? rulesRes?.data ?? [])
        .filter((r: Record<string, any>) => r.is_enabled === true || r.IS_ENABLED === true);
      for (const rule of ruleList) {
        const ruleId = rule.rule_id ?? rule.RULE_ID;
        if (!ruleId) continue;
        const ruleDetail = await getBusinessRuleInfo(ruleId);
        if (!ruleDetail) continue;
        const nodes: Record<string, any>[] = ruleDetail.nodes ?? [];
        // ★ 룰이 sourceTable을 포함하는지 확인 (table 타입 노드의 table_name 매칭)
        const involvesSourceTable = nodes.some((n) =>
          n.type === 'table' && (n.table_name === sourceTable || n.tableName === sourceTable)
        );
        if (!involvesSourceTable) continue;
        overlays.push({
          ruleName: rule.name ?? rule.NAME ?? ruleId,
          nodes,
          connections: ruleDetail.connections ?? [],
        });
      }
    } catch { /* 룰 조회 실패 시 관계만 표시 */ }
    setRuleOverlays(overlays);

    // 흐름 계산 (★ table_relationships만 — 룰은 별도 오버레이)
    const result = showFlow(cardId, sourceTable, relations, { right: cardRight, centerY: cardCenterY }, canvasHeight);

    // 테이블 메타 로드
    const tableNames = new Set<string>();
    result.edges.forEach((e) => {
      if (!e.to.startsWith('CARD:')) tableNames.add(e.to);
      if (!e.from.startsWith('CARD:')) tableNames.add(e.from);
    });

    const metas: Record<string, { label: string; icon: string; columns: FieldConfig[] }> = {};
    await Promise.all(
      Array.from(tableNames).map(async (name) => {
        metas[name] = await loadTableMeta(name);
      })
    );
    setTableMetas(metas);

    // 상태 업데이트
    setActiveFlowCard(cardId);
    setFlowEdges(result.edges);
    setTablePositions(result.positions);
    setAnimTimings(result.timings);

    // 애니메이션: 순차 reveal
    const revealed = new Set<string>();
    setRevealedNodes(new Set());

    animRef.current.forEach(clearTimeout);
    animRef.current = [];

    result.timings.forEach(({ edge, nodeDelay }) => {
      const t = setTimeout(() => {
        if (!edge.to.startsWith('CARD:') && !revealed.has(edge.to)) {
          revealed.add(edge.to);
          setRevealedNodes(new Set(revealed));
        }
      }, nodeDelay);
      animRef.current.push(t);
    });
  }, [activeFlowCardId, cards, canvasRef, setActiveFlowCard, setFlowEdges, setTablePositions, showFlow]);

  // 클릭 이벤트 위임
  useEffect(() => {
    const cv = canvasRef.current;
    if (!cv) return;

    const handler = (e: MouseEvent) => {
      const cardEl = (e.target as HTMLElement).closest('[data-card-id]') as HTMLElement;
      if (cardEl) {
        const id = cardEl.dataset.cardId;
        if (id) handleCardClick(id);
        return;
      }
      // 빈 영역 클릭 → 흐름 닫기
      if ((e.target as HTMLElement).closest('.tbl-node') ||
          (e.target as HTMLElement).closest('.ctrl-badge')) return;
      if (activeFlowCardId) clearFlow();
    };

    cv.addEventListener('click', handler);
    return () => cv.removeEventListener('click', handler);
  }, [canvasRef, handleCardClick, activeFlowCardId]);

  const clearFlow = useCallback(() => {
    animRef.current.forEach(clearTimeout);
    animRef.current = [];
    setActiveFlowCard(null);
    setFlowEdges([]);
    setTablePositions({});
    setAnimTimings([]);
    setRevealedNodes(new Set());
    setTableMetas({});
    setRuleOverlays([]);
  }, [setActiveFlowCard, setFlowEdges, setTablePositions]);

  // 테이블 노드 드래그 → 위치 업데이트 + 선 재그리기
  const handleNodeMove = useCallback((name: string, x: number, y: number) => {
    setTablePositions({ ...tablePositions, [name]: { x, y } });
  }, [tablePositions, setTablePositions]);

  if (!activeFlowCardId || flowEdges.length === 0) return null;

  // 카드 위치 가져오기
  const getCardPos = (cardId: string) => {
    const cv = canvasRef.current;
    if (!cv) return { right: 0, centerY: 0 };
    const el = cv.querySelector(`[data-card-id="${cardId}"]`) as HTMLElement;
    if (!el) return { right: 0, centerY: 0 };
    return { right: el.offsetLeft + el.offsetWidth, centerY: el.offsetTop + el.offsetHeight / 2 };
  };

  // 좌표 계산
  const getFromPos = (from: string) => {
    if (from.startsWith('CARD:')) {
      const cardId = from.split(':')[1];
      const pos = getCardPos(cardId);
      return { x: pos.right, y: pos.centerY };
    }
    const p = tablePositions[from];
    if (!p) return null;
    return { x: p.x + 200, y: p.y + 80 }; // 노드 우측 중앙
  };

  const getToPos = (to: string) => {
    const p = tablePositions[to];
    if (!p) return null;
    return { x: p.x, y: p.y + 80 }; // 노드 좌측 중앙
  };

  return (
    <>
      {/* SVG 연결선 */}
      <ConnectionSvg>
        {animTimings.map(({ edge, lineDelay }, idx) => {
          const from = getFromPos(edge.from);
          const to = getToPos(edge.to);
          if (!from || !to) return null;
          return (
            <FlowLine
              key={`line-${idx}`}
              x1={from.x} y1={from.y}
              x2={to.x} y2={to.y}
              type={edge.type}
              animate
              delay={lineDelay}
            />
          );
        })}
      </ConnectionSvg>

      {/* 연결선 뱃지 */}
      {animTimings.map(({ edge, nodeDelay }, idx) => {
        const from = getFromPos(edge.from);
        const to = getToPos(edge.to);
        if (!from || !to) return null;
        const mx = (from.x + to.x) / 2;
        const my = (from.y + to.y) / 2;
        return (
          <FlowBadge
            key={`badge-${idx}`}
            x={mx} y={my}
            label={edge.label}
            type={edge.type}
            animate
            delay={nodeDelay}
          />
        );
      })}

      {/* 테이블 노드 (table_relationships 레이어) */}
      {Object.entries(tablePositions).map(([name, pos]) => {
        const meta = tableMetas[name];
        if (!meta) return null;
        const revealed = revealedNodes.has(name);
        return (
          <TableNode
            key={name}
            tableName={name}
            label={meta.label}
            icon={meta.icon}
            columns={meta.columns}
            x={pos.x}
            y={pos.y}
            onMove={handleNodeMove}
            style={{
              opacity: revealed ? 1 : 0,
              transform: revealed ? 'scale(1)' : 'scale(0.3)',
              transition: 'opacity .35s ease-out, transform .35s cubic-bezier(.16,1,.3,1)',
              pointerEvents: revealed ? 'auto' : 'none',
            }}
          />
        );
      })}

      {/* ★ 비즈니스 룰 오버레이 (별도 레이어 — 저장된 노드 type별로 렌더) */}
      {ruleOverlays.map((overlay, oi) => (
        <div key={`rule-overlay-${oi}`}>
          {/* 룰 노드 → type별로 TableNode 또는 ControlNode (read-only) */}
          {overlay.nodes.map((node) => {
            // ★ type === 'table'이면 TableNode로 렌더
            if (node.type === 'table') {
              const tableName = node.table_name ?? node.tableName ?? node.label ?? node.id;
              const columns: FieldConfig[] = (node.columns ?? []).slice(0, 8);
              return (
                <div
                  key={node.id}
                  style={{
                    position: 'absolute',
                    left: node.x ?? 0,
                    top: node.y ?? 0,
                    opacity: 0.85,
                    pointerEvents: 'none',
                  }}
                >
                  <TableNode
                    tableName={tableName}
                    label={node.label ?? tableName}
                    icon="🏢"
                    columns={columns}
                    x={0}
                    y={0}
                    onMove={() => {}}
                  />
                </div>
              );
            }
            // ★ 그 외는 제어 노드 (CTRL_NODE_TYPES)
            const nodeType = node.type ?? 'auto-insert';
            const typeDef = (CTRL_NODE_TYPES as Record<string, any>)[nodeType];
            return (
              <div
                key={node.id}
                className="ctrl-action-node"
                style={{
                  position: 'absolute',
                  left: node.x ?? 0,
                  top: node.y ?? 0,
                  width: 160,
                  opacity: 0.85,
                  pointerEvents: 'none',
                  // @ts-ignore
                  '--na-rgb': typeDef?.rgb ?? '108,92,231',
                } as React.CSSProperties}
              >
                <div className="ctrl-an-head" style={{ cursor: 'default' }}>
                  <div className="ctrl-an-icon">{typeDef?.icon ?? '⚡'}</div>
                  <span className="ctrl-an-name">{typeDef?.label ?? nodeType}</span>
                </div>
                <div className="ctrl-an-body">
                  <div className="ctrl-an-summary" style={{ fontSize: '.45rem', color: 'var(--v5-text-muted)' }}>
                    [{overlay.ruleName}]
                  </div>
                </div>
              </div>
            );
          })}

          {/* 룰 연결선 (SVG) — RuleBuilder.portPos와 동일한 앵커 계산 */}
          <ConnectionSvg>
            {overlay.connections.map((conn, ci) => {
              const fromNode = overlay.nodes.find((n) => n.id === (conn.from_node_id ?? conn.fromNodeId));
              const toNode = overlay.nodes.find((n) => n.id === (conn.to_node_id ?? conn.toNodeId));
              if (!fromNode || !toNode) return null;

              const fromPort = conn.from_port ?? conn.fromPort ?? 'out';
              const toPort = conn.to_port ?? conn.toPort ?? 'in';
              const f = computePortPos(fromNode, fromPort);
              const t = computePortPos(toNode, toPort);
              if (!f || !t) return null;

              const lineType = fromPort === 'yes' ? 'auto' : fromPort === 'no' ? 'cond' : 'auto';
              return (
                <FlowLine
                  key={`rule-line-${oi}-${ci}`}
                  x1={f.x} y1={f.y} x2={t.x} y2={t.y}
                  type={lineType}
                  animate={false}
                  delay={0}
                />
              );
            })}
          </ConnectionSvg>
        </div>
      ))}
    </>
  );
}
