import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Loader2, AlertCircle, Check, X, Database, Code2 } from "lucide-react";
import { cn } from "@/lib/utils";
import { ComponentData, LayerCondition, LayerDefinition, DisplayRegion } from "@/types/screen-management";
import { getCodesByCategory, CodeItem } from "@/lib/api/codeManagement";
import { EntityReferenceAPI } from "@/lib/api/entityReference";
import { apiClient } from "@/lib/api/client";

// 통합 옵션 타입 (코드/엔티티/카테고리 모두 사용)
interface ConditionOption {
  value: string;
  label: string;
}

// 컴포넌트의 데이터 소스 타입
type DataSourceType = "code" | "entity" | "category" | "static" | "none";

interface LayerConditionPanelProps {
  layer: LayerDefinition;
  components: ComponentData[]; // 화면의 모든 컴포넌트
  baseLayerComponents?: ComponentData[]; // 기본 레이어 컴포넌트 (트리거 우선 대상)
  onUpdateCondition: (condition: LayerCondition | undefined) => void;
  onUpdateDisplayRegion: (region: DisplayRegion | undefined) => void;
  onClose?: () => void;
}

// 조건 연산자 옵션
const OPERATORS = [
  { value: "eq", label: "같음 (=)" },
  { value: "neq", label: "같지 않음 (≠)" },
  { value: "in", label: "포함 (in)" },
] as const;

type OperatorType = "eq" | "neq" | "in";

