"use client";

import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Badge } from "@/components/ui/badge";
import { Plus, Columns, AlignJustify, Trash2, Search } from "lucide-react";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";

// 기존 ModalRepeaterTable 컴포넌트 재사용
import { RepeaterTable } from "../modal-repeater-table/RepeaterTable";
import { ItemSelectionModal } from "../modal-repeater-table/ItemSelectionModal";
import { RepeaterColumnConfig, CalculationRule } from "../modal-repeater-table/types";

// 타입 정의
import {
  TableSectionConfig,
  TableColumnConfig,
  TableJoinCondition,
  FormDataState,
  TableCalculationRule,
} from "./types";

interface TableSectionRendererProps {
  sectionId: string;
  tableConfig: TableSectionConfig;
  formData: FormDataState;
  onFormDataChange: (field: string, value: any) => void;
  onTableDataChange: (data: any[]) => void;
  // 조건부 테이블용 콜백 (조건별 데이터 변경)
  onConditionalTableDataChange?: (conditionValue: string, data: any[]) => void;
  // 외부 데이터 (데이터 전달 모달열기 액션으로 전달받은 데이터)
  groupedData?: Record<string, any>[];
  className?: string;
}

// 조건부 테이블 데이터 타입
interface ConditionalTableData {
  [conditionValue: string]: any[];
}

/**
 * TableColumnConfig를 RepeaterColumnConfig로 변환
 * columnModes 또는 lookup이 있으면 dynamicDataSource로 변환
 */
function convertToRepeaterColumn(col: TableColumnConfig): RepeaterColumnConfig {
  const baseColumn: RepeaterColumnConfig = {
    field: col.field,
    label: col.label,
    type: col.type,
    editable: col.editable ?? true,
    calculated: col.calculated ?? false,
    width: col.width || "150px",
    required: col.required,
    hidden: col.hidden ?? false,
    defaultValue: col.defaultValue,
    selectOptions: col.selectOptions,
    // valueMapping은 별도로 처리
  };

  // lookup 설정을 dynamicDataSource로 변환 (새로운 조회 기능)
  if (col.lookup?.enabled && col.lookup.options && col.lookup.options.length > 0) {
    baseColumn.dynamicDataSource = {
      enabled: true,
      options: col.lookup.options.map((option) => ({
        id: option.id,
        // "컬럼명 - 옵션라벨" 형식으로 헤더에 표시
        label: option.displayLabel || option.label,
        // 헤더에 표시될 전체 라벨 (컬럼명 - 옵션라벨)
        headerLabel: `${col.label} - ${option.displayLabel || option.label}`,
        sourceType: "table" as const,
        tableConfig: {
          tableName: option.tableName,
          valueColumn: option.valueColumn,
          joinConditions: option.conditions.map((cond) => ({
            sourceField: cond.sourceField,
            targetField: cond.targetColumn,
            // sourceType에 따른 데이터 출처 설정
            sourceType: cond.sourceType, // "currentRow" | "sectionField" | "externalTable"
            fromFormData: cond.sourceType === "sectionField",
            sectionId: cond.sectionId,
            // 외부 테이블 조회 설정 (sourceType이 "externalTable"인 경우)
            externalLookup: cond.externalLookup,
            // 값 변환 설정 전달 (레거시 호환)
            transform: cond.transform?.enabled
              ? {
                  tableName: cond.transform.tableName,
                  matchColumn: cond.transform.matchColumn,
                  resultColumn: cond.transform.resultColumn,
                }
              : undefined,
          })),
        },
        // 조회 유형 정보 추가
        lookupType: option.type,
      })),
      defaultOptionId: col.lookup.options.find((o) => o.isDefault)?.id || col.lookup.options[0]?.id,
    };
  }
  // columnModes를 dynamicDataSource로 변환 (기존 로직 유지)
  else if (col.columnModes && col.columnModes.length > 0) {
    baseColumn.dynamicDataSource = {
      enabled: true,
      options: col.columnModes.map((mode) => ({
        id: mode.id,
        label: mode.label,
        sourceType: "table" as const,
        // 실제 조회 로직은 TableSectionRenderer에서 처리
        tableConfig: {
          tableName: mode.valueMapping?.externalRef?.tableName || "",
          valueColumn: mode.valueMapping?.externalRef?.valueColumn || "",
          joinConditions: (mode.valueMapping?.externalRef?.joinConditions || []).map((jc) => ({
            sourceField: jc.sourceField,
            targetField: jc.targetColumn,
          })),
        },
      })),
      defaultOptionId: col.columnModes.find((m) => m.isDefault)?.id || col.columnModes[0]?.id,
    };
  }

  return baseColumn;
}

/**
 * TableCalculationRule을 CalculationRule로 변환
 */
function convertToCalculationRule(calc: {
  resultField: string;
  formula: string;
  dependencies: string[];
}): CalculationRule {
  return {
    result: calc.resultField,
    formula: calc.formula,
    dependencies: calc.dependencies,
  };
}

/**
 * 값 변환 함수: 중간 테이블을 통해 값을 변환
 * 예: 거래처 이름 "(무)테스트업체" → 거래처 코드 "CUST-0002"
 */
async function transformValue(
  value: any,
  transform: { tableName: string; matchColumn: string; resultColumn: string },
): Promise<any> {
  if (!value || !transform.tableName || !transform.matchColumn || !transform.resultColumn) {
    return value;
  }

  try {
    // 정확히 일치하는 검색
    const response = await apiClient.post(`/table-management/tables/${transform.tableName}/data`, {
      search: {
        [transform.matchColumn]: {
          value: value,
          operator: "equals",
        },
      },
      size: 1,
      page: 1,
    });

    if (response.data.success && response.data.data?.data?.length > 0) {
      const transformedValue = response.data.data.data[0][transform.resultColumn];
      return transformedValue;
    }

    console.warn(`변환 실패: ${transform.tableName}.${transform.matchColumn} = "${value}" 인 행을 찾을 수 없습니다.`);
    return undefined;
  } catch (error) {
    console.error("값 변환 오류:", error);
    return undefined;
  }
}

/**
 * 외부 테이블에서 조건 값을 조회하는 함수
 * LookupCondition.sourceType이 "externalTable"인 경우 사용
 */
async function fetchExternalLookupValue(
  externalLookup: {
    tableName: string;
    matchColumn: string;
    matchSourceType: "currentRow" | "sourceTable" | "sectionField";
    matchSourceField: string;
    matchSectionId?: string;
    resultColumn: string;
  },
  rowData: any,
  sourceData: any,
  formData: FormDataState,
): Promise<any> {
  // 1. 비교 값 가져오기
  let matchValue: any;
  if (externalLookup.matchSourceType === "currentRow") {
    matchValue = rowData[externalLookup.matchSourceField];
  } else if (externalLookup.matchSourceType === "sourceTable") {
    matchValue = sourceData?.[externalLookup.matchSourceField];
  } else {
    matchValue = formData[externalLookup.matchSourceField];
  }

  if (matchValue === undefined || matchValue === null || matchValue === "") {
    console.warn(
      `외부 테이블 조회: 비교 값이 없습니다. (${externalLookup.matchSourceType}.${externalLookup.matchSourceField})`,
    );
    return undefined;
  }

  // 2. 외부 테이블에서 값 조회 (정확히 일치하는 검색)
  try {
    const response = await apiClient.post(`/table-management/tables/${externalLookup.tableName}/data`, {
      search: {
        [externalLookup.matchColumn]: {
          value: matchValue,
          operator: "equals",
        },
      },
      size: 1,
      page: 1,
    });

    if (response.data.success && response.data.data?.data?.length > 0) {
      return response.data.data.data[0][externalLookup.resultColumn];
    }

    console.warn(
      `외부 테이블 조회: ${externalLookup.tableName}.${externalLookup.matchColumn} = "${matchValue}" 인 행을 찾을 수 없습니다.`,
    );
    return undefined;
  } catch (error) {
    console.error("외부 테이블 조회 오류:", error);
    return undefined;
  }
}

/**
 * 외부 테이블에서 값을 조회하는 함수
 *
 * @param tableName - 조회할 테이블명
 * @param valueColumn - 가져올 컬럼명
 * @param joinConditions - 조인 조건 목록
 * @param rowData - 현재 행 데이터 (설정된 컬럼 필드)
 * @param sourceData - 원본 소스 데이터 (_sourceData)
 * @param formData - 폼 데이터 (다른 섹션 필드)
 */
async function fetchExternalValue(
  tableName: string,
  valueColumn: string,
  joinConditions: TableJoinCondition[],
  rowData: any,
  sourceData: any,
  formData: FormDataState,
): Promise<any> {
  if (joinConditions.length === 0) {
    return undefined;
  }

  try {
    const whereConditions: Record<string, any> = {};

    for (const condition of joinConditions) {
      let value: any;

      // 값 출처에 따라 가져오기 (4가지 소스 타입 지원)
      if (condition.sourceType === "row") {
        // 현재 행 데이터 (설정된 컬럼 필드)
        value = rowData[condition.sourceField];
      } else if (condition.sourceType === "sourceData") {
        // 원본 소스 테이블 데이터 (_sourceData)
        value = sourceData?.[condition.sourceField];
      } else if (condition.sourceType === "formData") {
        // formData에서 가져오기 (다른 섹션)
        value = formData[condition.sourceField];
      } else if (condition.sourceType === "externalTable" && condition.externalLookup) {
        // 외부 테이블에서 조회하여 가져오기
        value = await fetchExternalLookupValue(condition.externalLookup, rowData, sourceData, formData);
      }

      if (value === undefined || value === null || value === "") {
        return undefined;
      }

      // 값 변환이 필요한 경우 (예: 이름 → 코드) - 레거시 호환
      if (condition.transform) {
        value = await transformValue(value, condition.transform);
        if (value === undefined) {
          return undefined;
        }
      }

      // 숫자형 ID 변환
      let convertedValue = value;
      if (condition.targetColumn.endsWith("_id") || condition.targetColumn === "id") {
        const numValue = Number(value);
        if (!isNaN(numValue)) {
          convertedValue = numValue;
        }
      }

      // 정확히 일치하는 검색을 위해 operator: "equals" 사용
      whereConditions[condition.targetColumn] = {
        value: convertedValue,
        operator: "equals",
      };
    }

    // API 호출
    const response = await apiClient.post(`/table-management/tables/${tableName}/data`, {
      search: whereConditions,
      size: 1,
      page: 1,
    });

    if (response.data.success && response.data.data?.data?.length > 0) {
      return response.data.data.data[0][valueColumn];
    }

    return undefined;
  } catch (error) {
    console.error("외부 테이블 조회 오류:", error);
    return undefined;
  }
}

/**
 * 테이블 섹션 렌더러
 * UniversalFormModal 내에서 테이블 형식의 데이터를 표시하고 편집
 */
