/**
 * useConnectionResolver - 런타임 컴포넌트 연결 해석기
 *
 * PopViewerWithModals에서 사용.
 * layout.dataFlow.connections를 읽고, 소스 컴포넌트의 __comp_output__ 이벤트를
 * 타겟 컴포넌트의 __comp_input__ 이벤트로 자동 변환/중계한다.
 *
 * 이벤트 규칙:
 *   소스:  __comp_output__${sourceComponentId}__${outputKey}
 *   타겟:  __comp_input__${targetComponentId}__${inputKey}
 *
 * _auto 모드:
 *   sourceOutput="_auto"인 연결은 소스/타겟의 connectionMeta를 비교하여
 *   key가 같고 category="event"인 쌍을 양방향으로 자동 라우팅한다.
 *   (정방향: 소스->타겟, 역방향: 타겟->소스)
 */

import { useEffect, useRef } from "react";
import { usePopEvent } from "./usePopEvent";
import type { PopDataConnection } from "@/components/pop/designer/types/pop-layout";
import {
  PopComponentRegistry,
} from "@/lib/registry/PopComponentRegistry";

interface UseConnectionResolverOptions {
  screenId: string;
  connections: PopDataConnection[];
  componentTypes?: Map<string, string>;
}

interface AutoMatchPair {
  sourceKey: string;
  targetKey: string;
  isFilter: boolean;
}

/**
 * 소스/타겟의 connectionMeta에서 자동 매칭 가능한 쌍을 찾는다.
 * 규칙 1: category="event"이고 key가 동일한 쌍 (이벤트 매칭)
 * 규칙 2: 소스 type="filter_value" + 타겟 type="filter_value" (필터 매칭)
 */
function getAutoMatchPairs(
  sourceType: string,
  targetType: string
): AutoMatchPair[] {
  const sourceDef = PopComponentRegistry.getComponent(sourceType);
  const targetDef = PopComponentRegistry.getComponent(targetType);

  if (!sourceDef?.connectionMeta?.sendable || !targetDef?.connectionMeta?.receivable) {
    return [];
  }

  const pairs: AutoMatchPair[] = [];

  for (const s of sourceDef.connectionMeta.sendable) {
    for (const r of targetDef.connectionMeta.receivable) {
      if (s.category === "event" && r.category === "event" && s.key === r.key) {
        pairs.push({ sourceKey: s.key, targetKey: r.key, isFilter: false });
      }
      if (s.type === "filter_value" && r.type === "filter_value") {
        pairs.push({ sourceKey: s.key, targetKey: r.key, isFilter: true });
      }
      if (s.type === "all_rows" && r.type === "all_rows") {
        pairs.push({ sourceKey: s.key, targetKey: r.key, isFilter: false });
      }
    }
  }

  return pairs;
}

export function useConnectionResolver({
  screenId,
  connections,
  componentTypes,
}: UseConnectionResolverOptions): void {
  const { publish, subscribe } = usePopEvent(screenId);

  const connectionsRef = useRef(connections);
  connectionsRef.current = connections;

  const componentTypesRef = useRef(componentTypes);
  componentTypesRef.current = componentTypes;

  useEffect(() => {
    if (!connections || connections.length === 0) return;

    const unsubscribers: (() => void)[] = [];

    for (const conn of connections) {
      const isAutoMode = conn.sourceOutput === "_auto" || !conn.sourceOutput;

      if (isAutoMode && componentTypesRef.current) {
        const sourceType = componentTypesRef.current.get(conn.sourceComponent);
        const targetType = componentTypesRef.current.get(conn.targetComponent);

        if (!sourceType || !targetType) continue;

        // 정방향: 소스 sendable -> 타겟 receivable
        const forwardPairs = getAutoMatchPairs(sourceType, targetType);
        for (const pair of forwardPairs) {
          const sourceEvent = `__comp_output__${conn.sourceComponent}__${pair.sourceKey}`;
          const targetEvent = `__comp_input__${conn.targetComponent}__${pair.targetKey}`;

          const unsub = subscribe(sourceEvent, (payload: unknown) => {
            if (pair.isFilter) {
              const data = payload as Record<string, unknown> | null;
              const fieldName = data?.fieldName as string | undefined;
              const filterColumns = data?.filterColumns as string[] | undefined;
              const filterMode = (data?.filterMode as string) || "contains";
              // conn.filterConfig에 targetColumn이 명시되어 있으면 우선 사용
              const effectiveColumn = conn.filterConfig?.targetColumn || fieldName;
              const effectiveMode = conn.filterConfig?.filterMode || filterMode;
              const baseFilterConfig = effectiveColumn
                ? { targetColumn: effectiveColumn, targetColumns: conn.filterConfig?.targetColumns || (filterColumns?.length ? filterColumns : [effectiveColumn]), filterMode: effectiveMode }
                : conn.filterConfig;
              publish(targetEvent, {
                value: payload,
                filterConfig: conn.filterConfig?.isSubTable
                  ? { ...baseFilterConfig, isSubTable: true }
                  : baseFilterConfig,
                _connectionId: conn.id,
              });
            } else {
              publish(targetEvent, {
                value: payload,
                _connectionId: conn.id,
              });
            }
          });
          unsubscribers.push(unsub);
        }

        // 역방향: 타겟 sendable -> 소스 receivable
        const reversePairs = getAutoMatchPairs(targetType, sourceType);
        for (const pair of reversePairs) {
          const sourceEvent = `__comp_output__${conn.targetComponent}__${pair.sourceKey}`;
          const targetEvent = `__comp_input__${conn.sourceComponent}__${pair.targetKey}`;

          const unsub = subscribe(sourceEvent, (payload: unknown) => {
            publish(targetEvent, {
              value: payload,
              _connectionId: conn.id,
            });
          });
          unsubscribers.push(unsub);
        }
      } else {
        const sourceEvent = `__comp_output__${conn.sourceComponent}__${conn.sourceOutput || conn.sourceField}`;

        const unsub = subscribe(sourceEvent, (payload: unknown) => {
          const targetEvent = `__comp_input__${conn.targetComponent}__${conn.targetInput || conn.targetField}`;

          let resolvedFilterConfig = conn.filterConfig;
          if (!resolvedFilterConfig) {
            const data = payload as Record<string, unknown> | null;
            const fieldName = data?.fieldName as string | undefined;
            const filterColumns = data?.filterColumns as string[] | undefined;
            if (fieldName) {
              const filterMode = (data?.filterMode as string) || "contains";
              resolvedFilterConfig = { targetColumn: fieldName, targetColumns: filterColumns?.length ? filterColumns : [fieldName], filterMode: filterMode as "equals" | "contains" | "starts_with" | "range" };
            }
          }

          publish(targetEvent, {
            value: payload,
            filterConfig: resolvedFilterConfig,
            _connectionId: conn.id,
          });
        });
        unsubscribers.push(unsub);
      }
    }

    return () => {
      for (const unsub of unsubscribers) {
        unsub();
      }
    };
  }, [screenId, connections, subscribe, publish]);
}