export const LayerConditionPanel: React.FC<LayerConditionPanelProps> = ({
  layer,
  components,
  baseLayerComponents,
  onUpdateCondition,
  onUpdateDisplayRegion,
  onClose,
}) => {
  // 조건 설정 상태
  const [targetComponentId, setTargetComponentId] = useState<string>(
    layer.condition?.targetComponentId || ""
  );
  const [operator, setOperator] = useState<OperatorType>(
    (layer.condition?.operator as OperatorType) || "eq"
  );
  const [value, setValue] = useState<string>(
    layer.condition?.value?.toString() || ""
  );
  const [multiValues, setMultiValues] = useState<string[]>(
    Array.isArray(layer.condition?.value) ? layer.condition.value : []
  );

  // 옵션 목록 로딩 상태 (코드/엔티티 통합)
  const [options, setOptions] = useState<ConditionOption[]>([]);
  const [isLoadingOptions, setIsLoadingOptions] = useState(false);
  const [loadError, setLoadError] = useState<string | null>(null);

  // 트리거 가능한 컴포넌트 필터링 (기본 레이어 우선, 셀렉트/라디오/코드 타입 등)
  const triggerableComponents = useMemo(() => {
    // 기본 레이어 컴포넌트가 전달된 경우 우선 사용, 없으면 전체 컴포넌트 사용
    const sourceComponents = baseLayerComponents && baseLayerComponents.length > 0 
      ? baseLayerComponents 
      : components;

    const isTriggerComponent = (comp: ComponentData): boolean => {
      const componentType = (comp.componentType || "").toLowerCase();
      const widgetType = ((comp as any).widgetType || "").toLowerCase();
      const webType = ((comp as any).webType || comp.componentConfig?.webType || "").toLowerCase();
      const inputType = ((comp as any).inputType || comp.componentConfig?.inputType || "").toLowerCase();
      const source = ((comp as any).source || comp.componentConfig?.source || "").toLowerCase();
      
      // 셀렉트, 라디오, 코드, 카테고리, 엔티티 타입 컴포넌트 허용
      const triggerTypes = ["select", "radio", "code", "checkbox", "toggle", "entity", "category"];
      return triggerTypes.some((type) => 
        componentType.includes(type) ||
        widgetType.includes(type) ||
        webType.includes(type) ||
        inputType.includes(type) ||
        source.includes(type)
      );
    };

    // 기본 레이어 컴포넌트 ID Set (그룹 구분용)
    const baseLayerIds = new Set(
      (baseLayerComponents || []).map((c) => c.id)
    );

    // 기본 레이어 트리거 컴포넌트
    const baseLayerTriggers = sourceComponents.filter(isTriggerComponent);

    // 기본 레이어가 아닌 다른 레이어의 트리거 컴포넌트도 포함 (하단에 표시)
    // 단, baseLayerComponents가 별도로 전달된 경우에만 나머지 컴포넌트 추가
    const otherLayerTriggers = baseLayerComponents && baseLayerComponents.length > 0
      ? components.filter((comp) => !baseLayerIds.has(comp.id) && isTriggerComponent(comp))
      : [];

    return { baseLayerTriggers, otherLayerTriggers };
  }, [components, baseLayerComponents]);

  // 선택된 컴포넌트 정보
  // 기본 레이어 + 현재 레이어 통합 컴포넌트 목록 (트리거 컴포넌트 검색용)
  const allAvailableComponents = useMemo(() => {
    const merged = [...(baseLayerComponents || []), ...components];
    // 중복 제거 (id 기준)
    const seen = new Set<string>();
    return merged.filter((c) => {
      if (seen.has(c.id)) return false;
      seen.add(c.id);
      return true;
    });
  }, [components, baseLayerComponents]);

  const selectedComponent = useMemo(() => {
    return allAvailableComponents.find((c) => c.id === targetComponentId);
  }, [allAvailableComponents, targetComponentId]);

  // 선택된 컴포넌트의 데이터 소스 정보 추출
  const dataSourceInfo = useMemo<{
    type: DataSourceType;
    codeCategory?: string;
    // 엔티티: 원본 테이블.컬럼 (entity-reference API용)
    originTable?: string;
    originColumn?: string;
    // 엔티티: 참조 대상 정보 (직접 조회용 폴백)
    referenceTable?: string;
    referenceColumn?: string;
    categoryTable?: string;
    categoryColumn?: string;
    staticOptions?: any[];
  }>(() => {
    if (!selectedComponent) return { type: "none" };
    
    const comp = selectedComponent as any;
    const config = comp.componentConfig || comp.webTypeConfig || {};
    const detailSettings = comp.detailSettings || {};
    
    // V2 컴포넌트: source 확인 (componentConfig, 상위 레벨, inputType 모두 체크)
    const source = config.source || comp.source;
    const inputType = config.inputType || comp.inputType;
    const webType = config.webType || comp.webType;
    
    // inputType/webType이 category면 카테고리로 판단
    if (inputType === "category" || webType === "category") {
      const categoryTable = config.categoryTable || comp.tableName || config.tableName;
      const categoryColumn = config.categoryColumn || comp.columnName || config.columnName;
      return { type: "category", categoryTable, categoryColumn };
    }
    
    // 1. 카테고리 소스 (V2: source === "category", category_values 테이블)
    if (source === "category") {
      const categoryTable = config.categoryTable || comp.tableName;
      const categoryColumn = config.categoryColumn || comp.columnName;
      return { type: "category", categoryTable, categoryColumn };
    }
    
    // 2. 코드 카테고리 확인 (V2: source === "code" + codeGroup, 기존: codeCategory)
    const codeCategory = 
      config.codeGroup ||  // V2 컴포넌트
      config.codeCategory ||
      comp.codeCategory ||
      detailSettings.codeCategory;
    
    if (source === "code" || codeCategory) {
      return { type: "code", codeCategory };
    }
    
    // 3. 엔티티 참조 확인 (V2: source === "entity")
    // entity-reference API는 원본 테이블.컬럼으로 호출해야 함
    // (백엔드에서 table_type_columns를 조회하여 참조 테이블/컬럼을 자동 매핑)
    const originTable = comp.tableName || config.tableName;
    const originColumn = comp.columnName || config.columnName;
    
    const referenceTable = 
      config.entityTable ||
      config.referenceTable ||
      comp.referenceTable ||
      detailSettings.referenceTable;
    
    const referenceColumn = 
      config.entityValueColumn ||
      config.referenceColumn ||
      comp.referenceColumn ||
      detailSettings.referenceColumn;
    
    if (source === "entity" || referenceTable) {
      return { type: "entity", originTable, originColumn, referenceTable, referenceColumn };
    }
    
    // 4. 정적 옵션 확인 (V2: source === "static" 또는 config.options 존재)
    const staticOptions = config.options;
    if (source === "static" || (staticOptions && Array.isArray(staticOptions) && staticOptions.length > 0)) {
      return { type: "static", staticOptions };
    }
    
    return { type: "none" };
  }, [selectedComponent]);

  // 의존성 안정화를 위한 직렬화 키
  const dataSourceKey = useMemo(() => {
    const { type, categoryTable, categoryColumn, codeCategory, originTable, originColumn, referenceTable, referenceColumn } = dataSourceInfo;
    return `${type}|${categoryTable || ""}|${categoryColumn || ""}|${codeCategory || ""}|${originTable || ""}|${originColumn || ""}|${referenceTable || ""}|${referenceColumn || ""}`;
  }, [dataSourceInfo]);

  // 컴포넌트 선택 시 옵션 목록 로드 (카테고리, 코드, 엔티티, 정적)
  useEffect(() => {
    // race condition 방지
    let cancelled = false;

    if (dataSourceInfo.type === "none") {
      setOptions([]);
      return;
    }

    // 정적 옵션은 즉시 설정
    if (dataSourceInfo.type === "static") {
      const staticOpts = dataSourceInfo.staticOptions || [];
      setOptions(staticOpts.map((opt: any) => ({
        value: opt.value || "",
        label: opt.label || opt.value || "",
      })));
      return;
    }

    const loadOptions = async () => {
      setIsLoadingOptions(true);
      setLoadError(null);
      
      try {
        if (dataSourceInfo.type === "category" && dataSourceInfo.categoryTable && dataSourceInfo.categoryColumn) {
          // 카테고리 값에서 옵션 로드 (category_values 테이블)
          console.log("[LayerCondition] 카테고리 옵션 로드:", dataSourceInfo.categoryTable, dataSourceInfo.categoryColumn);
          const response = await apiClient.get(
            `/table-categories/${dataSourceInfo.categoryTable}/${dataSourceInfo.categoryColumn}/values`
          );
          if (cancelled) return;
          const data = response.data;
          console.log("[LayerCondition] 카테고리 API 응답:", data?.success, "항목수:", Array.isArray(data?.data) ? data.data.length : 0);
          if (data.success && data.data) {
            // 트리 구조를 평탄화
            const flattenTree = (items: any[], depth = 0): ConditionOption[] => {
              const result: ConditionOption[] = [];
              for (const item of items) {
                const prefix = depth > 0 ? "  ".repeat(depth) : "";
                result.push({
                  value: item.valueCode || item.valueLabel,
                  label: `${prefix}${item.valueLabel}`,
                });
                if (item.children && item.children.length > 0) {
                  result.push(...flattenTree(item.children, depth + 1));
                }
              }
              return result;
            };
            const loadedOptions = flattenTree(Array.isArray(data.data) ? data.data : []);
            console.log("[LayerCondition] 카테고리 옵션 설정:", loadedOptions.length, "개");
            setOptions(loadedOptions);
          } else {
            setOptions([]);
          }
        } else if (dataSourceInfo.type === "code" && dataSourceInfo.codeCategory) {
          // 코드 카테고리에서 옵션 로드
          const codes = await getCodesByCategory(dataSourceInfo.codeCategory);
          if (cancelled) return;
          setOptions(codes.map((code) => ({
            value: code.code,
            label: code.name,
          })));
        } else if (dataSourceInfo.type === "entity") {
          // 엔티티 참조에서 옵션 로드
          let entityLoaded = false;
          
          if (dataSourceInfo.originTable && dataSourceInfo.originColumn) {
            try {
              const entityData = await EntityReferenceAPI.getEntityReferenceData(
                dataSourceInfo.originTable,
                dataSourceInfo.originColumn,
                { limit: 100 }
              );
              if (cancelled) return;
              setOptions(entityData.options.map((opt) => ({
                value: opt.value,
                label: opt.label,
              })));
              entityLoaded = true;
            } catch {
              console.warn("원본 테이블.컬럼으로 엔티티 조회 실패, 직접 참조로 폴백");
            }
          }
          
          // 폴백: 참조 테이블에서 직접 조회
          if (!entityLoaded && dataSourceInfo.referenceTable) {
            try {
              const refColumn = dataSourceInfo.referenceColumn || "id";
              const entityData = await EntityReferenceAPI.getEntityReferenceData(
                dataSourceInfo.referenceTable,
                refColumn,
                { limit: 100 }
              );
              if (cancelled) return;
              setOptions(entityData.options.map((opt) => ({
                value: opt.value,
                label: opt.label,
              })));
              entityLoaded = true;
            } catch {
              console.warn("직접 참조 테이블로도 엔티티 조회 실패");
            }
          }
          
          if (!entityLoaded && !cancelled) {
            setOptions([]);
          }
        } else {
          if (!cancelled) setOptions([]);
        }
      } catch (error: any) {
        if (!cancelled) {
          console.error("옵션 목록 로드 실패:", error);
          setLoadError(error.message || "옵션 목록을 불러올 수 없습니다.");
          setOptions([]);
        }
      } finally {
        if (!cancelled) {
          setIsLoadingOptions(false);
        }
      }
    };

    loadOptions();

    return () => {
      cancelled = true;
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [dataSourceKey]);

  // 조건 저장
  const handleSave = useCallback(() => {
    if (!targetComponentId) {
      return;
    }

    const condition: LayerCondition = {
      targetComponentId,
      operator,
      value: operator === "in" ? multiValues : value,
    };

    onUpdateCondition(condition);
    onClose?.();
  }, [targetComponentId, operator, value, multiValues, onUpdateCondition, onClose]);

  // 조건 삭제
  const handleClear = useCallback(() => {
    onUpdateCondition(undefined);
    setTargetComponentId("");
    setOperator("eq");
    setValue("");
    setMultiValues([]);
    onClose?.();
  }, [onUpdateCondition, onClose]);

  // in 연산자용 다중 값 토글
  const toggleMultiValue = useCallback((val: string) => {
    setMultiValues((prev) => 
      prev.includes(val) 
        ? prev.filter((v) => v !== val) 
        : [...prev, val]
    );
  }, []);

  // 컴포넌트 라벨 가져오기
  const getComponentLabel = (comp: ComponentData) => {
    return comp.label || (comp as any).columnName || comp.id;
  };

  return (
    <div className="space-y-4 p-4">
      <div className="flex items-center justify-between">
        <h4 className="text-sm font-semibold">조건부 표시 설정</h4>
        {layer.condition && (
          <Badge variant="secondary" className="text-xs">
            설정됨
          </Badge>
        )}
      </div>

      {/* 트리거 컴포넌트 선택 */}
      <div className="space-y-2">
        <Label className="text-xs">트리거 컴포넌트</Label>
        <Select value={targetComponentId} onValueChange={setTargetComponentId}>
          <SelectTrigger className="h-8 text-xs">
            <SelectValue placeholder="컴포넌트 선택..." />
          </SelectTrigger>
          <SelectContent>
            {triggerableComponents.baseLayerTriggers.length === 0 && 
             triggerableComponents.otherLayerTriggers.length === 0 ? (
              <div className="p-2 text-xs text-muted-foreground text-center">
                조건 설정 가능한 컴포넌트가 없습니다.
                <br />
                (셀렉트, 라디오, 코드 타입)
              </div>
            ) : (
              <>
                {/* 기본 레이어 컴포넌트 (우선 표시) */}
                {triggerableComponents.baseLayerTriggers.length > 0 && (
                  <>
                    {triggerableComponents.otherLayerTriggers.length > 0 && (
                      <div className="px-2 py-1 text-[10px] font-semibold text-muted-foreground">
                        기본 레이어
                      </div>
                    )}
                    {triggerableComponents.baseLayerTriggers.map((comp) => (
                      <SelectItem key={comp.id} value={comp.id} className="text-xs">
                        <div className="flex items-center gap-2">
                          <span>{getComponentLabel(comp)}</span>
                          <Badge variant="outline" className="text-[10px]">
                            {comp.componentType || (comp as any).widgetType}
                          </Badge>
                        </div>
                      </SelectItem>
                    ))}
                  </>
                )}
                {/* 다른 레이어 컴포넌트 (하단에 구분하여 표시) */}
                {triggerableComponents.otherLayerTriggers.length > 0 && (
                  <>
                    <div className="px-2 py-1 text-[10px] font-semibold text-muted-foreground border-t mt-1 pt-1">
                      다른 레이어
                    </div>
                    {triggerableComponents.otherLayerTriggers.map((comp) => (
                      <SelectItem key={comp.id} value={comp.id} className="text-xs">
                        <div className="flex items-center gap-2">
                          <span>{getComponentLabel(comp)}</span>
                          <Badge variant="outline" className="text-[10px]">
                            {comp.componentType || (comp as any).widgetType}
                          </Badge>
                        </div>
                      </SelectItem>
                    ))}
                  </>
                )}
              </>
            )}
          </SelectContent>
        </Select>
        
        {/* 데이터 소스 표시 */}
        {dataSourceInfo.type === "code" && dataSourceInfo.codeCategory && (
          <div className="flex items-center gap-2 text-xs text-muted-foreground">
            <Code2 className="h-3 w-3" />
            <span>코드:</span>
            <Badge variant="secondary" className="text-[10px]">
              {dataSourceInfo.codeCategory}
            </Badge>
          </div>
        )}
        {dataSourceInfo.type === "entity" && (dataSourceInfo.referenceTable || dataSourceInfo.originTable) && (
          <div className="flex items-center gap-2 text-xs text-muted-foreground">
            <Database className="h-3 w-3" />
            <span>엔티티:</span>
            <Badge variant="secondary" className="text-[10px]">
              {dataSourceInfo.referenceTable || `${dataSourceInfo.originTable}.${dataSourceInfo.originColumn}`}
            </Badge>
          </div>
        )}
        {dataSourceInfo.type === "category" && dataSourceInfo.categoryTable && (
          <div className="flex items-center gap-2 text-xs text-muted-foreground">
            <Database className="h-3 w-3" />
            <span>카테고리:</span>
            <Badge variant="secondary" className="text-[10px]">
              {dataSourceInfo.categoryTable}.{dataSourceInfo.categoryColumn}
            </Badge>
          </div>
        )}
        {dataSourceInfo.type === "static" && (
          <div className="flex items-center gap-2 text-xs text-muted-foreground">
            <span>정적 옵션</span>
          </div>
        )}
      </div>

      {/* 연산자 선택 */}
      {targetComponentId && (
        <div className="space-y-2">
          <Label className="text-xs">조건</Label>
          <Select 
            value={operator} 
            onValueChange={(val) => setOperator(val as OperatorType)}
          >
            <SelectTrigger className="h-8 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {OPERATORS.map((op) => (
                <SelectItem key={op.value} value={op.value} className="text-xs">
                  {op.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      )}

      {/* 조건 값 선택 */}
      {targetComponentId && (
        <div className="space-y-2">
          <Label className="text-xs">
            {operator === "in" ? "값 선택 (복수)" : "값"}
          </Label>
          
          {isLoadingOptions ? (
            <div className="flex items-center gap-2 text-xs text-muted-foreground p-2">
              <Loader2 className="h-3 w-3 animate-spin" />
              옵션 목록 로딩 중...
            </div>
          ) : loadError ? (
            <div className="flex items-center gap-2 text-xs text-destructive p-2">
              <AlertCircle className="h-3 w-3" />
              {loadError}
            </div>
          ) : options.length > 0 ? (
            // 옵션이 있는 경우 - 선택 UI
            operator === "in" ? (
              // 다중 선택 (in 연산자)
              <div className="space-y-1 max-h-40 overflow-y-auto border rounded-md p-2">
                {options.map((opt) => (
                  <div
                    key={opt.value}
                    className={cn(
                      "flex items-center gap-2 p-1.5 rounded cursor-pointer text-xs hover:bg-accent",
                      multiValues.includes(opt.value) && "bg-primary/10"
                    )}
                    onClick={() => toggleMultiValue(opt.value)}
                  >
                    <div className={cn(
                      "w-4 h-4 rounded border flex items-center justify-center",
                      multiValues.includes(opt.value) 
                        ? "bg-primary border-primary" 
                        : "border-input"
                    )}>
                      {multiValues.includes(opt.value) && (
                        <Check className="h-3 w-3 text-primary-foreground" />
                      )}
                    </div>
                    <span>{opt.label}</span>
                  </div>
                ))}
              </div>
            ) : (
              // 단일 선택 (eq, neq 연산자)
              <Select value={value} onValueChange={setValue}>
                <SelectTrigger className="h-8 text-xs">
                  <SelectValue placeholder="값 선택..." />
                </SelectTrigger>
                <SelectContent>
                  {options.map((opt) => (
                    <SelectItem 
                      key={opt.value} 
                      value={opt.value} 
                      className="text-xs"
                    >
                      {opt.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            )
          ) : (
            // 옵션이 없는 경우 - 직접 입력
            <Input
              value={value}
              onChange={(e) => setValue(e.target.value)}
              placeholder="조건 값 입력..."
              className="h-8 text-xs"
            />
          )}
          
          {/* 선택된 값 표시 (in 연산자) */}
          {operator === "in" && multiValues.length > 0 && (
            <div className="flex flex-wrap gap-1 mt-2">
              {multiValues.map((val) => {
                const opt = options.find((o) => o.value === val);
                return (
                  <Badge 
                    key={val} 
                    variant="secondary" 
                    className="text-[10px] gap-1"
                  >
                    {opt?.label || val}
                    <X 
                      className="h-2.5 w-2.5 cursor-pointer hover:text-destructive"
                      onClick={() => toggleMultiValue(val)}
                    />
                  </Badge>
                );
              })}
            </div>
          )}
        </div>
      )}

      {/* 현재 조건 요약 */}
      {targetComponentId && selectedComponent && (value || multiValues.length > 0) && (
        <div className="p-2 bg-muted rounded-md text-xs">
          <span className="font-medium">요약: </span>
          <span className="text-muted-foreground">
            "{getComponentLabel(selectedComponent)}" 값이{" "}
            {operator === "eq" && `"${options.find(o => o.value === value)?.label || value}"와 같으면`}
            {operator === "neq" && `"${options.find(o => o.value === value)?.label || value}"와 다르면`}
            {operator === "in" && `[${multiValues.map(v => options.find(o => o.value === v)?.label || v).join(", ")}] 중 하나이면`}
            {" "}이 레이어 표시
          </span>
        </div>
      )}

      {/* 표시 영역 설정 */}
      <div className="space-y-2 border-t pt-3">
        <Label className="text-xs font-semibold">표시 영역</Label>
        
        {layer.displayRegion ? (
          <>
            {/* 현재 영역 정보 표시 */}
            <div className="flex items-center gap-2 rounded-md border bg-muted/30 p-2">
              <div className="flex-1 text-[10px] text-muted-foreground">
                <span className="font-medium text-foreground">
                  {layer.displayRegion.width} x {layer.displayRegion.height}
                </span>
                <span className="ml-1">
                  ({layer.displayRegion.x}, {layer.displayRegion.y})
                </span>
              </div>
              <Button
                variant="ghost"
                size="sm"
                className="h-5 px-1.5 text-[10px] text-destructive hover:text-destructive"
                onClick={() => onUpdateDisplayRegion(undefined)}
              >
                삭제
              </Button>
            </div>
            <p className="text-[10px] text-muted-foreground">
              캔버스에서 점선 영역을 드래그하여 이동/리사이즈할 수 있습니다.
            </p>
          </>
        ) : (
          <div className="space-y-2">
            <div className="rounded-md border border-dashed p-3 text-center">
              <p className="text-xs font-medium text-muted-foreground">
                좌측의 레이어 항목을 캔버스로
              </p>
              <p className="text-xs font-medium text-muted-foreground">
                드래그&드롭하여 영역을 배치하세요
              </p>
            </div>
            <p className="text-[10px] text-muted-foreground">
              영역을 추가하면 조건 미충족 시 해당 영역이 사라지고 아래 컴포넌트가 위로 이동합니다.
            </p>
          </div>
        )}
      </div>

      {/* 버튼 */}
      <div className="flex gap-2 pt-2">
        <Button
          variant="outline"
          size="sm"
          className="flex-1 h-8 text-xs"
          onClick={handleClear}
        >
          조건 삭제
        </Button>
        <Button
          size="sm"
          className="flex-1 h-8 text-xs"
          onClick={handleSave}
          disabled={!targetComponentId || (!value && multiValues.length === 0)}
        >
          저장
        </Button>
      </div>
    </div>
  );
};