export function TableSectionRenderer({
  sectionId,
  tableConfig,
  formData,
  onFormDataChange,
  onTableDataChange,
  onConditionalTableDataChange,
  groupedData,
  className,
}: TableSectionRendererProps) {
  // 테이블 데이터 상태 (일반 모드)
  const [tableData, setTableData] = useState<any[]>([]);

  // 조건부 테이블 데이터 상태 (조건별로 분리)
  const [conditionalTableData, setConditionalTableData] = useState<ConditionalTableData>({});

  // 조건부 테이블: 선택된 조건들 (체크박스 모드)
  const [selectedConditions, setSelectedConditions] = useState<string[]>([]);

  // 조건부 테이블: 현재 활성 탭
  const [activeConditionTab, setActiveConditionTab] = useState<string>("");

  // 조건부 테이블: 현재 모달이 열린 조건 (어떤 조건의 테이블에 추가할지)
  const [modalCondition, setModalCondition] = useState<string>("");

  // 모달 상태
  const [modalOpen, setModalOpen] = useState(false);

  // 체크박스 선택 상태 (조건별로 분리)
  const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());
  const [conditionalSelectedRows, setConditionalSelectedRows] = useState<Record<string, Set<number>>>({});

  // 너비 조정 트리거 (홀수: 자동맞춤, 짝수: 균등분배)
  const [widthTrigger, setWidthTrigger] = useState(0);

  // 동적 데이터 소스 활성화 상태
  const [activeDataSources, setActiveDataSources] = useState<Record<string, string>>({});

  // 날짜 일괄 적용 완료 플래그 (컬럼별로 한 번만 적용)
  const [batchAppliedFields, setBatchAppliedFields] = useState<Set<string>>(new Set());

  // 초기 데이터 로드 완료 플래그 (무한 루프 방지)
  const initialDataLoadedRef = React.useRef(false);

  // 외부 데이터 로드 완료 플래그
  const externalDataLoadedRef = React.useRef(false);

  // 외부 데이터 소스 설정
  const externalDataConfig = tableConfig.externalDataSource;
  const isExternalDataMode = externalDataConfig?.enabled && externalDataConfig?.tableName;

  // 조건부 테이블 설정
  const conditionalConfig = tableConfig.conditionalTable;
  const isConditionalMode = conditionalConfig?.enabled ?? false;

  // 조건부 테이블: 동적 옵션 로드 상태
  const [dynamicOptions, setDynamicOptions] = useState<{ id: string; value: string; label: string }[]>([]);
  const [dynamicOptionsLoading, setDynamicOptionsLoading] = useState(false);
  const dynamicOptionsLoadedRef = React.useRef(false);
  
  // 소스 테이블의 카테고리 타입 컬럼 목록
  const [sourceCategoryColumns, setSourceCategoryColumns] = useState<string[]>([]);

  // 소스 테이블의 컬럼 라벨 (API에서 동적 로드)
  const [sourceColumnLabels, setSourceColumnLabels] = useState<Record<string, string>>({});

  // 카테고리 타입 컬럼의 옵션 (column.type === "category")
  const [categoryOptionsMap, setCategoryOptionsMap] = useState<Record<string, { value: string; label: string }[]>>({});

  // 외부 데이터(groupedData) 처리: 데이터 전달 모달열기 액션으로 전달받은 데이터를 초기 테이블 데이터로 설정
  useEffect(() => {
    // 외부 데이터 소스가 활성화되지 않았거나, groupedData가 없으면 스킵
    if (!isExternalDataMode) return;
    if (!groupedData || groupedData.length === 0) return;
    // 이미 로드된 경우 스킵
    if (externalDataLoadedRef.current) return;
    
    console.log("[TableSectionRenderer] 외부 데이터 처리 시작:", {
      externalTableName: externalDataConfig?.tableName,
      groupedDataCount: groupedData.length,
      columns: tableConfig.columns?.length,
    });

    // groupedData를 테이블 컬럼 매핑에 따라 변환
    const mappedData = groupedData.map((externalRow, index) => {
      const newRow: Record<string, any> = {
        _id: `external_${Date.now()}_${index}`,
        _sourceData: externalRow, // 원본 데이터 보관
      };

      // 각 컬럼에 대해 externalField 또는 field로 값을 매핑
      tableConfig.columns?.forEach((col) => {
        // externalField가 설정되어 있으면 사용, 아니면 field와 동일한 이름으로 매핑
        const externalFieldName = col.externalField || col.field;
        const value = externalRow[externalFieldName];
        
        // 값이 있으면 설정
        if (value !== undefined) {
          newRow[col.field] = value;
        } else if (col.defaultValue !== undefined) {
          // 기본값이 설정되어 있으면 기본값 사용
          newRow[col.field] = col.defaultValue;
        }
      });

      return newRow;
    });

    console.log("[TableSectionRenderer] 외부 데이터 매핑 완료:", {
      mappedCount: mappedData.length,
      sampleRow: mappedData[0],
    });

    // 테이블 데이터 설정
    setTableData(mappedData);
    onTableDataChange(mappedData);
    externalDataLoadedRef.current = true;
  }, [isExternalDataMode, groupedData, tableConfig.columns, externalDataConfig?.tableName, onTableDataChange]);

  // 소스 테이블의 카테고리 타입 컬럼 목록 로드
  useEffect(() => {
    const loadCategoryColumns = async () => {
      if (!tableConfig.source.tableName) return;
      
      try {
        const response = await apiClient.get(
          `/table-categories/${tableConfig.source.tableName}/columns`
        );
        
        if (response.data?.success && Array.isArray(response.data.data)) {
          const categoryColNames = response.data.data.map(
            (col: { columnName?: string; column_name?: string }) => 
              col.columnName || col.column_name || ""
          ).filter(Boolean);
          setSourceCategoryColumns(categoryColNames);
        }
      } catch (error) {
        console.error("카테고리 컬럼 목록 조회 실패:", error);
      }
    };
    
    loadCategoryColumns();
  }, [tableConfig.source.tableName]);

  // 소스 테이블의 컬럼 라벨 로드 (source.columnLabels가 비어있을 때만)
  useEffect(() => {
    const loadColumnLabels = async () => {
      const sourceTableName = tableConfig.source.tableName;
      if (!sourceTableName) return;
      
      // 이미 source.columnLabels가 설정되어 있으면 스킵
      if (tableConfig.source.columnLabels && Object.keys(tableConfig.source.columnLabels).length > 0) {
        return;
      }
      
      try {
        const response = await apiClient.get(`/table-management/tables/${sourceTableName}/columns`);
        
        if (response.data?.success && response.data.data) {
          const columnsData = response.data.data.columns || response.data.data || [];
          const labels: Record<string, string> = {};
          
          for (const col of columnsData) {
            const colName = col.column_name || col.columnName;
            // displayName: API에서 반환하는 라벨 (COALESCE(cl.column_label, c.column_name))
            const colLabel = col.displayName || col.column_label || col.columnLabel || col.comment;
            // 라벨이 컬럼명과 다를 때만 저장 (의미있는 라벨인 경우)
            if (colName && colLabel && colLabel !== colName) {
              labels[colName] = colLabel;
            }
          }
          
          setSourceColumnLabels(labels);
        }
      } catch (error) {
        console.error("소스 테이블 컬럼 라벨 조회 실패:", error);
      }
    };
    
    loadColumnLabels();
  }, [tableConfig.source.tableName, tableConfig.source.columnLabels]);

  // 카테고리 타입 컬럼 + referenceDisplay 소스 카테고리 컬럼의 옵션 로드
  useEffect(() => {
    const loadCategoryOptions = async () => {
      const sourceTableName = tableConfig.source.tableName;
      if (!sourceTableName) return;
      if (!tableConfig.columns) return;

      const newOptionsMap: Record<string, { value: string; label: string }[]> = {};
      const loadedSourceColumns = new Set<string>();

      const { getCategoryValues } = await import("@/lib/api/tableCategoryValue");

      for (const col of tableConfig.columns) {
        let sourceColumnName: string | undefined;

        if (col.type === "category") {
          sourceColumnName = col.sourceField || col.field;
        } else {
          // referenceDisplay로 소스 카테고리 컬럼을 참조하는 컬럼도 포함
          const refSource = (col as any).saveConfig?.referenceDisplay?.sourceColumn;
          if (refSource && sourceCategoryColumns.includes(refSource)) {
            sourceColumnName = refSource;
          }
        }

        if (!sourceColumnName || loadedSourceColumns.has(`${col.field}:${sourceColumnName}`)) continue;
        loadedSourceColumns.add(`${col.field}:${sourceColumnName}`);

        try {
          const result = await getCategoryValues(sourceTableName, sourceColumnName, false);

          if (result?.success && Array.isArray(result.data)) {
            const options = result.data.map((item: any) => ({
              value: item.valueCode || item.value_code || item.value || "",
              label: item.valueLabel || item.displayLabel || item.display_label || item.label || item.valueCode || item.value_code || item.value || "",
            }));
            newOptionsMap[col.field] = options;
          }
        } catch (error) {
          console.error(`카테고리 옵션 로드 실패 (${col.field}):`, error);
        }
      }

      if (Object.keys(newOptionsMap).length > 0) {
        setCategoryOptionsMap((prev) => ({ ...prev, ...newOptionsMap }));
      }
    };

    loadCategoryOptions();
  }, [tableConfig.source.tableName, tableConfig.columns, sourceCategoryColumns]);

  // receiveFromParent / internal 매핑으로 넘어오는 formData 값의 라벨 사전 로드
  useEffect(() => {
    if (!formData || Object.keys(formData).length === 0) return;
    if (!tableConfig.columns) return;

    const codesToResolve: string[] = [];
    for (const col of tableConfig.columns) {
      // receiveFromParent 컬럼
      if ((col as any).receiveFromParent) {
        const parentField = (col as any).parentFieldName || col.field;
        const val = formData[parentField];
        if (typeof val === "string" && val) {
          codesToResolve.push(val);
        }
      }
      // internal 매핑 컬럼
      const mapping = (col as any).valueMapping;
      if (mapping?.type === "internal" && mapping.internalField) {
        const val = formData[mapping.internalField];
        if (typeof val === "string" && val) {
          codesToResolve.push(val);
        }
      }
    }

    if (codesToResolve.length === 0) return;

    const loadParentLabels = async () => {
      try {
        const resp = await apiClient.post("/table-categories/labels-by-codes", {
          valueCodes: codesToResolve,
        });
        if (resp.data?.success && resp.data.data) {
          const labelData = resp.data.data as Record<string, string>;
          // categoryOptionsMap에 추가 (receiveFromParent 컬럼별로)
          const newOptionsMap: Record<string, { value: string; label: string }[]> = {};
          for (const col of tableConfig.columns) {
            let val: string | undefined;
            if ((col as any).receiveFromParent) {
              const parentField = (col as any).parentFieldName || col.field;
              val = formData[parentField] as string;
            }
            const mapping = (col as any).valueMapping;
            if (mapping?.type === "internal" && mapping.internalField) {
              val = formData[mapping.internalField] as string;
            }
            if (val && typeof val === "string" && labelData[val]) {
              newOptionsMap[col.field] = [{ value: val, label: labelData[val] }];
            }
          }
          if (Object.keys(newOptionsMap).length > 0) {
            setCategoryOptionsMap((prev) => ({ ...prev, ...newOptionsMap }));
          }
        }
      } catch {
        // 라벨 조회 실패 시 무시
      }
    };

    loadParentLabels();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [formData, tableConfig.columns]);

  // 조건부 테이블: 동적 옵션 로드 (optionSource 설정이 있는 경우)
  useEffect(() => {
    if (!isConditionalMode) return;
    if (!conditionalConfig?.optionSource?.enabled) return;
    if (dynamicOptionsLoadedRef.current) return;

    const { tableName, valueColumn, labelColumn, filterCondition } = conditionalConfig.optionSource;

    if (!tableName || !valueColumn) return;

    const loadDynamicOptions = async () => {
      setDynamicOptionsLoading(true);
      try {
        // 카테고리 값이 있는 컬럼인지 확인 (category_values 테이블에서 라벨 해결)
        let categoryLabelMap: Record<string, string> = {};
        try {
          const { getCategoryValues } = await import("@/lib/api/tableCategoryValue");
          const catResult = await getCategoryValues(tableName, valueColumn, false);
          if (catResult?.success && Array.isArray(catResult.data)) {
            for (const item of catResult.data) {
              const code = item.valueCode || item.value_code || item.value || "";
              const label = item.valueLabel || item.displayLabel || item.display_label || item.label || code;
              if (code) categoryLabelMap[code] = label;
            }
          }
        } catch {
          // 카테고리 값이 없으면 무시
        }

        const hasCategoryValues = Object.keys(categoryLabelMap).length > 0;

        if (hasCategoryValues) {
          // 카테고리 값이 정의되어 있으면 그대로 옵션으로 사용
          const options = Object.entries(categoryLabelMap).map(([code, label], index) => ({
            id: `dynamic_${index}`,
            value: code,
            label,
          }));

          console.log("[TableSectionRenderer] 카테고리 기반 옵션 로드 완료:", {
            tableName,
            valueColumn,
            optionCount: options.length,
          });

          setDynamicOptions(options);
          dynamicOptionsLoadedRef.current = true;
        } else {
          // 카테고리 값이 없으면 기존 방식: DISTINCT 값에서 추출 (쉼표 다중값 분리)
          const response = await apiClient.post(`/table-management/tables/${tableName}/data`, {
            search: filterCondition ? { _raw: filterCondition } : {},
            size: 1000,
            page: 1,
          });

          if (response.data.success && response.data.data?.data) {
            const rows = response.data.data.data;

            const uniqueValues = new Map<string, string>();
            for (const row of rows) {
              const rawValue = row[valueColumn];
              if (!rawValue) continue;

              // 쉼표 구분 다중값을 개별로 분리
              const values = String(rawValue).split(",").map((v: string) => v.trim()).filter(Boolean);
              for (const v of values) {
                if (!uniqueValues.has(v)) {
                  const label = labelColumn ? row[labelColumn] || v : v;
                  uniqueValues.set(v, label);
                }
              }
            }

            const options = Array.from(uniqueValues.entries()).map(([value, label], index) => ({
              id: `dynamic_${index}`,
              value,
              label,
            }));

            console.log("[TableSectionRenderer] DISTINCT 기반 옵션 로드 완료:", {
              tableName,
              valueColumn,
              optionCount: options.length,
            });

            setDynamicOptions(options);
            dynamicOptionsLoadedRef.current = true;
          }
        }
      } catch (error) {
        console.error("[TableSectionRenderer] 동적 옵션 로드 실패:", error);
      } finally {
        setDynamicOptionsLoading(false);
      }
    };

    loadDynamicOptions();
  }, [isConditionalMode, conditionalConfig?.optionSource]);

  // ============================================
  // 동적 Select 옵션 (소스 테이블에서 드롭다운 옵션 로드)
  // ============================================

  // 소스 테이블 데이터 캐시 (동적 Select 옵션용)
  const [sourceDataCache, setSourceDataCache] = useState<any[]>([]);
  const sourceDataLoadedRef = React.useRef(false);

  // 동적 Select 옵션이 있는 컬럼 확인
  const hasDynamicSelectColumns = useMemo(() => {
    return tableConfig.columns?.some((col) => col.dynamicSelectOptions?.enabled);
  }, [tableConfig.columns]);

  // 소스 테이블 데이터 로드 (동적 Select 옵션용)
  useEffect(() => {
    if (!hasDynamicSelectColumns) return;
    if (sourceDataLoadedRef.current) return;
    if (!tableConfig.source?.tableName) return;

    const loadSourceData = async () => {
      try {
        // 조건부 테이블 필터 조건 적용
        const filterCondition: Record<string, any> = {};

        // 소스 필터가 활성화되어 있고 조건이 선택되어 있으면 필터 적용
        if (conditionalConfig?.sourceFilter?.enabled && activeConditionTab) {
          filterCondition[conditionalConfig.sourceFilter.filterColumn] = activeConditionTab;
        }

        const response = await apiClient.post(`/table-management/tables/${tableConfig.source.tableName}/data`, {
          search: filterCondition,
          size: 1000,
          page: 1,
        });

        if (response.data.success && response.data.data?.data) {
          setSourceDataCache(response.data.data.data);
          sourceDataLoadedRef.current = true;
          console.log("[TableSectionRenderer] 소스 데이터 로드 완료:", {
            tableName: tableConfig.source.tableName,
            rowCount: response.data.data.data.length,
            filter: filterCondition,
          });
        }
      } catch (error) {
        console.error("[TableSectionRenderer] 소스 데이터 로드 실패:", error);
      }
    };

    loadSourceData();
  }, [hasDynamicSelectColumns, tableConfig.source?.tableName, conditionalConfig?.sourceFilter, activeConditionTab]);

  // 조건 탭 변경 시 소스 데이터 다시 로드
  useEffect(() => {
    if (!hasDynamicSelectColumns) return;
    if (!conditionalConfig?.sourceFilter?.enabled) return;
    if (!activeConditionTab) return;
    if (!tableConfig.source?.tableName) return;

    // 조건 변경 시 캐시 리셋하고 즉시 다시 로드
    sourceDataLoadedRef.current = false;
    setSourceDataCache([]);

    // 즉시 데이터 다시 로드 (기존 useEffect에 의존하지 않고 직접 호출)
    const loadSourceData = async () => {
      try {
        const filterCondition: Record<string, any> = {};
        filterCondition[conditionalConfig.sourceFilter!.filterColumn] = activeConditionTab;

        const response = await apiClient.post(`/table-management/tables/${tableConfig.source!.tableName}/data`, {
          search: filterCondition,
          size: 1000,
          page: 1,
        });

        if (response.data.success && response.data.data?.data) {
          setSourceDataCache(response.data.data.data);
          sourceDataLoadedRef.current = true;
          console.log("[TableSectionRenderer] 조건 탭 변경 - 소스 데이터 로드 완료:", {
            tableName: tableConfig.source!.tableName,
            rowCount: response.data.data.data.length,
            filter: filterCondition,
          });
        }
      } catch (error) {
        console.error("[TableSectionRenderer] 소스 데이터 로드 실패:", error);
      }
    };

    loadSourceData();
  }, [
    activeConditionTab,
    hasDynamicSelectColumns,
    conditionalConfig?.sourceFilter?.enabled,
    conditionalConfig?.sourceFilter?.filterColumn,
    tableConfig.source?.tableName,
  ]);

  // 컬럼별 동적 Select 옵션 생성
  const dynamicSelectOptionsMap = useMemo(() => {
    const optionsMap: Record<string, { value: string; label: string }[]> = {};

    if (!sourceDataCache.length) return optionsMap;

    for (const col of tableConfig.columns || []) {
      if (!col.dynamicSelectOptions?.enabled) continue;

      const { sourceField, labelField, distinct = true } = col.dynamicSelectOptions;

      if (!sourceField) continue;

      // 소스 데이터에서 옵션 추출
      const seenValues = new Set<string>();
      const options: { value: string; label: string }[] = [];

      for (const row of sourceDataCache) {
        const value = row[sourceField];
        if (value === undefined || value === null || value === "") continue;

        const stringValue = String(value);

        if (distinct && seenValues.has(stringValue)) continue;
        seenValues.add(stringValue);

        const label = labelField ? row[labelField] || stringValue : stringValue;
        options.push({ value: stringValue, label: String(label) });
      }

      optionsMap[col.field] = options;
    }

    return optionsMap;
  }, [sourceDataCache, tableConfig.columns]);

  // 데이터 변경 핸들러 (날짜 일괄 적용 로직 포함) - 다른 함수에서 참조하므로 먼저 정의
  const handleDataChange = useCallback(
    (newData: any[]) => {
      let processedData = newData;

      // 날짜 일괄 적용 로직: batchApply가 활성화된 날짜 컬럼 처리
      const batchApplyColumns = tableConfig.columns.filter((col) => col.type === "date" && col.batchApply === true);

      for (const dateCol of batchApplyColumns) {
        // 이미 일괄 적용된 컬럼은 건너뜀
        if (batchAppliedFields.has(dateCol.field)) continue;

        // 해당 컬럼에 값이 있는 행과 없는 행 분류
        const itemsWithDate = processedData.filter((item) => item[dateCol.field]);
        const itemsWithoutDate = processedData.filter((item) => !item[dateCol.field]);

        // 조건: 정확히 1개만 날짜가 있고, 나머지는 모두 비어있을 때
        if (itemsWithDate.length === 1 && itemsWithoutDate.length > 0) {
          const selectedDate = itemsWithDate[0][dateCol.field];

          // 모든 행에 동일한 날짜 적용
          processedData = processedData.map((item) => ({
            ...item,
            [dateCol.field]: selectedDate,
          }));

          // 플래그 활성화 (이후 개별 수정 가능)
          setBatchAppliedFields((prev) => new Set([...prev, dateCol.field]));
        }
      }

      setTableData(processedData);
      onTableDataChange(processedData);
    },
    [onTableDataChange, tableConfig.columns, batchAppliedFields],
  );

  // 행 선택 모드: 드롭다운 값 변경 시 같은 소스 행의 다른 컬럼들 자동 채움
  const handleDynamicSelectChange = useCallback(
    (rowIndex: number, columnField: string, selectedValue: string, conditionValue?: string) => {
      const column = tableConfig.columns?.find((col) => col.field === columnField);
      if (!column?.dynamicSelectOptions?.rowSelectionMode?.enabled) {
        // 행 선택 모드가 아니면 일반 값 변경만
        if (conditionValue && isConditionalMode) {
          const currentData = conditionalTableData[conditionValue] || [];
          const newData = [...currentData];
          newData[rowIndex] = { ...newData[rowIndex], [columnField]: selectedValue };
          setConditionalTableData((prev) => ({ ...prev, [conditionValue]: newData }));
          onConditionalTableDataChange?.(conditionValue, newData);
        } else {
          const newData = [...tableData];
          newData[rowIndex] = { ...newData[rowIndex], [columnField]: selectedValue };
          handleDataChange(newData);
        }
        return;
      }

      // 행 선택 모드: 소스 데이터에서 해당 값을 가진 행 찾기
      const { sourceField } = column.dynamicSelectOptions;
      const { autoFillColumns, sourceIdColumn, targetIdField } = column.dynamicSelectOptions.rowSelectionMode;

      const sourceRow = sourceDataCache.find((row) => String(row[sourceField]) === selectedValue);

      if (!sourceRow) {
        console.warn(`[TableSectionRenderer] 소스 행을 찾을 수 없음: ${sourceField} = ${selectedValue}`);
        return;
      }

      // 현재 행 데이터 가져오기
      let currentData: any[];
      if (conditionValue && isConditionalMode) {
        currentData = conditionalTableData[conditionValue] || [];
      } else {
        currentData = tableData;
      }

      const newData = [...currentData];
      const updatedRow = { ...newData[rowIndex], [columnField]: selectedValue };

      // 자동 채움 매핑 적용
      if (autoFillColumns) {
        for (const mapping of autoFillColumns) {
          const sourceValue = sourceRow[mapping.sourceColumn];
          if (sourceValue !== undefined) {
            updatedRow[mapping.targetField] = sourceValue;
          }
        }
      }

      // 소스 ID 저장
      if (sourceIdColumn && targetIdField) {
        updatedRow[targetIdField] = sourceRow[sourceIdColumn];
      }

      newData[rowIndex] = updatedRow;

      // 데이터 업데이트
      if (conditionValue && isConditionalMode) {
        setConditionalTableData((prev) => ({ ...prev, [conditionValue]: newData }));
        onConditionalTableDataChange?.(conditionValue, newData);
      } else {
        handleDataChange(newData);
      }

      console.log("[TableSectionRenderer] 행 선택 모드 자동 채움:", {
        columnField,
        selectedValue,
        sourceRow,
        updatedRow,
      });
    },
    [
      tableConfig.columns,
      sourceDataCache,
      tableData,
      conditionalTableData,
      isConditionalMode,
      handleDataChange,
      onConditionalTableDataChange,
    ],
  );

  // 참조 컬럼 값 조회 함수 (saveToTarget: false인 컬럼에 대해 소스 테이블 조회)
  const loadReferenceColumnValues = useCallback(
    async (data: any[]) => {
      // saveToTarget: false이고 referenceDisplay가 설정된 컬럼 찾기
      const referenceColumns = (tableConfig.columns || []).filter(
        (col) => col.saveConfig?.saveToTarget === false && col.saveConfig?.referenceDisplay,
      );

      if (referenceColumns.length === 0) return;

      const sourceTableName = tableConfig.source?.tableName;
      if (!sourceTableName) {
        console.warn("[TableSectionRenderer] 참조 조회를 위한 소스 테이블이 설정되지 않았습니다.");
        return;
      }

      // 참조 ID들 수집 (중복 제거)
      const referenceIdSet = new Set<string>();

      for (const col of referenceColumns) {
        const refDisplay = col.saveConfig!.referenceDisplay!;

        for (const row of data) {
          const refId = row[refDisplay.referenceIdField];
          if (refId !== undefined && refId !== null && refId !== "") {
            referenceIdSet.add(String(refId));
          }
        }
      }

      if (referenceIdSet.size === 0) return;

      try {
        // 소스 테이블에서 참조 ID에 해당하는 데이터 조회
        const response = await apiClient.post(`/table-management/tables/${sourceTableName}/data`, {
          search: { id: Array.from(referenceIdSet) }, // ID 배열로 조회
          size: 1000,
          page: 1,
        });

        if (!response.data?.success || !response.data?.data?.data) {
          console.warn("[TableSectionRenderer] 참조 데이터 조회 실패");
          return;
        }

        const sourceData: any[] = response.data.data.data;

        // ID를 키로 하는 맵 생성
        const sourceDataMap: Record<string, any> = {};
        for (const sourceRow of sourceData) {
          sourceDataMap[String(sourceRow.id)] = sourceRow;
        }

        // 각 행에 참조 컬럼 값 채우기
        const updatedData = data.map((row) => {
          const newRow = { ...row };

          for (const col of referenceColumns) {
            const refDisplay = col.saveConfig!.referenceDisplay!;
            const refId = row[refDisplay.referenceIdField];

            if (refId !== undefined && refId !== null && refId !== "") {
              const sourceRow = sourceDataMap[String(refId)];
              if (sourceRow) {
                newRow[col.field] = sourceRow[refDisplay.sourceColumn];
              }
            }
          }

          return newRow;
        });

        console.log("[TableSectionRenderer] 참조 컬럼 값 조회 완료:", {
          referenceColumns: referenceColumns.map((c) => c.field),
          updatedRowCount: updatedData.length,
        });

        setTableData(updatedData);
      } catch (error) {
        console.error("[TableSectionRenderer] 참조 데이터 조회 실패:", error);
      }
    },
    [tableConfig.columns, tableConfig.source?.tableName],
  );

  // formData에서 초기 테이블 데이터 로드 (수정 모드에서 _groupedData 표시)
  // 조건부 테이블은 별도 useEffect에서 applyConditionalGrouping으로 처리
  useEffect(() => {
    if (initialDataLoadedRef.current) return;
    if (isConditionalMode) return;

    const tableSectionKey = `__tableSection_${sectionId}`;
    const initialData = formData[tableSectionKey];

    if (Array.isArray(initialData) && initialData.length > 0) {
      console.warn("[TableSectionRenderer] 비조건부 초기 데이터 로드:", {
        sectionId,
        itemCount: initialData.length,
      });
      setTableData(initialData);
      initialDataLoadedRef.current = true;
      loadReferenceColumnValues(initialData);
    }
  }, [sectionId, formData, isConditionalMode, loadReferenceColumnValues]);

  // RepeaterColumnConfig로 변환 (동적 Select 옵션 반영)
  const columns: RepeaterColumnConfig[] = useMemo(() => {
    return (tableConfig.columns || []).map((col) => {
      const baseColumn = convertToRepeaterColumn(col);

      // 동적 Select 옵션이 있으면 적용
      if (col.dynamicSelectOptions?.enabled && dynamicSelectOptionsMap[col.field]) {
        baseColumn.selectOptions = dynamicSelectOptionsMap[col.field];
      }

      // 카테고리 타입인 경우 옵션 적용 및 select 타입으로 변환
      if (col.type === "category" && categoryOptionsMap[col.field]) {
        baseColumn.type = "select"; // RepeaterTable에서 select로 렌더링
        baseColumn.selectOptions = categoryOptionsMap[col.field];
      }

      return baseColumn;
    });
  }, [tableConfig.columns, dynamicSelectOptionsMap, categoryOptionsMap]);

  // categoryOptionsMap + dynamicOptions에서 RepeaterTable용 카테고리 정보 파생
  const tableCategoryColumns = useMemo(() => {
    const cols = new Set(Object.keys(categoryOptionsMap));
    // 조건부 테이블의 conditionColumn과 매핑된 컬럼도 카테고리 컬럼으로 추가
    if (isConditionalMode && conditionalConfig?.conditionColumn && dynamicOptions.length > 0) {
      // 조건 컬럼 자체
      cols.add(conditionalConfig.conditionColumn);
      // referenceDisplay로 조건 컬럼의 소스를 참조하는 컬럼도 추가
      for (const col of tableConfig.columns || []) {
        const refDisplay = (col as any).saveConfig?.referenceDisplay;
        if (refDisplay?.sourceColumn === conditionalConfig.conditionColumn) {
          cols.add(col.field);
        }
      }
    }
    return Array.from(cols);
  }, [categoryOptionsMap, isConditionalMode, conditionalConfig?.conditionColumn, dynamicOptions, tableConfig.columns]);

  const tableCategoryLabelMap = useMemo(() => {
    const map: Record<string, string> = {};
    for (const options of Object.values(categoryOptionsMap)) {
      for (const opt of options) {
        if (opt.value && opt.label) {
          map[opt.value] = opt.label;
        }
      }
    }
    // 조건부 테이블 동적 옵션의 카테고리 코드→라벨 매핑도 추가
    for (const opt of dynamicOptions) {
      if (opt.value && opt.label && opt.value !== opt.label) {
        map[opt.value] = opt.label;
      }
    }
    return map;
  }, [categoryOptionsMap, dynamicOptions]);

  // 원본 계산 규칙 (조건부 계산 포함)
  const originalCalculationRules: TableCalculationRule[] = useMemo(
    () => tableConfig.calculations || [],
    [tableConfig.calculations],
  );

  // 기본 계산 규칙 변환 (RepeaterTable용 - 조건부 계산이 없는 경우에 사용)
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const calculationRules: CalculationRule[] = originalCalculationRules.map(convertToCalculationRule);

  // 조건부 계산 로직: 행의 조건 필드 값에 따라 적절한 계산식 선택
  const getFormulaForRow = useCallback((rule: TableCalculationRule, row: Record<string, unknown>): string => {
    // 조건부 계산이 활성화된 경우
    if (rule.conditionalCalculation?.enabled && rule.conditionalCalculation.conditionField) {
      const conditionValue = row[rule.conditionalCalculation.conditionField];
      // 조건값과 일치하는 규칙 찾기
      const matchedRule = rule.conditionalCalculation.rules?.find((r) => r.conditionValue === conditionValue);
      if (matchedRule) {
        return matchedRule.formula;
      }
      // 일치하는 규칙이 없으면 기본 계산식 사용
      if (rule.conditionalCalculation.defaultFormula) {
        return rule.conditionalCalculation.defaultFormula;
      }
    }
    // 조건부 계산이 비활성화되었거나 기본값이 없으면 원래 계산식 사용
    return rule.formula;
  }, []);

  // 계산 로직 (조건부 계산 지원)
  const calculateRow = useCallback(
    (row: any): any => {
      if (originalCalculationRules.length === 0) return row;

      const updatedRow = { ...row };

      for (const rule of originalCalculationRules) {
        try {
          // 조건부 계산에 따라 적절한 계산식 선택
          let formula = getFormulaForRow(rule, row);

          if (!formula) continue;

          const fieldMatches = formula.match(/[a-zA-Z_][a-zA-Z0-9_]*/g) || [];
          const dependencies = rule.dependencies.length > 0 ? rule.dependencies : fieldMatches;

          for (const dep of dependencies) {
            if (dep === rule.resultField) continue;
            const value = parseFloat(row[dep]) || 0;
            formula = formula.replace(new RegExp(`\\b${dep}\\b`, "g"), value.toString());
          }

          const result = new Function(`return ${formula}`)();
          updatedRow[rule.resultField] = result;
        } catch (error) {
          console.error(`계산 오류 (${rule.formula}):`, error);
          updatedRow[rule.resultField] = 0;
        }
      }

      return updatedRow;
    },
    [originalCalculationRules, getFormulaForRow],
  );

  const calculateAll = useCallback(
    (data: any[]): any[] => {
      return data.map((row) => calculateRow(row));
    },
    [calculateRow],
  );

  // 행 변경 핸들러 (동적 Select 행 선택 모드 지원)
  const handleRowChange = useCallback(
    (index: number, newRow: any, conditionValue?: string) => {
      const oldRow =
        conditionValue && isConditionalMode
          ? conditionalTableData[conditionValue]?.[index] || {}
          : tableData[index] || {};

      // 변경된 필드 찾기
      const changedFields: string[] = [];
      for (const key of Object.keys(newRow)) {
        if (oldRow[key] !== newRow[key]) {
          changedFields.push(key);
        }
      }

      // 동적 Select 컬럼의 행 선택 모드 확인
      for (const changedField of changedFields) {
        const column = tableConfig.columns?.find((col) => col.field === changedField);
        if (column?.dynamicSelectOptions?.rowSelectionMode?.enabled) {
          // 행 선택 모드 처리 (자동 채움)
          handleDynamicSelectChange(index, changedField, newRow[changedField], conditionValue);
          return; // 행 선택 모드에서 처리 완료
        }
      }

      // 일반 행 변경 처리
      const calculatedRow = calculateRow(newRow);

      if (conditionValue && isConditionalMode) {
        const currentData = conditionalTableData[conditionValue] || [];
        const newData = [...currentData];
        newData[index] = calculatedRow;
        setConditionalTableData((prev) => ({ ...prev, [conditionValue]: newData }));
        onConditionalTableDataChange?.(conditionValue, newData);
      } else {
        const newData = [...tableData];
        newData[index] = calculatedRow;
        handleDataChange(newData);
      }
    },
    [
      tableData,
      conditionalTableData,
      isConditionalMode,
      tableConfig.columns,
      calculateRow,
      handleDataChange,
      handleDynamicSelectChange,
      onConditionalTableDataChange,
    ],
  );

  // 행 삭제 핸들러
  const handleRowDelete = useCallback(
    (index: number) => {
      const newData = tableData.filter((_, i) => i !== index);
      handleDataChange(newData);
    },
    [tableData, handleDataChange],
  );

  // 선택된 항목 일괄 삭제
  const handleBulkDelete = useCallback(() => {
    if (selectedRows.size === 0) return;
    const newData = tableData.filter((_, index) => !selectedRows.has(index));
    handleDataChange(newData);
    setSelectedRows(new Set());

    // 데이터가 모두 삭제되면 일괄 적용 플래그도 리셋
    if (newData.length === 0) {
      setBatchAppliedFields(new Set());
    }
  }, [tableData, selectedRows, handleDataChange]);

  // 아이템 추가 핸들러 (모달에서 선택)
  const handleAddItems = useCallback(
    async (items: any[]) => {
      // 각 아이템에 대해 valueMapping 적용
      const mappedItems = await Promise.all(
        items.map(async (sourceItem) => {
          const newItem: any = {};

          for (const col of tableConfig.columns) {
            const mapping = col.valueMapping;

            // 0. lookup 설정이 있는 경우 (동적 조회)
            if (col.lookup?.enabled && col.lookup.options && col.lookup.options.length > 0) {
              // 현재 활성화된 옵션 또는 기본 옵션 사용
              const activeOptionId = activeDataSources[col.field];
              const defaultOption = col.lookup.options.find((o) => o.isDefault) || col.lookup.options[0];
              const selectedOption = activeOptionId
                ? col.lookup.options.find((o) => o.id === activeOptionId) || defaultOption
                : defaultOption;

              if (selectedOption) {
                // sameTable 타입: 소스 데이터에서 직접 값 복사
                if (selectedOption.type === "sameTable") {
                  const value = sourceItem[selectedOption.valueColumn];
                  if (value !== undefined) {
                    newItem[col.field] = value;
                  }
                  // _sourceData에 원본 저장 (나중에 다른 옵션으로 전환 시 사용)
                  newItem._sourceData = sourceItem;
                  continue;
                }

                // relatedTable, combinedLookup: 외부 테이블 조회
                // 조인 조건 구성 (4가지 소스 타입 지원)
                const joinConditions: TableJoinCondition[] = selectedOption.conditions.map((cond) => {
                  // sourceType 매핑
                  let sourceType: "row" | "sourceData" | "formData" | "externalTable";
                  if (cond.sourceType === "currentRow") {
                    sourceType = "row";
                  } else if (cond.sourceType === "sourceTable") {
                    sourceType = "sourceData";
                  } else if (cond.sourceType === "externalTable") {
                    sourceType = "externalTable";
                  } else {
                    sourceType = "formData";
                  }

                  return {
                    sourceType,
                    sourceField: cond.sourceField,
                    targetColumn: cond.targetColumn,
                    // 외부 테이블 조회 설정
                    externalLookup: cond.externalLookup,
                    // 값 변환 설정 전달 (레거시 호환)
                    transform: cond.transform?.enabled
                      ? {
                          tableName: cond.transform.tableName,
                          matchColumn: cond.transform.matchColumn,
                          resultColumn: cond.transform.resultColumn,
                        }
                      : undefined,
                  };
                });

                // 외부 테이블에서 값 조회 (sourceItem이 _sourceData 역할)
                const value = await fetchExternalValue(
                  selectedOption.tableName,
                  selectedOption.valueColumn,
                  joinConditions,
                  { ...sourceItem, ...newItem }, // rowData (현재 행)
                  sourceItem, // sourceData (소스 테이블 원본)
                  formData,
                );

                if (value !== undefined) {
                  newItem[col.field] = value;
                }

                // _sourceData에 원본 저장
                newItem._sourceData = sourceItem;
              }
              continue;
            }

            // 1. 먼저 col.sourceField 확인 (간단 매핑)
            if (!mapping && col.sourceField) {
              // sourceField가 명시적으로 설정된 경우
              if (sourceItem[col.sourceField] !== undefined) {
                newItem[col.field] = sourceItem[col.sourceField];
              }
              continue;
            }

            if (!mapping) {
              // 매핑 없으면 소스에서 동일 필드명으로 복사
              if (sourceItem[col.field] !== undefined) {
                newItem[col.field] = sourceItem[col.field];
              }
              continue;
            }

            // 2. valueMapping이 있는 경우 (고급 매핑)
            switch (mapping.type) {
              case "source":
                // 소스 테이블에서 복사
                const srcField = mapping.sourceField || col.sourceField || col.field;
                if (sourceItem[srcField] !== undefined) {
                  newItem[col.field] = sourceItem[srcField];
                }
                break;

              case "manual":
                // 사용자 입력 (빈 값 또는 기본값)
                newItem[col.field] = col.defaultValue ?? undefined;
                break;

              case "internal":
                // formData에서 값 가져오기
                if (mapping.internalField) {
                  newItem[col.field] = formData[mapping.internalField];
                }
                break;

              case "external":
                // 외부 테이블에서 조회
                if (mapping.externalRef) {
                  const { tableName, valueColumn, joinConditions } = mapping.externalRef;
                  const value = await fetchExternalValue(
                    tableName,
                    valueColumn,
                    joinConditions,
                    { ...sourceItem, ...newItem }, // rowData
                    sourceItem, // sourceData
                    formData,
                  );
                  if (value !== undefined) {
                    newItem[col.field] = value;
                  }
                }
                break;
            }

            // 기본값 적용
            if (col.defaultValue !== undefined && newItem[col.field] === undefined) {
              newItem[col.field] = col.defaultValue;
            }

            // 부모에서 값 받기 (receiveFromParent)
            if (col.receiveFromParent) {
              const parentField = col.parentFieldName || col.field;
              if (formData[parentField] !== undefined) {
                newItem[col.field] = formData[parentField];
              }
            }
          }

          return newItem;
        }),
      );

      // 카테고리 타입 컬럼의 코드 → 라벨 변환 (categoryOptionsMap 활용)
      const categoryFields = (tableConfig.columns || [])
        .filter((col) => col.type === "category" || col.type === "select")
        .reduce<Record<string, Record<string, string>>>((acc, col) => {
          const options = categoryOptionsMap[col.field];
          if (options && options.length > 0) {
            acc[col.field] = {};
            for (const opt of options) {
              acc[col.field][opt.value] = opt.label;
            }
          }
          return acc;
        }, {});

      // receiveFromParent / internal 매핑으로 넘어온 값도 포함하여 변환
      if (Object.keys(categoryFields).length > 0) {
        for (const item of mappedItems) {
          for (const [field, codeToLabel] of Object.entries(categoryFields)) {
            const val = item[field];
            if (typeof val === "string" && codeToLabel[val]) {
              item[field] = codeToLabel[val];
            }
          }
        }
      }

      // categoryOptionsMap에 없는 경우 API fallback
      const unresolvedCodes = new Set<string>();
      const categoryColFields = new Set(
        (tableConfig.columns || []).filter((col) => col.type === "category").map((col) => col.field),
      );
      for (const item of mappedItems) {
        for (const field of categoryColFields) {
          const val = item[field];
          if (typeof val === "string" && val && !categoryFields[field]?.[val] && val !== item[field]) {
            unresolvedCodes.add(val);
          }
        }
      }

      if (unresolvedCodes.size > 0) {
        try {
          const labelResp = await apiClient.post("/table-categories/labels-by-codes", {
            valueCodes: Array.from(unresolvedCodes),
          });
          if (labelResp.data?.success && labelResp.data.data) {
            const labelData = labelResp.data.data as Record<string, string>;
            for (const item of mappedItems) {
              for (const field of categoryColFields) {
                const val = item[field];
                if (typeof val === "string" && labelData[val]) {
                  item[field] = labelData[val];
                }
              }
            }
          }
        } catch {
          // 변환 실패 시 코드 유지
        }
      }

      // 계산 필드 업데이트
      const calculatedItems = calculateAll(mappedItems);

      // 기존 데이터에 추가
      const newData = [...tableData, ...calculatedItems];
      handleDataChange(newData);
    },
    [tableConfig.columns, formData, tableData, calculateAll, handleDataChange, activeDataSources, categoryOptionsMap],
  );

  // 컬럼 모드/조회 옵션 변경 핸들러
  const handleDataSourceChange = useCallback(
    async (columnField: string, optionId: string) => {
      setActiveDataSources((prev) => ({
        ...prev,
        [columnField]: optionId,
      }));

      // 해당 컬럼의 모든 행 데이터 재조회
      const column = tableConfig.columns.find((col) => col.field === columnField);

      // lookup 설정이 있는 경우 (새로운 조회 기능)
      if (column?.lookup?.enabled && column.lookup.options) {
        const selectedOption = column.lookup.options.find((opt) => opt.id === optionId);
        if (!selectedOption) return;

        // sameTable 타입: 현재 행의 소스 데이터에서 값 복사 (외부 조회 필요 없음)
        if (selectedOption.type === "sameTable") {
          const updatedData = tableData.map((row) => {
            // sourceField에서 값을 가져와 해당 컬럼에 복사
            // row에 _sourceData가 있으면 거기서, 없으면 row 자체에서 가져옴
            const sourceData = row._sourceData || row;
            const newValue = sourceData[selectedOption.valueColumn] ?? row[columnField];
            return { ...row, [columnField]: newValue };
          });

          const calculatedData = calculateAll(updatedData);
          handleDataChange(calculatedData);
          return;
        }

        // 모든 행에 대해 새 값 조회
        const updatedData = await Promise.all(
          tableData.map(async (row) => {
            let newValue: any = row[columnField];

            // 조인 조건 구성 (4가지 소스 타입 지원)
            const joinConditions: TableJoinCondition[] = selectedOption.conditions.map((cond) => {
              // sourceType 매핑
              let sourceType: "row" | "sourceData" | "formData" | "externalTable";
              if (cond.sourceType === "currentRow") {
                sourceType = "row";
              } else if (cond.sourceType === "sourceTable") {
                sourceType = "sourceData";
              } else if (cond.sourceType === "externalTable") {
                sourceType = "externalTable";
              } else {
                sourceType = "formData";
              }

              return {
                sourceType,
                sourceField: cond.sourceField,
                targetColumn: cond.targetColumn,
                // 외부 테이블 조회 설정
                externalLookup: cond.externalLookup,
                // 값 변환 설정 전달 (레거시 호환)
                transform: cond.transform?.enabled
                  ? {
                      tableName: cond.transform.tableName,
                      matchColumn: cond.transform.matchColumn,
                      resultColumn: cond.transform.resultColumn,
                    }
                  : undefined,
              };
            });

            // 외부 테이블에서 값 조회 (_sourceData 전달)
            const sourceData = row._sourceData || row;
            const value = await fetchExternalValue(
              selectedOption.tableName,
              selectedOption.valueColumn,
              joinConditions,
              row,
              sourceData,
              formData,
            );

            if (value !== undefined) {
              newValue = value;
            }

            return { ...row, [columnField]: newValue };
          }),
        );

        // 계산 필드 업데이트
        const calculatedData = calculateAll(updatedData);
        handleDataChange(calculatedData);
        return;
      }

      // 기존 columnModes 처리 (레거시 호환)
      if (!column?.columnModes) return;

      const selectedMode = column.columnModes.find((mode) => mode.id === optionId);
      if (!selectedMode) return;

      // 모든 행에 대해 새 값 조회
      const updatedData = await Promise.all(
        tableData.map(async (row) => {
          const mapping = selectedMode.valueMapping;
          let newValue: any = row[columnField];
          const sourceData = row._sourceData || row;

          if (mapping.type === "external" && mapping.externalRef) {
            const { tableName, valueColumn, joinConditions } = mapping.externalRef;
            const value = await fetchExternalValue(tableName, valueColumn, joinConditions, row, sourceData, formData);
            if (value !== undefined) {
              newValue = value;
            }
          } else if (mapping.type === "source" && mapping.sourceField) {
            newValue = row[mapping.sourceField];
          } else if (mapping.type === "internal" && mapping.internalField) {
            newValue = formData[mapping.internalField];
          }

          return { ...row, [columnField]: newValue };
        }),
      );

      // 계산 필드 업데이트
      const calculatedData = calculateAll(updatedData);
      handleDataChange(calculatedData);
    },
    [tableConfig.columns, tableData, formData, calculateAll, handleDataChange],
  );

  // 소스 테이블 정보
  const { source, filters, uiConfig } = tableConfig;
  const sourceTable = source.tableName;
  const sourceColumns = source.displayColumns;
  const sourceSearchFields = source.searchColumns;
  // 컬럼 라벨: source.columnLabels가 있으면 우선 사용, 없으면 동적 로드된 라벨 사용
  const columnLabels = useMemo(() => {
    const configLabels = source.columnLabels || {};
    // 설정된 라벨이 있으면 설정 우선, 없으면 API에서 로드한 라벨 사용
    return { ...sourceColumnLabels, ...configLabels };
  }, [source.columnLabels, sourceColumnLabels]);
  const modalTitle = uiConfig?.modalTitle || "항목 검색 및 선택";
  const multiSelect = uiConfig?.multiSelect ?? true;

  // 버튼 표시 설정 (두 버튼 동시 표시 가능)
  // showSearchButton/showAddRowButton 신규 필드 우선, 레거시 addButtonType은 신규 필드 없을 때만 참고
  const showSearchButton = uiConfig?.showSearchButton ?? true;
  const showAddRowButton = uiConfig?.showAddRowButton ?? false;
  const searchButtonText = uiConfig?.searchButtonText || uiConfig?.addButtonText || "품목 검색";
  const addRowButtonText = uiConfig?.addRowButtonText || "직접 입력";

  // 기본 필터 조건 생성 (사전 필터만 - 모달 필터는 ItemSelectionModal에서 처리)
  // 연산자별로 특수 키 형식 사용: column__operator (예: division__in)
  const baseFilterCondition: Record<string, any> = useMemo(() => {
    const condition: Record<string, any> = {};
    if (filters?.preFilters) {
      for (const filter of filters.preFilters) {
        if (!filter.column || filter.value === undefined || filter.value === "") continue;
        
        const operator = filter.operator || "=";
        
        if (operator === "=") {
          // 기본 등호 연산자는 그대로 전달
          condition[filter.column] = filter.value;
        } else {
          // 다른 연산자는 특수 키 형식 사용: column__operator
          condition[`${filter.column}__${operator}`] = filter.value;
        }
      }
    }
    // console.log("[TableSectionRenderer] baseFilterCondition:", condition, "preFilters:", filters?.preFilters);
    return condition;
  }, [filters?.preFilters]);

  // 조건부 테이블용 필터 조건 생성 (선택된 조건값으로 소스 테이블 필터링)
  const conditionalFilterCondition = useMemo(() => {
    const filter = { ...baseFilterCondition };

    // 조건부 테이블의 소스 필터 설정이 있고, 모달에서 선택된 조건이 있으면 적용
    // __like 연산자로 ILIKE 포함 검색 (쉼표 구분 다중값 매칭 지원)
    if (conditionalConfig?.sourceFilter?.enabled && modalCondition) {
      filter[`${conditionalConfig.sourceFilter.filterColumn}__like`] = modalCondition;
    }

    return filter;
  }, [baseFilterCondition, conditionalConfig?.sourceFilter, modalCondition]);

  // 모달 필터 설정을 ItemSelectionModal에 전달할 형식으로 변환
  const modalFiltersForModal = useMemo(() => {
    if (!filters?.modalFilters) return [];
    return filters.modalFilters.map((filter) => ({
      column: filter.column,
      label: filter.label || filter.column,
      // category 타입을 select로 변환 (ModalFilterConfig 호환)
      type: filter.type === "category" ? ("select" as const) : (filter.type as "text" | "select"),
      options: filter.options,
      categoryRef: filter.categoryRef,
      defaultValue: filter.defaultValue,
    }));
  }, [filters?.modalFilters]);

  // ============================================
  // 조건부 테이블 관련 핸들러
  // ============================================

  // 조건부 테이블: 조건 체크박스 토글
  const handleConditionToggle = useCallback(
    (conditionValue: string, checked: boolean) => {
      setSelectedConditions((prev) => {
        if (checked) {
          const newConditions = [...prev, conditionValue];
          // 첫 번째 조건 선택 시 해당 탭 활성화
          if (prev.length === 0) {
            setActiveConditionTab(conditionValue);
          }
          return newConditions;
        } else {
          const newConditions = prev.filter((c) => c !== conditionValue);
          // 현재 활성 탭이 제거된 경우 다른 탭으로 전환
          if (activeConditionTab === conditionValue && newConditions.length > 0) {
            setActiveConditionTab(newConditions[0]);
          }
          return newConditions;
        }
      });
    },
    [activeConditionTab],
  );

  // 조건부 테이블: 조건별 데이터 변경
  const handleConditionalDataChange = useCallback(
    (conditionValue: string, newData: any[]) => {
      setConditionalTableData((prev) => ({
        ...prev,
        [conditionValue]: newData,
      }));

      // 부모에게 조건별 데이터 변경 알림
      if (onConditionalTableDataChange) {
        onConditionalTableDataChange(conditionValue, newData);
      }

      // 전체 데이터를 flat array로 변환하여 onTableDataChange 호출
      // (저장 시 조건 컬럼 값이 자동으로 추가됨)
      const conditionColumn = conditionalConfig?.conditionColumn;
      const allData: any[] = [];

      // 현재 변경된 조건의 데이터 업데이트
      const updatedConditionalData = { ...conditionalTableData, [conditionValue]: newData };

      for (const [condition, data] of Object.entries(updatedConditionalData)) {
        for (const row of data) {
          allData.push({
            ...row,
            ...(conditionColumn ? { [conditionColumn]: condition } : {}),
          });
        }
      }

      onTableDataChange(allData);
    },
    [conditionalTableData, conditionalConfig?.conditionColumn, onConditionalTableDataChange, onTableDataChange],
  );

  // 조건부 테이블: 조건별 행 변경
  const handleConditionalRowChange = useCallback(
    (conditionValue: string, index: number, newRow: any) => {
      const calculatedRow = calculateRow(newRow);
      const currentData = conditionalTableData[conditionValue] || [];
      const newData = [...currentData];
      newData[index] = calculatedRow;
      handleConditionalDataChange(conditionValue, newData);
    },
    [conditionalTableData, calculateRow, handleConditionalDataChange],
  );

  // 조건부 테이블: 조건별 행 삭제
  const handleConditionalRowDelete = useCallback(
    (conditionValue: string, index: number) => {
      const currentData = conditionalTableData[conditionValue] || [];
      const newData = currentData.filter((_, i) => i !== index);
      handleConditionalDataChange(conditionValue, newData);
    },
    [conditionalTableData, handleConditionalDataChange],
  );

  // 조건부 테이블: 조건별 선택 행 일괄 삭제
  const handleConditionalBulkDelete = useCallback(
    (conditionValue: string) => {
      const selected = conditionalSelectedRows[conditionValue] || new Set();
      if (selected.size === 0) return;

      const currentData = conditionalTableData[conditionValue] || [];
      const newData = currentData.filter((_, index) => !selected.has(index));
      handleConditionalDataChange(conditionValue, newData);

      // 선택 상태 초기화
      setConditionalSelectedRows((prev) => ({
        ...prev,
        [conditionValue]: new Set(),
      }));
    },
    [conditionalTableData, conditionalSelectedRows, handleConditionalDataChange],
  );

  // 조건부 테이블: 아이템 추가 (특정 조건에)
  const handleConditionalAddItems = useCallback(
    async (items: any[]) => {
      if (!modalCondition) return;

      // autoFillColumns 매핑 빌드: targetField → sourceColumn
      const autoFillMap: Record<string, string> = {};
      for (const col of tableConfig.columns) {
        const dso = (col as any).dynamicSelectOptions;
        if (dso?.sourceField) {
          autoFillMap[col.field] = dso.sourceField;
        }
        if (dso?.rowSelectionMode?.autoFillColumns) {
          for (const af of dso.rowSelectionMode.autoFillColumns) {
            autoFillMap[af.targetField] = af.sourceColumn;
          }
        }
      }
      // referenceDisplay에서도 매핑 추가
      for (const col of tableConfig.columns) {
        if (!autoFillMap[col.field]) {
          const refDisplay = (col as any).saveConfig?.referenceDisplay;
          if (refDisplay?.sourceColumn) {
            autoFillMap[col.field] = refDisplay.sourceColumn;
          }
        }
      }

      const mappedItems = await Promise.all(
        items.map(async (sourceItem) => {
          const newItem: any = {};

          for (const col of tableConfig.columns) {
            const mapping = col.valueMapping;

            // autoFill 또는 referenceDisplay 매핑이 있으면 우선 사용
            const autoFillSource = autoFillMap[col.field];
            if (!mapping && autoFillSource) {
              if (sourceItem[autoFillSource] !== undefined) {
                newItem[col.field] = sourceItem[autoFillSource];
              }
              continue;
            }

            // 소스 필드에서 값 복사 (기본)
            if (!mapping) {
              const sourceField = col.sourceField || col.field;
              if (sourceItem[sourceField] !== undefined) {
                newItem[col.field] = sourceItem[sourceField];
              }
              continue;
            }

            // valueMapping 처리
            if (mapping.type === "source" && mapping.sourceField) {
              const value = sourceItem[mapping.sourceField];
              if (value !== undefined) {
                newItem[col.field] = value;
              }
            } else if (mapping.type === "manual") {
              newItem[col.field] = col.defaultValue || "";
            } else if (mapping.type === "internal" && mapping.internalField) {
              newItem[col.field] = formData[mapping.internalField];
            }
          }

          // 원본 소스 데이터 보존
          newItem._sourceData = sourceItem;

          return newItem;
        }),
      );

      // 카테고리 타입 컬럼의 코드 → 라벨 변환 (categoryOptionsMap 활용)
      const categoryFields = (tableConfig.columns || [])
        .filter((col) => col.type === "category" || col.type === "select")
        .reduce<Record<string, Record<string, string>>>((acc, col) => {
          const options = categoryOptionsMap[col.field];
          if (options && options.length > 0) {
            acc[col.field] = {};
            for (const opt of options) {
              acc[col.field][opt.value] = opt.label;
            }
          }
          return acc;
        }, {});

      if (Object.keys(categoryFields).length > 0) {
        for (const item of mappedItems) {
          for (const [field, codeToLabel] of Object.entries(categoryFields)) {
            const val = item[field];
            if (typeof val === "string" && codeToLabel[val]) {
              item[field] = codeToLabel[val];
            }
          }
        }
      }

      // 현재 조건의 데이터에 추가
      const currentData = conditionalTableData[modalCondition] || [];
      const newData = [...currentData, ...mappedItems];
      handleConditionalDataChange(modalCondition, newData);

      setModalOpen(false);
    },
    [modalCondition, tableConfig.columns, formData, conditionalTableData, handleConditionalDataChange],
  );

  // 조건부 테이블: 모달 열기 (특정 조건에 대해)
  const openConditionalModal = useCallback((conditionValue: string) => {
    setModalCondition(conditionValue);
    setModalOpen(true);
  }, []);

  // 조건부 테이블: 빈 행 추가 (addRow 모드에서 사용)
  const addEmptyRowToCondition = useCallback(
    (conditionValue: string) => {
      const newRow: Record<string, any> = {};

      // 각 컬럼의 기본값으로 빈 행 생성
      for (const col of tableConfig.columns) {
        if (col.defaultValue !== undefined) {
          newRow[col.field] = col.defaultValue;
        } else if (col.type === "number") {
          newRow[col.field] = 0;
        } else if (col.type === "checkbox") {
          newRow[col.field] = false;
        } else {
          newRow[col.field] = "";
        }
      }

      // 조건 컬럼에 현재 조건 값 설정
      if (conditionalConfig?.conditionColumn) {
        newRow[conditionalConfig.conditionColumn] = conditionValue;
      }

      // 현재 조건의 데이터에 추가
      const currentData = conditionalTableData[conditionValue] || [];
      const newData = [...currentData, newRow];
      handleConditionalDataChange(conditionValue, newData);
    },
    [tableConfig.columns, conditionalConfig?.conditionColumn, conditionalTableData, handleConditionalDataChange],
  );

  // 검색 버튼 클릭 핸들러
  const handleSearchButtonClick = useCallback(
    (conditionValue: string) => {
      openConditionalModal(conditionValue);
    },
    [openConditionalModal],
  );

  // 행 추가 버튼 클릭 핸들러
  const handleAddRowButtonClick = useCallback(
    (conditionValue: string) => {
      addEmptyRowToCondition(conditionValue);
    },
    [addEmptyRowToCondition],
  );

  // 조건부 테이블: 초기 데이터를 그룹핑하여 표시하는 헬퍼
  const applyConditionalGrouping = useCallback((data: any[]) => {
    const conditionColumn = conditionalConfig?.conditionColumn;
    console.warn(`[applyConditionalGrouping] 호출됨:`, {
      conditionColumn,
      dataLength: data.length,
      sampleConditions: data.slice(0, 3).map(r => r[conditionColumn || ""]),
    });
    if (!conditionColumn || data.length === 0) return;

    const grouped: ConditionalTableData = {};
    const conditions = new Set<string>();

    for (const row of data) {
      const conditionValue = row[conditionColumn] || "";
      if (conditionValue) {
        if (!grouped[conditionValue]) {
          grouped[conditionValue] = [];
        }
        grouped[conditionValue].push(row);
        conditions.add(conditionValue);
      }
    }

    setConditionalTableData(grouped);
    setSelectedConditions(Array.from(conditions));

    if (conditions.size > 0) {
      setActiveConditionTab(Array.from(conditions)[0]);
    }

    initialDataLoadedRef.current = true;
  }, [conditionalConfig?.conditionColumn]);

  // 조건부 테이블: 초기 데이터 로드 (수정 모드)
  useEffect(() => {
    if (!isConditionalMode) return;
    if (initialDataLoadedRef.current) return;

    const initialData =
      formData[`_tableSection_${sectionId}`] ||
      formData[`__tableSection_${sectionId}`];

    console.warn(`[TableSectionRenderer] 초기 데이터 로드 체크:`, {
      sectionId,
      hasUnderscoreData: !!formData[`_tableSection_${sectionId}`],
      hasDoubleUnderscoreData: !!formData[`__tableSection_${sectionId}`],
      dataLength: Array.isArray(initialData) ? initialData.length : "not array",
      initialDataLoaded: initialDataLoadedRef.current,
    });

    if (Array.isArray(initialData) && initialData.length > 0) {
      applyConditionalGrouping(initialData);
    }
  }, [isConditionalMode, sectionId, formData, applyConditionalGrouping]);

  // 조건부 테이블: formData에 데이터가 없으면 editConfig 기반으로 직접 API 로드
  const selfLoadAttemptedRef = React.useRef(false);
  useEffect(() => {
    if (!isConditionalMode) return;
    if (initialDataLoadedRef.current) return;
    if (selfLoadAttemptedRef.current) return;

    const editConfig = (tableConfig as any).editConfig;
    const saveConfig = tableConfig.saveConfig;
    const linkColumn = editConfig?.linkColumn;
    const targetTable = saveConfig?.targetTable;

    console.warn(`[TableSectionRenderer] 자체 로드 체크:`, {
      sectionId,
      hasEditConfig: !!editConfig,
      linkColumn,
      targetTable,
      masterField: linkColumn?.masterField,
      masterValue: linkColumn?.masterField ? formData[linkColumn.masterField] : "N/A",
      formDataKeys: Object.keys(formData).slice(0, 15),
      initialDataLoaded: initialDataLoadedRef.current,
      selfLoadAttempted: selfLoadAttemptedRef.current,
      existingTableData_: !!formData[`_tableSection_${sectionId}`],
      existingTableData__: !!formData[`__tableSection_${sectionId}`],
    });

    if (!linkColumn?.masterField || !linkColumn?.detailField || !targetTable) {
      console.warn(`[TableSectionRenderer] 자체 로드 스킵: linkColumn/targetTable 미설정`);
      return;
    }

    const masterValue = formData[linkColumn.masterField];
    if (!masterValue) {
      console.warn(`[TableSectionRenderer] 자체 로드 대기: masterField=${linkColumn.masterField} 값 없음`);
      return;
    }

    // formData에 테이블 섹션 데이터가 이미 있으면 해당 데이터 사용
    const existingData =
      formData[`_tableSection_${sectionId}`] ||
      formData[`__tableSection_${sectionId}`];
    if (Array.isArray(existingData) && existingData.length > 0) {
      console.warn(`[TableSectionRenderer] 기존 데이터 발견, applyConditionalGrouping 호출: ${existingData.length}건`);
      applyConditionalGrouping(existingData);
      return;
    }

    selfLoadAttemptedRef.current = true;
    console.warn(`[TableSectionRenderer] 자체 API 로드 시작: ${targetTable}, ${linkColumn.detailField}=${masterValue}`);

    const loadDetailData = async () => {
      try {
        const response = await apiClient.post(`/table-management/tables/${targetTable}/data`, {
          search: {
            [linkColumn.detailField]: { value: masterValue, operator: "equals" },
          },
          page: 1,
          size: 1000,
          autoFilter: { enabled: true },
        });

        if (response.data?.success) {
          let items: any[] = [];
          const data = response.data.data;
          if (Array.isArray(data)) items = data;
          else if (data?.items && Array.isArray(data.items)) items = data.items;
          else if (data?.rows && Array.isArray(data.rows)) items = data.rows;
          else if (data?.data && Array.isArray(data.data)) items = data.data;

          console.warn(`[TableSectionRenderer] 자체 데이터 로드 완료: ${items.length}건`);

          if (items.length > 0) {
            applyConditionalGrouping(items);
          }
        } else {
          console.warn(`[TableSectionRenderer] API 응답 실패:`, response.data);
        }
      } catch (error) {
        console.error(`[TableSectionRenderer] 자체 데이터 로드 실패:`, error);
      }
    };

    loadDetailData();
  }, [isConditionalMode, sectionId, formData, tableConfig, applyConditionalGrouping]);

  // 조건부 테이블: 전체 항목 수 계산
  const totalConditionalItems = useMemo(() => {
    return Object.values(conditionalTableData).reduce((sum, data) => sum + data.length, 0);
  }, [conditionalTableData]);

  // 조건부 테이블: 모달 중복 체크용 alreadySelected 구성
  // DB에서 로드된 항목은 _sourceData가 없으므로 참조 ID 필드를 기반으로 _sourceData를 생성
  const conditionalAlreadySelected = useMemo(() => {
    const allItems = Object.values(conditionalTableData).flat();
    if (allItems.length === 0) return allItems;

    // 참조 ID 필드 탐색 (소스 테이블의 id를 저장하는 디테일 테이블 컬럼)
    const referenceIdField = (tableConfig.columns || [])
      .map((col) => col.saveConfig?.referenceDisplay?.referenceIdField)
      .find(Boolean)
      || (tableConfig.columns || [])
        .map((col) => (col as any).dynamicSelectOptions?.rowSelectionMode?.targetIdField)
        .find(Boolean);

    // sourceField 매핑 수집 (소스 테이블 필드 → 디테일 테이블 필드)
    const sourceFieldMap: Record<string, string> = {};
    for (const col of tableConfig.columns || []) {
      if (col.sourceField && col.sourceField !== col.field) {
        sourceFieldMap[col.sourceField] = col.field;
      }
    }

    return allItems.map((item) => {
      if (item._sourceData) return item;

      // DB에서 로드된 항목: _sourceData 재구성
      const sourceData: any = {};

      // 참조 ID 필드가 있으면 소스 테이블의 id로 매핑
      if (referenceIdField && item[referenceIdField] !== undefined) {
        sourceData.id = item[referenceIdField];
      }

      // sourceField 매핑을 역으로 적용 (디테일 필드 → 소스 필드)
      for (const [srcField, detailField] of Object.entries(sourceFieldMap)) {
        if (item[detailField] !== undefined) {
          sourceData[srcField] = item[detailField];
        }
      }

      // 디테일 테이블의 필드도 소스 데이터에 포함 (동일 필드명인 경우)
      for (const col of tableConfig.columns || []) {
        if (!col.sourceField && item[col.field] !== undefined) {
          sourceData[col.field] = item[col.field];
        }
      }

      return Object.keys(sourceData).length > 0
        ? { ...item, _sourceData: sourceData }
        : item;
    });
  }, [conditionalTableData, tableConfig.columns]);

  // 일반 테이블: 모달 중복 체크용 alreadySelected 구성 (DB 로드 항목 대응)
  const normalAlreadySelected = useMemo(() => {
    if (tableData.length === 0) return tableData;

    const referenceIdField = (tableConfig.columns || [])
      .map((col) => col.saveConfig?.referenceDisplay?.referenceIdField)
      .find(Boolean)
      || (tableConfig.columns || [])
        .map((col) => (col as any).dynamicSelectOptions?.rowSelectionMode?.targetIdField)
        .find(Boolean);

    const sourceFieldMap: Record<string, string> = {};
    for (const col of tableConfig.columns || []) {
      if (col.sourceField && col.sourceField !== col.field) {
        sourceFieldMap[col.sourceField] = col.field;
      }
    }

    return tableData.map((item) => {
      if (item._sourceData) return item;

      const sourceData: any = {};
      if (referenceIdField && item[referenceIdField] !== undefined) {
        sourceData.id = item[referenceIdField];
      }
      for (const [srcField, detailField] of Object.entries(sourceFieldMap)) {
        if (item[detailField] !== undefined) {
          sourceData[srcField] = item[detailField];
        }
      }
      for (const col of tableConfig.columns || []) {
        if (!col.sourceField && item[col.field] !== undefined) {
          sourceData[col.field] = item[col.field];
        }
      }

      return Object.keys(sourceData).length > 0
        ? { ...item, _sourceData: sourceData }
        : item;
    });
  }, [tableData, tableConfig.columns]);

  // ============================================
  // 조건부 테이블 렌더링
  // ============================================
  if (isConditionalMode && conditionalConfig) {
    const { triggerType } = conditionalConfig;

    // 정적 옵션과 동적 옵션 병합 (동적 옵션이 있으면 우선 사용)
    // 빈 value를 가진 옵션은 제외 (Select.Item은 빈 문자열 value를 허용하지 않음)
    const effectiveOptions = (
      conditionalConfig.optionSource?.enabled && dynamicOptions.length > 0
        ? dynamicOptions
        : conditionalConfig.options || []
    ).filter((opt) => opt.value && opt.value.trim() !== "");

    // 로딩 중이면 로딩 표시
    if (dynamicOptionsLoading) {
      return (
        <div className={cn("space-y-4", className)}>
          <div className="text-muted-foreground flex items-center justify-center py-8 text-sm">
            <div className="flex items-center gap-2">
              <div className="border-primary h-4 w-4 animate-spin rounded-full border-2 border-t-transparent" />
              조건 옵션을 불러오는 중...
            </div>
          </div>
        </div>
      );
    }

    return (
      <div className={cn("space-y-4", className)}>
        {/* 조건 선택 UI */}
        {triggerType === "checkbox" && (
          <div className="space-y-3">
            <div className="flex flex-wrap gap-3">
              {effectiveOptions.map((option) => (
                <label
                  key={option.id}
                  className="hover:bg-muted/50 flex cursor-pointer items-center gap-2 rounded-lg border px-3 py-2 transition-colors"
                >
                  <Checkbox
                    checked={selectedConditions.includes(option.value)}
                    onCheckedChange={(checked) => handleConditionToggle(option.value, !!checked)}
                  />
                  <span className="text-sm">{option.label}</span>
                  {conditionalTableData[option.value]?.length > 0 && (
                    <Badge variant="secondary" className="ml-1 text-xs">
                      {conditionalTableData[option.value].length}
                    </Badge>
                  )}
                </label>
              ))}
            </div>

            {selectedConditions.length > 0 && (
              <div className="text-muted-foreground text-xs">
                {selectedConditions.length}개 유형 선택됨, 총 {totalConditionalItems}개 항목
              </div>
            )}
          </div>
        )}

        {triggerType === "dropdown" && (
          <div className="flex items-center gap-2">
            <span className="text-sm">유형 선택:</span>
            <Select
              value={selectedConditions[0] || ""}
              onValueChange={(value) => {
                setSelectedConditions([value]);
                setActiveConditionTab(value);
              }}
            >
              <SelectTrigger className="h-9 w-[200px]">
                <SelectValue placeholder="유형을 선택하세요" />
              </SelectTrigger>
              <SelectContent>
                {effectiveOptions.map((option) => (
                  <SelectItem key={option.id} value={option.value}>
                    {option.label}
                    {conditionalTableData[option.value]?.length > 0 &&
                      ` (${conditionalTableData[option.value].length})`}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        )}

        {/* 선택된 조건들의 테이블 (탭 형태) */}
        {selectedConditions.length > 0 && (
          <Tabs value={activeConditionTab} onValueChange={setActiveConditionTab} className="w-full">
            <TabsList className="w-full justify-start">
              {selectedConditions.map((conditionValue) => {
                const option = effectiveOptions.find((o) => o.value === conditionValue);
                const itemCount = conditionalTableData[conditionValue]?.length || 0;
                return (
                  <TabsTrigger key={conditionValue} value={conditionValue} className="gap-1.5">
                    {option?.label || conditionValue}
                    {itemCount > 0 && (
                      <Badge variant="outline" className="ml-1 h-5 px-1.5 text-xs">
                        {itemCount}
                      </Badge>
                    )}
                  </TabsTrigger>
                );
              })}
            </TabsList>

            {selectedConditions.map((conditionValue) => {
              const data = conditionalTableData[conditionValue] || [];
              const selected = conditionalSelectedRows[conditionValue] || new Set();

              return (
                <TabsContent key={conditionValue} value={conditionValue} className="mt-4 space-y-4">
                  {/* 테이블 상단 컨트롤 */}
                  <div className="flex items-center justify-between">
                    <div className="flex items-center gap-2">
                      <span className="text-muted-foreground text-sm">
                        {data.length > 0 && `${data.length}개 항목`}
                        {selected.size > 0 && ` (${selected.size}개 선택됨)`}
                      </span>
                      {columns.length > 0 && (
                        <Button
                          variant="outline"
                          size="sm"
                          onClick={() => setWidthTrigger((prev) => prev + 1)}
                          className="h-7 px-2 text-xs"
                          title={widthTrigger % 2 === 0 ? "내용에 맞게 자동 조정" : "균등 분배"}
                        >
                          {widthTrigger % 2 === 0 ? (
                            <>
                              <AlignJustify className="mr-1 h-3.5 w-3.5" />
                              자동 맞춤
                            </>
                          ) : (
                            <>
                              <Columns className="mr-1 h-3.5 w-3.5" />
                              균등 분배
                            </>
                          )}
                        </Button>
                      )}
                    </div>
                    <div className="flex gap-2">
                      {selected.size > 0 && (
                        <Button
                          variant="destructive"
                          size="sm"
                          onClick={() => handleConditionalBulkDelete(conditionValue)}
                          className="h-8 text-xs"
                        >
                          <Trash2 className="mr-1 h-3.5 w-3.5" />
                          선택 삭제 ({selected.size})
                        </Button>
                      )}
                      {showSearchButton && (
                        <Button onClick={() => handleSearchButtonClick(conditionValue)} className="h-8 text-xs">
                          <Search className="mr-2 h-4 w-4" />
                          {searchButtonText}
                        </Button>
                      )}
                      {showAddRowButton && (
                        <Button
                          variant="outline"
                          onClick={() => handleAddRowButtonClick(conditionValue)}
                          className="h-8 text-xs"
                        >
                          <Plus className="mr-2 h-4 w-4" />
                          {addRowButtonText}
                        </Button>
                      )}
                    </div>
                  </div>

                  {/* 테이블 */}
                  <RepeaterTable
                    columns={columns}
                    data={data}
                    onDataChange={(newData) => handleConditionalDataChange(conditionValue, newData)}
                    onRowChange={(index, newRow) => handleConditionalRowChange(conditionValue, index, newRow)}
                    onRowDelete={(index) => handleConditionalRowDelete(conditionValue, index)}
                    activeDataSources={activeDataSources}
                    onDataSourceChange={handleDataSourceChange}
                    selectedRows={selected}
                    onSelectionChange={(newSelected) => {
                      setConditionalSelectedRows((prev) => ({
                        ...prev,
                        [conditionValue]: newSelected,
                      }));
                    }}
                    categoryColumns={tableCategoryColumns}
                    categoryLabelMap={tableCategoryLabelMap}
                    equalizeWidthsTrigger={widthTrigger}
                  />
                </TabsContent>
              );
            })}
          </Tabs>
        )}

        {/* tabs 모드: 모든 옵션을 탭으로 표시 (선택 UI 없음) */}
        {triggerType === "tabs" && effectiveOptions.length > 0 && (
          <Tabs
            value={activeConditionTab || effectiveOptions[0]?.value}
            onValueChange={setActiveConditionTab}
            className="w-full"
          >
            <TabsList className="w-full justify-start">
              {effectiveOptions.map((option) => {
                const itemCount = conditionalTableData[option.value]?.length || 0;
                return (
                  <TabsTrigger key={option.id} value={option.value} className="gap-1.5">
                    {option.label}
                    {itemCount > 0 && (
                      <Badge variant="outline" className="ml-1 h-5 px-1.5 text-xs">
                        {itemCount}
                      </Badge>
                    )}
                  </TabsTrigger>
                );
              })}
            </TabsList>

            {effectiveOptions.map((option) => {
              const data = conditionalTableData[option.value] || [];
              const selected = conditionalSelectedRows[option.value] || new Set();

              return (
                <TabsContent key={option.id} value={option.value} className="mt-4 space-y-4">
                  <div className="flex items-center justify-between">
                    <div className="flex items-center gap-2">
                      <span className="text-muted-foreground text-sm">
                        {data.length > 0 && `${data.length}개 항목`}
                        {selected.size > 0 && ` (${selected.size}개 선택됨)`}
                      </span>
                    </div>
                    <div className="flex gap-2">
                      {selected.size > 0 && (
                        <Button
                          variant="destructive"
                          size="sm"
                          onClick={() => handleConditionalBulkDelete(option.value)}
                          className="h-8 text-xs"
                        >
                          <Trash2 className="mr-1 h-3.5 w-3.5" />
                          선택 삭제 ({selected.size})
                        </Button>
                      )}
                      {showSearchButton && (
                        <Button onClick={() => handleSearchButtonClick(option.value)} className="h-8 text-xs">
                          <Search className="mr-2 h-4 w-4" />
                          {searchButtonText}
                        </Button>
                      )}
                      {showAddRowButton && (
                        <Button
                          variant="outline"
                          onClick={() => handleAddRowButtonClick(option.value)}
                          className="h-8 text-xs"
                        >
                          <Plus className="mr-2 h-4 w-4" />
                          {addRowButtonText}
                        </Button>
                      )}
                    </div>
                  </div>

                  <RepeaterTable
                    columns={columns}
                    data={data}
                    onDataChange={(newData) => handleConditionalDataChange(option.value, newData)}
                    onRowChange={(index, newRow) => handleConditionalRowChange(option.value, index, newRow)}
                    onRowDelete={(index) => handleConditionalRowDelete(option.value, index)}
                    activeDataSources={activeDataSources}
                    onDataSourceChange={handleDataSourceChange}
                    selectedRows={selected}
                    onSelectionChange={(newSelected) => {
                      setConditionalSelectedRows((prev) => ({
                        ...prev,
                        [option.value]: newSelected,
                      }));
                    }}
                    equalizeWidthsTrigger={widthTrigger}
                    categoryColumns={tableCategoryColumns}
                    categoryLabelMap={tableCategoryLabelMap}
                  />
                </TabsContent>
              );
            })}
          </Tabs>
        )}

        {/* 조건이 선택되지 않은 경우 안내 메시지 (checkbox/dropdown 모드에서만) */}
        {selectedConditions.length === 0 && triggerType !== "tabs" && (
          <div className="flex flex-col items-center justify-center rounded-lg border border-dashed py-12 text-center">
            <p className="text-muted-foreground text-sm">
              {triggerType === "checkbox" ? "위에서 유형을 선택하여 검사항목을 추가하세요." : "유형을 선택하세요."}
            </p>
          </div>
        )}

        {/* 옵션이 없는 경우 안내 메시지 */}
        {effectiveOptions.length === 0 && (
          <div className="flex flex-col items-center justify-center rounded-lg border border-dashed py-12 text-center">
            <p className="text-muted-foreground text-sm">조건 옵션이 설정되지 않았습니다.</p>
          </div>
        )}

        {/* 항목 선택 모달 (조건부 테이블용) */}
        <ItemSelectionModal
          open={modalOpen}
          onOpenChange={setModalOpen}
          sourceTable={sourceTable}
          sourceColumns={sourceColumns}
          sourceSearchFields={sourceSearchFields}
          multiSelect={multiSelect}
          filterCondition={conditionalFilterCondition}
          modalTitle={`${effectiveOptions.find((o) => o.value === modalCondition)?.label || modalCondition} - ${modalTitle}`}
          alreadySelected={conditionalAlreadySelected}
          uniqueField={tableConfig.saveConfig?.uniqueField}
          onSelect={handleConditionalAddItems}
          columnLabels={columnLabels}
          modalFilters={modalFiltersForModal}
          categoryColumns={sourceCategoryColumns}
        />
      </div>
    );
  }

  // ============================================
  // 일반 테이블 렌더링 (기존 로직)
  // ============================================
  return (
    <div className={cn("space-y-4", className)}>
      {/* 추가 버튼 영역 */}
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <span className="text-muted-foreground text-sm">
            {tableData.length > 0 && `${tableData.length}개 항목`}
            {selectedRows.size > 0 && ` (${selectedRows.size}개 선택됨)`}
          </span>
          {columns.length > 0 && (
            <Button
              variant="outline"
              size="sm"
              onClick={() => setWidthTrigger((prev) => prev + 1)}
              className="h-7 px-2 text-xs"
              title={widthTrigger % 2 === 0 ? "내용에 맞게 자동 조정" : "균등 분배"}
            >
              {widthTrigger % 2 === 0 ? (
                <>
                  <AlignJustify className="mr-1 h-3.5 w-3.5" />
                  자동 맞춤
                </>
              ) : (
                <>
                  <Columns className="mr-1 h-3.5 w-3.5" />
                  균등 분배
                </>
              )}
            </Button>
          )}
        </div>
        <div className="flex gap-2">
          {selectedRows.size > 0 && (
            <Button variant="destructive" onClick={handleBulkDelete} className="h-8 text-xs sm:h-10 sm:text-sm">
              선택 삭제 ({selectedRows.size})
            </Button>
          )}
          {showSearchButton && (
            <Button onClick={() => setModalOpen(true)} className="h-8 text-xs sm:h-10 sm:text-sm">
              <Search className="mr-2 h-4 w-4" />
              {searchButtonText}
            </Button>
          )}
          {showAddRowButton && (
            <Button
              variant="outline"
              onClick={() => {
                // 빈 행 추가
                const newRow: Record<string, any> = {};
                for (const col of columns) {
                  if (col.defaultValue !== undefined) {
                    newRow[col.field] = col.defaultValue;
                  } else if (col.type === "number") {
                    newRow[col.field] = 0;
                  } else if (col.type === "checkbox") {
                    newRow[col.field] = false;
                  } else {
                    newRow[col.field] = "";
                  }
                }
                handleDataChange([...tableData, newRow]);
              }}
              className="h-8 text-xs sm:h-10 sm:text-sm"
            >
              <Plus className="mr-2 h-4 w-4" />
              {addRowButtonText}
            </Button>
          )}
        </div>
      </div>

      {/* Repeater 테이블 */}
      <RepeaterTable
        columns={columns}
        data={tableData}
        onDataChange={handleDataChange}
        onRowChange={handleRowChange}
        onRowDelete={handleRowDelete}
        activeDataSources={activeDataSources}
        onDataSourceChange={handleDataSourceChange}
        selectedRows={selectedRows}
        onSelectionChange={setSelectedRows}
        equalizeWidthsTrigger={widthTrigger}
        categoryColumns={tableCategoryColumns}
        categoryLabelMap={tableCategoryLabelMap}
      />

      {/* 항목 선택 모달 */}
      <ItemSelectionModal
        open={modalOpen}
        onOpenChange={setModalOpen}
        sourceTable={sourceTable}
        sourceColumns={sourceColumns}
        sourceSearchFields={sourceSearchFields}
        multiSelect={multiSelect}
        filterCondition={baseFilterCondition}
        modalTitle={modalTitle}
        alreadySelected={normalAlreadySelected}
        uniqueField={tableConfig.saveConfig?.uniqueField}
        onSelect={handleAddItems}
        columnLabels={columnLabels}
        modalFilters={modalFiltersForModal}
        categoryColumns={sourceCategoryColumns}
      />
    </div>
  );
}
