"use client";

import React, { useState, useEffect, useCallback, useMemo, useRef } from "react";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { Textarea } from "@/components/ui/textarea";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import {
  Database,
  Link2,
  GitBranch,
  Columns3,
  Eye,
  Save,
  Plus,
  Minus,
  Pencil,
  Trash2,
  RefreshCw,
  Loader2,
  Check,
  ChevronsUpDown,
  ExternalLink,
  Table2,
  ArrowRight,
  Settings2,
  ChevronDown,
  ChevronRight,
  Filter,
  RotateCcw,
  X,
  Zap,
  MousePointer,
  Workflow,
} from "lucide-react";
import {
  getDataFlows,
  createDataFlow,
  updateDataFlow,
  deleteDataFlow,
  DataFlow,
  getMultipleScreenLayoutSummary,
  LayoutItem,
  getScreenGroup,
} from "@/lib/api/screenGroup";
import { tableManagementApi, ColumnTypeInfo, TableInfo, ColumnSettings } from "@/lib/api/tableManagement";
import { screenApi } from "@/lib/api/screen";
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
import { getNodeFlows, createNodeFlow, NodeFlow } from "@/lib/api/nodeFlows";
import { FlowEditor } from "@/components/dataflow/node-editor/FlowEditor";
import ScreenDesigner from "@/components/screen/ScreenDesigner";
import { TableSettingModal } from "@/components/screen/TableSettingModal";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

// ============================================================
// 타입 정의
// ============================================================

interface FilterTableInfo {
  tableName: string;
  tableLabel?: string;
  filterColumns?: string[];
  // 필터 키 매핑 정보 (메인 테이블.컬럼 → 필터 테이블.컬럼)
  filterKeyMapping?: {
    mainTableColumn: string;      // 메인 테이블의 컬럼 (leftColumn)
    mainTableColumnLabel?: string;
    filterTableColumn: string;    // 필터 테이블의 컬럼 (foreignKey)
    filterTableColumnLabel?: string;
  };
  joinColumnRefs?: Array<{
    column: string;
    refTable: string;
    refTableLabel?: string;
    refColumn: string;
  }>;
}

interface FieldMappingInfo {
  targetField: string;
  sourceField: string;
  sourceTable?: string;
  sourceDisplayName?: string;
  componentType?: string;
}

interface ScreenSettingModalProps {
  isOpen: boolean;
  onClose: () => void;
  screenId: number;
  screenName: string;
  groupId?: number;
  companyCode?: string; // 프리뷰용 회사 코드
  mainTable?: string;
  mainTableLabel?: string;
  filterTables?: FilterTableInfo[];
  fieldMappings?: FieldMappingInfo[];
  componentCount?: number;
  onSaveSuccess?: () => void;
}

// 검색 가능한 Select 컴포넌트
interface SearchableSelectProps {
  value: string;
  onValueChange: (value: string) => void;
  options: Array<{ value: string; label: string; description?: string }>;
  placeholder?: string;
  disabled?: boolean;
  className?: string;
}

function SearchableSelect({
  value,
  onValueChange,
  options,
  placeholder = "선택...",
  disabled = false,
  className,
}: SearchableSelectProps) {
  const [open, setOpen] = useState(false);

  const selectedOption = options.find((opt) => opt.value === value);

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          role="combobox"
          aria-expanded={open}
          disabled={disabled}
          className={cn("h-8 w-full justify-between text-xs", className)}
        >
          {selectedOption ? (
            <span className="truncate">{selectedOption.label}</span>
          ) : (
            <span className="text-muted-foreground">{placeholder}</span>
          )}
          <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent
        className="p-0"
        style={{ width: "var(--radix-popover-trigger-width)" }}
        align="start"
      >
        <Command>
          <CommandInput placeholder="검색..." className="text-xs" />
          <CommandList>
            <CommandEmpty className="py-2 text-center text-xs">
              결과 없음
            </CommandEmpty>
            <CommandGroup>
              {options.map((option) => (
                <CommandItem
                  key={option.value}
                  value={option.value}
                  onSelect={() => {
                    onValueChange(option.value);
                    setOpen(false);
                  }}
                  className="text-xs"
                >
                  <Check
                    className={cn(
                      "mr-2 h-4 w-4",
                      value === option.value ? "opacity-100" : "opacity-0"
                    )}
                  />
                  <div className="flex flex-col">
                    <span>{option.label}</span>
                    {option.description && (
                      <span className="text-muted-foreground text-[10px]">
                        {option.description}
                      </span>
                    )}
                  </div>
                </CommandItem>
              ))}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  );
}

// ============================================================
// 메인 모달 컴포넌트
// ============================================================

export function ScreenSettingModal({
  isOpen,
  onClose,
  screenId,
  screenName,
  groupId,
  companyCode,
  mainTable,
  mainTableLabel,
  filterTables = [],
  fieldMappings = [],
  componentCount = 0,
  onSaveSuccess,
}: ScreenSettingModalProps) {
  const [loading, setLoading] = useState(false);
  const [dataFlows, setDataFlows] = useState<DataFlow[]>([]);
  const [layoutItems, setLayoutItems] = useState<LayoutItem[]>([]);
  const [buttonControls, setButtonControls] = useState<ButtonControlInfo[]>([]);
  const [iframeKey, setIframeKey] = useState(0);
  const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });
  const [showDesignerModal, setShowDesignerModal] = useState(false);
  const [showTableSettingModal, setShowTableSettingModal] = useState(false);
  const [tableSettingTarget, setTableSettingTarget] = useState<{ tableName: string; tableLabel?: string } | null>(null);
  
  // 그룹 내 화면 목록 및 현재 선택된 화면
  const [groupScreens, setGroupScreens] = useState<Array<{
    screen_id: number;
    screen_name: string;
    screen_role?: string;
    display_order?: number;
    table_name?: string;
  }>>([]);
  const [currentScreenId, setCurrentScreenId] = useState(screenId);
  const [currentScreenName, setCurrentScreenName] = useState(screenName);
  const [currentMainTable, setCurrentMainTable] = useState(mainTable);
  const [currentMainTableLabel, setCurrentMainTableLabel] = useState(mainTableLabel);

  // 그룹 내 화면 목록 로드
  const loadGroupScreens = useCallback(async () => {
    if (!groupId) return;
    
    try {
      const groupRes = await getScreenGroup(groupId);
      if (groupRes.success && groupRes.data) {
        const groupData = groupRes.data as any;
        const screens = groupData.screens || [];
        // display_order 순으로 정렬
        screens.sort((a: any, b: any) => (a.display_order || 0) - (b.display_order || 0));
        setGroupScreens(screens);
      }
    } catch (error) {
      console.error("그룹 화면 목록 로드 실패:", error);
    }
  }, [groupId]);

  // 화면 선택 변경 핸들러
  const handleScreenChange = useCallback(async (newScreenId: number) => {
    const selectedScreen = groupScreens.find(s => s.screen_id === newScreenId);
    if (!selectedScreen) return;
    
    setCurrentScreenId(newScreenId);
    setCurrentScreenName(selectedScreen.screen_name);
    setCurrentMainTable(selectedScreen.table_name);
    // 테이블 라벨은 별도 조회 필요 (일단 테이블명 사용)
    setCurrentMainTableLabel(selectedScreen.table_name);
    setIframeKey(prev => prev + 1); // iframe 새로고침
  }, [groupScreens]);

  // 테이블 설정 모달 열기 핸들러
  const handleOpenTableSetting = useCallback((tableName: string, tableLabel?: string) => {
    setTableSettingTarget({ tableName, tableLabel });
    setShowTableSettingModal(true);
  }, []);

  // 테이블 설정 모달 닫기 핸들러
  const handleCloseTableSetting = useCallback(() => {
    setShowTableSettingModal(false);
    setTableSettingTarget(null);
  }, []);

  // 초기 로드 시 그룹 화면 목록도 로드
  useEffect(() => {
    if (isOpen && groupId) {
      loadGroupScreens();
    }
  }, [isOpen, groupId, loadGroupScreens]);

  // props 변경 시 현재 화면 상태 업데이트
  useEffect(() => {
    setCurrentScreenId(screenId);
    setCurrentScreenName(screenName);
    setCurrentMainTable(mainTable);
    setCurrentMainTableLabel(mainTableLabel);
  }, [screenId, screenName, mainTable, mainTableLabel]);

  // 데이터 로드
  const loadData = useCallback(async () => {
    if (!currentScreenId) return;

    setLoading(true);
    try {
      // 1. 해당 화면에서 시작하는 데이터 흐름 로드
      const flowsResponse = await getDataFlows({ sourceScreenId: currentScreenId });
      if (flowsResponse.success && flowsResponse.data) {
        setDataFlows(flowsResponse.data);
      }

      // 2. 화면 레이아웃 요약 정보 로드 (컴포넌트 컬럼 정보 포함)
      const layoutResponse = await getMultipleScreenLayoutSummary([currentScreenId]);
      if (layoutResponse.success && layoutResponse.data) {
        const screenLayout = layoutResponse.data[currentScreenId];
        setLayoutItems(screenLayout?.layoutItems || []);
        setCanvasSize({
          width: screenLayout?.canvasWidth || 0,
          height: screenLayout?.canvasHeight || 0,
        });
      }

      // 3. 버튼 정보 추출 (읽기 전용 요약용)
      try {
        const rawLayout = await screenApi.getLayout(currentScreenId);
        if (rawLayout?.components) {
          const buttons: ButtonControlInfo[] = [];
          const extractButtons = (components: any[]) => {
            for (const comp of components) {
              const config = comp.componentConfig || {};
              const isButton =
                comp.widgetType === "button" || comp.webType === "button" ||
                comp.type === "button" || config.webType === "button" ||
                comp.componentType?.includes("button") || comp.componentKind?.includes("button");
              if (isButton) {
                const webTypeConfig = comp.webTypeConfig || {};
                const action = config.action || {};
                buttons.push({
                  id: comp.id || comp.componentId || `btn-${buttons.length}`,
                  label: config.text || comp.label || comp.title || comp.name || "버튼",
                  actionType: typeof action === "string" ? action : (action.type || "custom"),
                  confirmMessage: action.confirmationMessage || action.confirmMessage || config.confirmMessage,
                  confirmationEnabled: action.confirmationEnabled ?? (!!action.confirmationMessage || !!action.confirmMessage),
                  backgroundColor: webTypeConfig.backgroundColor || config.backgroundColor || comp.style?.backgroundColor,
                  textColor: webTypeConfig.textColor || config.textColor || comp.style?.color,
                  borderRadius: webTypeConfig.borderRadius || config.borderRadius || comp.style?.borderRadius,
                  linkedFlows: webTypeConfig.dataflowConfig?.flowConfigs?.map((fc: any) => ({
                    id: fc.flowId, name: fc.flowName, timing: fc.executionTiming || "after",
                  })) || (webTypeConfig.dataflowConfig?.flowConfig ? [{
                    id: webTypeConfig.dataflowConfig.flowConfig.flowId,
                    name: webTypeConfig.dataflowConfig.flowConfig.flowName,
                    timing: webTypeConfig.dataflowConfig.flowConfig.executionTiming || "after",
                  }] : []),
                });
              }
              if (comp.children && Array.isArray(comp.children)) extractButtons(comp.children);
              if (comp.componentConfig?.children && Array.isArray(comp.componentConfig.children)) extractButtons(comp.componentConfig.children);
              if (comp.items && Array.isArray(comp.items)) extractButtons(comp.items);
            }
          };
          extractButtons(rawLayout.components);
          setButtonControls(buttons);
        }
      } catch (btnError) {
        console.error("버튼 정보 추출 실패:", btnError);
      }
    } catch (error) {
      console.error("데이터 로드 실패:", error);
    } finally {
      setLoading(false);
    }
  }, [currentScreenId]);

  useEffect(() => {
    if (isOpen && currentScreenId) {
      loadData();
    }
  }, [isOpen, currentScreenId, loadData]);

  // 새로고침 (데이터 + iframe)
  const handleRefresh = useCallback(() => {
    loadData();
    setIframeKey(prev => prev + 1);
  }, [loadData]);

  // 통계 계산
  const stats = useMemo(() => {
    const totalJoins = filterTables.reduce((sum, ft) => sum + (ft.joinColumnRefs?.length || 0), 0);
    const layoutColumnsSet = new Set<string>();
    layoutItems.forEach((item) => {
      if (item.usedColumns) item.usedColumns.forEach((col) => layoutColumnsSet.add(col));
      if (item.bindField) layoutColumnsSet.add(item.bindField);
    });
    const inputCount = layoutItems.filter(i => !i.widgetType?.includes("button") && !i.componentKind?.includes("table")).length;
    const gridCount = layoutItems.filter(i => i.componentKind?.includes("table") || i.componentKind?.includes("grid")).length;
    return {
      tableCount: 1 + filterTables.length,
      fieldCount: layoutColumnsSet.size || fieldMappings.length,
      joinCount: totalJoins,
      flowCount: dataFlows.length,
      inputCount,
      gridCount,
      buttonCount: buttonControls.length,
    };
  }, [filterTables, fieldMappings, dataFlows, layoutItems, buttonControls]);

  // 연결된 플로우 총 개수
  const linkedFlowCount = useMemo(() => {
    return buttonControls.reduce((sum, btn) => sum + (btn.linkedFlows?.length || 0), 0);
  }, [buttonControls]);

  return (
    <>
    <Dialog open={isOpen && !showDesignerModal} onOpenChange={onClose}>
      <DialogContent className="flex h-[90vh] max-h-[950px] w-[98vw] max-w-[1600px] flex-col overflow-hidden border-border/40 bg-background/95 backdrop-blur-xl">
        {/* V3 Header */}
        <DialogHeader className="flex-shrink-0 pb-0">
          <DialogTitle className="flex items-center gap-3 text-base">
            <span className="h-2 w-2 rounded-full bg-emerald-500 shadow-[0_0_6px_rgba(34,197,94,0.4)]" />
            <span className="font-bold tracking-tight">{currentScreenName}</span>
            {groupScreens.length > 1 && (
              <>
                <span className="h-3.5 w-px bg-border" />
                <Select
                  value={currentScreenId.toString()}
                  onValueChange={(value) => handleScreenChange(parseInt(value, 10))}
                >
                  <SelectTrigger className="h-7 w-auto min-w-[140px] max-w-[280px] border-border/40 bg-muted/30 text-xs font-medium">
                    <SelectValue placeholder="화면 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    {groupScreens.map((screen) => (
                      <SelectItem key={screen.screen_id} value={screen.screen_id.toString()}>
                        {screen.screen_name}
                        {screen.screen_role && (
                          <span className="ml-1 text-muted-foreground">({screen.screen_role})</span>
                        )}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </>
            )}
            <span className="ml-auto font-mono text-[10px] text-muted-foreground/60">#{currentScreenId}</span>
            <Button variant="ghost" size="sm" onClick={handleRefresh} className="h-7 w-7 p-0" title="새로고침">
              <RefreshCw className={cn("h-3.5 w-3.5", loading && "animate-spin")} />
            </Button>
          </DialogTitle>
          <DialogDescription className="sr-only">화면 정보 패널</DialogDescription>
        </DialogHeader>

        {/* V3 Body: Left Info Panel + Right Preview */}
        <div className="flex min-h-0 flex-1 gap-3 pt-2">
          {/* 왼쪽: 정보 패널 (탭 없음, 단일 스크롤) */}
          <div className="flex min-h-0 w-[380px] flex-shrink-0 flex-col rounded-lg border border-border/40">
            <div className="flex-1 overflow-y-auto p-4 [&::-webkit-scrollbar]:w-[2px] [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-border/50">

              {/* 1. 내러티브 요약 */}
              <div className="mb-4 rounded-lg border border-primary/10 bg-gradient-to-br from-primary/[0.04] to-blue-500/[0.02] p-3">
                <p className="text-xs leading-relaxed text-muted-foreground">
                  <span className="font-semibold text-foreground">{currentMainTable || "테이블 미연결"}</span>
                  {stats.fieldCount > 0 && <> 테이블의 <span className="font-bold text-primary">{stats.fieldCount}개</span> 컬럼을 사용하고 있어요.</>}
                  {filterTables.length > 0 && <><br />필터 테이블 {filterTables.length}개{stats.joinCount > 0 && <>, 엔티티 조인 {stats.joinCount}개</>}가 연결되어 있어요.</>}
                </p>
              </div>

              {/* 2. 속성 테이블 */}
              <div className="mb-4 space-y-0.5">
                <div className="flex h-[30px] items-center rounded-md px-2 text-[11px] transition-colors hover:bg-muted/30">
                  <span className="w-[76px] flex-shrink-0 text-[10px] font-medium text-muted-foreground">메인 테이블</span>
                  <span className="min-w-0 flex-1 truncate font-mono text-[10px] font-semibold">{currentMainTable || "-"}</span>
                  {stats.fieldCount > 0 && <span className="flex-shrink-0 font-mono text-[9px] text-muted-foreground">{stats.fieldCount} 컬럼</span>}
                </div>
                {filterTables.map((ft, idx) => (
                  <div key={idx} className="flex h-[30px] items-center rounded-md px-2 text-[11px] transition-colors hover:bg-muted/30">
                    <span className="w-[76px] flex-shrink-0 text-[10px] font-medium text-muted-foreground">필터 테이블</span>
                    <span className="min-w-0 flex-1 truncate font-mono text-[10px] font-semibold text-emerald-500">{ft.tableName}</span>
                    <span className="flex-shrink-0 font-mono text-[9px] text-muted-foreground">FK</span>
                  </div>
                ))}
                {filterTables.some(ft => ft.joinColumnRefs && ft.joinColumnRefs.length > 0) && (
                  <div className="flex h-[30px] items-center rounded-md px-2 text-[11px] transition-colors hover:bg-muted/30">
                    <span className="w-[76px] flex-shrink-0 text-[10px] font-medium text-muted-foreground">엔티티 조인</span>
                    <span className="min-w-0 flex-1 truncate text-[10px] font-semibold">
                      {filterTables.flatMap(ft => ft.joinColumnRefs || []).map((j, i) => (
                        <span key={i}>{i > 0 && ", "}<span className="font-mono">{j.column}</span> → <span className="font-mono text-amber-500">{j.refTable}</span></span>
                      ))}
                    </span>
                    <span className="flex-shrink-0 font-mono text-[9px] text-muted-foreground">{stats.joinCount}개</span>
                  </div>
                )}
                <div className="flex h-[30px] items-center rounded-md px-2 text-[11px] transition-colors hover:bg-muted/30">
                  <span className="w-[76px] flex-shrink-0 text-[10px] font-medium text-muted-foreground">컴포넌트</span>
                  <span className="min-w-0 flex-1 truncate text-[10px] font-semibold">
                    {stats.inputCount > 0 && <>입력 {stats.inputCount}</>}
                    {stats.gridCount > 0 && <>{stats.inputCount > 0 && " · "}그리드 {stats.gridCount}</>}
                    {stats.buttonCount > 0 && <>{(stats.inputCount > 0 || stats.gridCount > 0) && " · "}버튼 {stats.buttonCount}</>}
                    {stats.inputCount === 0 && stats.gridCount === 0 && stats.buttonCount === 0 && `${componentCount}개`}
                  </span>
                </div>
              </div>

              <div className="my-4 h-px bg-border/40" />

              {/* 3. 테이블 섹션 */}
              <div className="mb-4">
                <div className="mb-2 flex items-center gap-1.5 border-b border-border/30 pb-2">
                  <div className="flex h-4 w-4 items-center justify-center rounded bg-blue-500/10">
                    <Database className="h-2.5 w-2.5 text-blue-500" />
                  </div>
                  <span className="text-[11px] font-bold uppercase tracking-wide text-muted-foreground">테이블</span>
                  <Badge variant="secondary" className="ml-auto h-4 rounded-full px-1.5 text-[9px] font-bold bg-blue-500/10 text-blue-500 hover:bg-blue-500/10">{stats.tableCount}</Badge>
                </div>
                <p className="mb-2 text-[10px] text-muted-foreground/70">컬럼 타입이나 조인을 변경하려면 "설정"을 눌러요</p>
                <div className="space-y-1">
                  {currentMainTable && (
                    <div className="flex items-center gap-2.5 rounded-lg border border-border/40 bg-muted/20 p-2.5 transition-colors hover:border-border/60 hover:bg-muted/30">
                      <div className="h-6 w-[3px] flex-shrink-0 rounded-full bg-blue-500" />
                      <div className="min-w-0 flex-1">
                        <div className="truncate font-mono text-[11px] font-semibold">{currentMainTable}</div>
                        <div className="text-[9px] text-muted-foreground">메인 · {stats.fieldCount} 컬럼 사용중</div>
                      </div>
                      <Button variant="outline" size="sm" className="h-6 px-2.5 text-[10px] font-semibold border-border/50" onClick={() => handleOpenTableSetting(currentMainTable, currentMainTableLabel)}>설정</Button>
                    </div>
                  )}
                  {filterTables.map((ft, idx) => (
                    <div key={idx} className="flex items-center gap-2.5 rounded-lg border border-border/40 bg-muted/20 p-2.5 transition-colors hover:border-border/60 hover:bg-muted/30">
                      <div className="h-6 w-[3px] flex-shrink-0 rounded-full bg-emerald-500" />
                      <div className="min-w-0 flex-1">
                        <div className="truncate font-mono text-[11px] font-semibold">{ft.tableName}</div>
                        <div className="text-[9px] text-muted-foreground">필터{ft.filterKeyMapping ? ` · FK: ${ft.filterKeyMapping.filterTableColumn}` : ""}</div>
                      </div>
                      <Button variant="outline" size="sm" className="h-6 px-2.5 text-[10px] font-semibold border-border/50" onClick={() => handleOpenTableSetting(ft.tableName, ft.tableLabel)}>설정</Button>
                    </div>
                  ))}
                </div>
              </div>

              <div className="my-4 h-px bg-border/40" />

              {/* 4. 버튼 섹션 (읽기 전용) */}
              <div className="mb-4">
                <div className="mb-2 flex items-center gap-1.5 border-b border-border/30 pb-2">
                  <div className="flex h-4 w-4 items-center justify-center rounded bg-amber-500/10">
                    <MousePointer className="h-2.5 w-2.5 text-amber-500" />
                  </div>
                  <span className="text-[11px] font-bold uppercase tracking-wide text-muted-foreground">버튼</span>
                  <Badge variant="secondary" className="ml-auto h-4 rounded-full px-1.5 text-[9px] font-bold bg-amber-500/10 text-amber-500 hover:bg-amber-500/10">{stats.buttonCount}</Badge>
                </div>
                <p className="mb-2 text-[10px] text-muted-foreground/70">버튼 편집은 화면 디자이너에서 해요</p>
                {buttonControls.length > 0 ? (
                  <div className="space-y-0">
                    {buttonControls.map((btn) => (
                      <div key={btn.id} className="flex items-center gap-2 border-b border-border/20 py-1.5 last:border-b-0">
                        <span
                          className="flex h-5 flex-shrink-0 items-center rounded px-2 text-[9px] font-bold"
                          style={{
                            backgroundColor: btn.backgroundColor ? `${btn.backgroundColor}20` : "hsl(var(--muted))",
                            color: btn.textColor || btn.backgroundColor || "hsl(var(--foreground))",
                          }}
                        >{btn.label}</span>
                        <div className="min-w-0 flex-1">
                          <div className="text-[10px] text-muted-foreground">{btn.actionType?.toUpperCase() || "CUSTOM"}</div>
                          {btn.confirmMessage && <div className="truncate text-[9px] italic text-muted-foreground/60">"{btn.confirmMessage}"</div>}
                        </div>
                        {btn.linkedFlows && btn.linkedFlows.length > 0 && (
                          <Badge variant="secondary" className="h-4 rounded px-1.5 text-[8px] font-bold bg-violet-500/10 text-violet-500 hover:bg-violet-500/10">
                            플로우 {btn.linkedFlows.length}
                          </Badge>
                        )}
                      </div>
                    ))}
                  </div>
                ) : (
                  <div className="py-4 text-center text-[10px] text-muted-foreground/50">버튼이 없어요</div>
                )}
              </div>

              <div className="my-4 h-px bg-border/40" />

              {/* 5. 데이터 흐름 섹션 */}
              <div className="mb-4">
                <div className="mb-2 flex items-center gap-1.5 border-b border-border/30 pb-2">
                  <div className="flex h-4 w-4 items-center justify-center rounded bg-rose-500/10">
                    <ArrowRight className="h-2.5 w-2.5 text-rose-500" />
                  </div>
                  <span className="text-[11px] font-bold uppercase tracking-wide text-muted-foreground">데이터 흐름</span>
                  <Badge variant="secondary" className="ml-auto h-4 rounded-full px-1.5 text-[9px] font-bold bg-rose-500/10 text-rose-500 hover:bg-rose-500/10">{stats.flowCount}</Badge>
                </div>
                {dataFlows.length > 0 ? (
                  <div className="space-y-1">
                    {dataFlows.map((flow) => (
                      <div key={flow.id} className="flex items-center gap-2.5 rounded-lg border border-border/40 bg-muted/20 p-2.5">
                        <div className="h-6 w-[3px] flex-shrink-0 rounded-full bg-rose-500" />
                        <div className="min-w-0 flex-1">
                          <div className="truncate text-[11px] font-semibold">{flow.source_action || flow.flow_type} → {flow.target_screen_name || `화면 ${flow.target_screen_id}`}</div>
                          <div className="text-[9px] text-muted-foreground">{flow.flow_type}{flow.flow_label ? ` · ${flow.flow_label}` : ""}</div>
                        </div>
                        <Button variant="ghost" size="sm" className="h-5 w-5 p-0 text-muted-foreground hover:text-destructive" onClick={async () => {
                          if (!confirm("정말 삭제하시겠습니까?")) return;
                          const res = await deleteDataFlow(flow.id);
                          if (res.success) { toast.success("삭제되었습니다."); loadData(); onSaveSuccess?.(); }
                          else toast.error("삭제 실패");
                        }}>
                          <Trash2 className="h-3 w-3" />
                        </Button>
                      </div>
                    ))}
                  </div>
                ) : (
                  <div className="rounded-lg border border-dashed border-border/40 py-5 text-center">
                    <ArrowRight className="mx-auto mb-1 h-4 w-4 text-muted-foreground/30" />
                    <div className="text-[11px] font-medium text-muted-foreground/60">데이터 흐름이 없어요</div>
                    <div className="text-[9px] text-muted-foreground/40">다른 화면으로 데이터를 전달하려면 추가해보세요</div>
                  </div>
                )}
                <Button variant="outline" size="sm" className="mt-2 h-7 w-full text-[10px] font-semibold border-border/40 text-muted-foreground" onClick={() => toast.info("데이터 흐름 추가는 준비 중이에요")}>
                  <Plus className="mr-1 h-3 w-3" />
                  흐름 추가
                </Button>
              </div>

              <div className="my-4 h-px bg-border/40" />

              {/* 6. 플로우 연동 섹션 */}
              <div>
                <div className="mb-2 flex items-center gap-1.5 border-b border-border/30 pb-2">
                  <div className="flex h-4 w-4 items-center justify-center rounded bg-violet-500/10">
                    <Link2 className="h-2.5 w-2.5 text-violet-500" />
                  </div>
                  <span className="text-[11px] font-bold uppercase tracking-wide text-muted-foreground">플로우 연동</span>
                  <Badge variant="secondary" className="ml-auto h-4 rounded-full px-1.5 text-[9px] font-bold bg-violet-500/10 text-violet-500 hover:bg-violet-500/10">{linkedFlowCount}</Badge>
                </div>
                {linkedFlowCount > 0 ? (
                  <div className="space-y-1">
                    {buttonControls.filter(b => b.linkedFlows && b.linkedFlows.length > 0).flatMap(btn =>
                      (btn.linkedFlows || []).map(flow => (
                        <div key={`${btn.id}-${flow.id}`} className="flex items-center gap-2.5 rounded-lg border border-violet-500/10 bg-violet-500/[0.03] p-2.5">
                          <div className="h-6 w-[3px] flex-shrink-0 rounded-full bg-violet-500" />
                          <div className="min-w-0 flex-1">
                            <div className="truncate text-[11px] font-semibold">{flow.name || `플로우 #${flow.id}`}</div>
                            <div className="text-[9px] text-muted-foreground">{btn.label} 버튼 · {flow.timing === "before" ? "실행 전" : "실행 후"}</div>
                          </div>
                        </div>
                      ))
                    )}
                  </div>
                ) : (
                  <div className="py-3 text-center text-[10px] text-muted-foreground/50">연동된 플로우가 없어요</div>
                )}
              </div>
            </div>

            {/* CTA: 화면 디자이너 열기 */}
            <div className="flex-shrink-0 border-t border-border/40 p-3">
              <Button
                className="h-8 w-full gap-1.5 bg-gradient-to-r from-primary to-blue-500 text-[11px] font-bold tracking-tight text-primary-foreground shadow-md shadow-primary/20 transition-all hover:shadow-lg hover:shadow-primary/30"
                onClick={() => setShowDesignerModal(true)}
              >
                <ExternalLink className="h-3 w-3" />
                화면 디자이너에서 편집
              </Button>
            </div>
          </div>

          {/* 오른쪽: 화면 프리뷰 */}
          <div className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-lg border border-border/40">
            <PreviewTab
              screenId={currentScreenId}
              screenName={currentScreenName}
              companyCode={companyCode}
              iframeKey={iframeKey}
              canvasWidth={canvasSize.width}
              canvasHeight={canvasSize.height}
            />
          </div>
        </div>
      </DialogContent>
    </Dialog>

    {/* ScreenDesigner 전체 화면 - Dialog 중첩 시 오버레이 컴포지팅으로 깜빡임 발생하여 직접 렌더링 */}
    {/* ScreenDesigner 자체 SlimToolbar에 "목록으로" 닫기 버튼이 있으므로 별도 X 버튼 불필요 */}
    {showDesignerModal && (
      <div className="bg-background fixed inset-0 z-[1000] flex flex-col">
        <ScreenDesigner
          selectedScreen={{
            screenId: currentScreenId,
            screenCode: `screen_${currentScreenId}`,
            screenName: currentScreenName,
            tableName: currentMainTable || "",
            companyCode: companyCode || "*",
            description: "",
            isActive: "Y" as const,
            createdDate: new Date(),
            updatedDate: new Date(),
          }}
          onBackToList={async () => {
            setShowDesignerModal(false);
            await loadData();
            setIframeKey(prev => prev + 1);
          }}
        />
      </div>
    )}

    {/* TableSettingModal */}
    {tableSettingTarget && (
      <TableSettingModal
        isOpen={showTableSettingModal}
        onClose={handleCloseTableSetting}
        tableName={tableSettingTarget.tableName}
        tableLabel={tableSettingTarget.tableLabel}
        screenId={currentScreenId}
        onSaveSuccess={() => {
          handleRefresh();
        }}
      />
    )}
  </>
  );
}

// ============================================================
// 통합 테이블 컬럼 아코디언 컴포넌트
// ============================================================

interface ColumnMapping {
  columnName: string;
  fieldLabel?: string;
  order: number; // 화면 순서 (y 좌표 기준)
}

interface JoinColumnRef {
  column: string;
  refTable: string;
  refTableLabel?: string;
  refColumn: string;
  displayColumn?: string;
}

interface FilterKeyMapping {
  mainTableColumn: string;
  mainTableColumnLabel?: string;
  filterTableColumn: string;
  filterTableColumnLabel?: string;
}

interface TableColumnAccordionProps {
  // 공통 props
  tableName: string;
  tableLabel?: string;
  tableType: "main" | "filter"; // 테이블 타입
  columnMappings?: ColumnMapping[];
  onColumnChange?: (fieldLabel: string, oldColumn: string, newColumn: string) => void;
  onColumnReorder?: (newOrder: string[]) => void; // 컬럼 순서 변경 콜백
  onJoinSettingSaved?: () => void;
  usedFields?: Set<string>; // 화면에서 사용 중인 컬럼 목록
  
  // 필터 테이블 전용 props (optional)
  mainTable?: string; // 메인 테이블명 (필터 테이블에서 필터 연결 정보 표시용)
  filterKeyMapping?: FilterKeyMapping;
  joinColumnRefs?: JoinColumnRef[];
}

function TableColumnAccordion({
  tableName,
  tableLabel,
  tableType,
  columnMappings = [],
  onColumnChange,
  onColumnReorder,
  onJoinSettingSaved,
  usedFields = new Set(),
  mainTable,
  filterKeyMapping,
  joinColumnRefs = [],
}: TableColumnAccordionProps) {
  // columnMappings를 Map으로 변환 (컬럼명 → 매핑정보)
  const columnMappingMap = useMemo(() => {
    const map = new Map<string, ColumnMapping>();
    columnMappings.forEach(m => map.set(m.columnName.toLowerCase(), m));
    return map;
  }, [columnMappings]);
  
  const [isOpen, setIsOpen] = useState(false);
  const [columns, setColumns] = useState<ColumnTypeInfo[]>([]);
  const [loadingColumns, setLoadingColumns] = useState(false);
  
  // 편집 중인 필드
  const [editingField, setEditingField] = useState<string | null>(null);
  
  // 조인 설정 관련 상태
  const [allTables, setAllTables] = useState<TableInfo[]>([]);
  const [refTableColumns, setRefTableColumns] = useState<ColumnTypeInfo[]>([]);
  const [loadingRefColumns, setLoadingRefColumns] = useState(false);
  const [savingJoinSetting, setSavingJoinSetting] = useState(false);
  
  // 조인 설정 편집 상태
  const [editingJoin, setEditingJoin] = useState<{
    columnName: string;
    referenceTable: string;
    referenceColumn: string;
    displayColumn: string;
  } | null>(null);
  
  // 드래그 앤 드롭 상태
  const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
  const [localColumnOrder, setLocalColumnOrder] = useState<string[] | null>(null); // 드래그 중 로컬 순서
  
  // 스타일 설정 (테이블 타입별)
  const isMain = tableType === "main";
  const themeColor = isMain ? "blue" : "purple";
  const themeIcon = isMain ? Table2 : Filter;
  const themeBadge = isMain ? "메인" : "필터";
  
  // 필터 테이블용 플래그
  const hasJoinRefs = joinColumnRefs && joinColumnRefs.length > 0;
  const hasFilterKey = !!filterKeyMapping;
  
  // 정렬된 컬럼 목록
  const sortedColumns = useMemo(() => {
    if (columns.length === 0) return [];
    
    if (isMain) {
      // 메인: 사용 중 → 안 쓰는 컬럼
      const used: (ColumnTypeInfo & { mapping: ColumnMapping })[] = [];
      const unused: ColumnTypeInfo[] = [];
      
      columns.forEach(col => {
        const mapping = columnMappingMap.get(col.columnName.toLowerCase());
        if (mapping) {
          used.push({ ...col, mapping });
        } else {
          unused.push(col);
        }
      });
      
      used.sort((a, b) => a.mapping.order - b.mapping.order);
      return [...used, ...unused];
    } else {
      // 필터: 필터키 → 조인키 → 필드 → 안 쓰는 컬럼
      const filterKeys: ColumnTypeInfo[] = [];
      const joinKeys: ColumnTypeInfo[] = [];
      const fieldCols: (ColumnTypeInfo & { mapping: ColumnMapping })[] = [];
      const unused: ColumnTypeInfo[] = [];
      
      columns.forEach(col => {
        const colNameLower = col.columnName.toLowerCase();
        const isFilterKey = filterKeyMapping?.filterTableColumn?.toLowerCase() === colNameLower;
        const isJoinKey = joinColumnRefs?.some(j => j.column.toLowerCase() === colNameLower);
        const mapping = columnMappingMap.get(colNameLower);
        
        if (isFilterKey) {
          filterKeys.push(col);
        } else if (isJoinKey) {
          joinKeys.push(col);
        } else if (mapping) {
          fieldCols.push({ ...col, mapping });
        } else {
          unused.push(col);
        }
      });
      
      fieldCols.sort((a, b) => a.mapping.order - b.mapping.order);
      return [...filterKeys, ...joinKeys, ...fieldCols, ...unused];
    }
  }, [columns, columnMappingMap, isMain, filterKeyMapping, joinColumnRefs]);

  // 아코디언 열릴 때 테이블 컬럼 + 전체 테이블 목록 로드
  const handleToggle = async () => {
    const newIsOpen = !isOpen;
    setIsOpen(newIsOpen);
    
    if (newIsOpen && columns.length === 0 && tableName) {
      setLoadingColumns(true);
      try {
        const result = await tableManagementApi.getColumnList(tableName);
        if (result.success && result.data && result.data.columns) {
          setColumns(result.data.columns);
        }
        
        if (allTables.length === 0) {
          const tablesResult = await tableManagementApi.getTableList();
          if (tablesResult.success && tablesResult.data) {
            // 중복 테이블 제거 (tableName 기준)
            const uniqueTables = tablesResult.data.filter(
              (table, index, self) =>
                index === self.findIndex((t) => t.tableName === table.tableName)
            );
            setAllTables(uniqueTables);
          }
        }
      } catch (error) {
        console.error("테이블 컬럼 로드 실패:", error);
      } finally {
        setLoadingColumns(false);
      }
    }
  };
  
  // 참조 테이블 선택 시 해당 테이블의 컬럼 로드
  const loadRefTableColumns = useCallback(async (refTableName: string) => {
    if (!refTableName) {
      setRefTableColumns([]);
      return;
    }
    
    setLoadingRefColumns(true);
    try {
      const result = await tableManagementApi.getColumnList(refTableName);
      if (result.success && result.data && result.data.columns) {
        setRefTableColumns(result.data.columns);
      }
    } catch (error) {
      console.error("참조 테이블 컬럼 로드 실패:", error);
    } finally {
      setLoadingRefColumns(false);
    }
  }, []);
  
  // 조인 설정 저장
  const handleSaveJoinSetting = useCallback(async () => {
    if (!editingJoin || !tableName) return;
    
    setSavingJoinSetting(true);
    try {
      const settings: ColumnSettings = {
        columnLabel: columns.find(c => c.columnName === editingJoin.columnName)?.displayName || editingJoin.columnName,
        webType: "entity",
        detailSettings: JSON.stringify({}),
        codeCategory: "",
        codeValue: "",
        referenceTable: editingJoin.referenceTable,
        referenceColumn: editingJoin.referenceColumn,
        displayColumn: editingJoin.displayColumn,
      };
      
      const result = await tableManagementApi.updateColumnSettings(
        tableName,
        editingJoin.columnName,
        settings
      );
      
      if (result.success) {
        toast.success("조인 설정이 저장되었습니다.");
        setEditingJoin(null);
        onJoinSettingSaved?.();
      } else {
        toast.error(result.message || "조인 설정 저장에 실패했습니다.");
      }
    } catch (error) {
      console.error("조인 설정 저장 실패:", error);
      toast.error("조인 설정 저장에 실패했습니다.");
    } finally {
      setSavingJoinSetting(false);
    }
  }, [editingJoin, tableName, columns, onJoinSettingSaved]);
  
  // 조인 설정 편집 시작
  const startEditingJoin = useCallback((columnName: string, currentRefTable?: string, currentRefColumn?: string, currentDisplayColumn?: string) => {
    setEditingJoin({
      columnName,
      referenceTable: currentRefTable || "",
      referenceColumn: currentRefColumn || "",
      displayColumn: currentDisplayColumn || "",
    });
    
    if (currentRefTable) {
      loadRefTableColumns(currentRefTable);
    }
  }, [loadRefTableColumns]);

  // 드래그 앤 드롭 핸들러
  const handleDragStart = useCallback((e: React.DragEvent, index: number) => {
    setDraggedIndex(index);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", String(index));
    
    // 드래그 시작 시 현재 순서를 로컬 상태로 저장
    const usedColumns = sortedColumns.filter(col => {
      const colNameLower = col.columnName.toLowerCase();
      return columnMappingMap.has(colNameLower);
    });
    setLocalColumnOrder(usedColumns.map(col => col.columnName));
  }, [sortedColumns, columnMappingMap]);

  const handleDragOver = useCallback((e: React.DragEvent, hoverIndex: number) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    
    if (draggedIndex === null || draggedIndex === hoverIndex || !localColumnOrder) return;
    
    // 사용 중인 컬럼 수 체크
    if (hoverIndex >= localColumnOrder.length || draggedIndex >= localColumnOrder.length) return;
    
    // 로컬 순서만 변경 (저장하지 않음)
    const newOrder = [...localColumnOrder];
    const draggedItem = newOrder[draggedIndex];
    newOrder.splice(draggedIndex, 1);
    newOrder.splice(hoverIndex, 0, draggedItem);
    
    setDraggedIndex(hoverIndex);
    setLocalColumnOrder(newOrder);
  }, [draggedIndex, localColumnOrder]);

  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    
    // 드롭 시 최종 순서로 저장
    if (localColumnOrder && onColumnReorder) {
      onColumnReorder(localColumnOrder);
    }
    
    setDraggedIndex(null);
    setLocalColumnOrder(null);
  }, [localColumnOrder, onColumnReorder]);

  const handleDragEnd = useCallback(() => {
    // 드래그 취소 시 (드롭 영역 밖으로 나간 경우)
    setDraggedIndex(null);
    setLocalColumnOrder(null);
  }, []);

  // 컬럼의 특수 상태 확인 (필터 테이블용)
  const getColumnState = (colNameLower: string) => {
    const isFilterKey = filterKeyMapping?.filterTableColumn?.toLowerCase() === colNameLower;
    const joinRef = joinColumnRefs?.find(j => j.column.toLowerCase() === colNameLower);
    const isJoinKey = !!joinRef;
    const mapping = columnMappingMap.get(colNameLower);
    // usedFields에서도 확인 (bindField 등에서 가져온 사용 컬럼)
    const isUsed = !!mapping || usedFields.has(colNameLower) || 
      Array.from(usedFields).some(f => f.toLowerCase() === colNameLower);
    
    return { isFilterKey, isJoinKey, joinRef, isUsed, mapping };
  };

  const ThemeIcon = themeIcon;

  return (
    <div className={`rounded-lg border bg-${themeColor}-50/30 overflow-hidden`}>
      {/* 헤더 */}
      <button
        type="button"
        onClick={handleToggle}
        className={`w-full flex items-center gap-3 p-3 hover:bg-${themeColor}-50/50 transition-colors text-left`}
      >
        {isOpen ? (
          <ChevronDown className={`h-4 w-4 text-${themeColor}-500 flex-shrink-0`} />
        ) : (
          <ChevronRight className={`h-4 w-4 text-${themeColor}-500 flex-shrink-0`} />
        )}
        
        <ThemeIcon className={`h-4 w-4 text-${themeColor}-500 flex-shrink-0`} />
        
        <div className="flex-1 min-w-0">
          <div className="font-medium truncate">{tableLabel || tableName}</div>
          {tableLabel && tableName !== tableLabel && (
            <div className="text-xs text-muted-foreground truncate">{tableName}</div>
          )}
        </div>
        
        <Badge variant="outline" className={`bg-${themeColor}-100 text-${themeColor}-700 text-xs flex-shrink-0`}>
          {themeBadge}
        </Badge>
        
        {/* 요약 정보 */}
        <div className="text-xs text-muted-foreground flex-shrink-0">
          {isMain ? (
            columns.length > 0 && `${columns.length}개 컬럼`
          ) : (
            <>
              {hasFilterKey && `${(filterKeyMapping ? 1 : 0)}개 필터`}
              {hasJoinRefs && hasFilterKey && " / "}
              {hasJoinRefs && `${joinColumnRefs!.length}개 조인`}
            </>
          )}
        </div>
      </button>

      {/* 펼쳐진 내용 */}
      {isOpen && (
        <div className={`border-t border-${themeColor}-100 p-3 space-y-3 bg-card/50`}>
          {/* 필터 연결 정보 (필터 테이블만) */}
          {!isMain && filterKeyMapping && (
            <div className="flex items-center gap-1 text-xs">
              <Badge variant="outline" className="h-4 px-1 text-[8px] bg-purple-200 text-purple-700 border-purple-300">필터</Badge>
              <span className="font-mono text-purple-700">
                {mainTable}.{filterKeyMapping.mainTableColumnLabel || filterKeyMapping.mainTableColumn}
              </span>
              <span className="text-muted-foreground">=</span>
              <span className="font-mono text-purple-700">
                {tableName}.{filterKeyMapping.filterTableColumnLabel || filterKeyMapping.filterTableColumn}
              </span>
            </div>
          )}

          {/* 테이블 컬럼 정보 */}
          <div className="space-y-2">
            <div className="flex items-center justify-between">
              <div className="flex items-center gap-1 text-xs font-medium text-foreground">
                <Table2 className="h-3 w-3" />
                테이블 컬럼 ({loadingColumns ? "로딩중..." : `${columns.length}개`})
              </div>
              {columnMappings.length > 0 && (
                <div className="flex items-center gap-2 text-[10px] text-muted-foreground">
                  <div className="flex items-center gap-1">
                    <div className="w-2 h-2 rounded-full bg-primary" />
                    <span>화면에서 사용 ({columnMappings.length}개)</span>
                  </div>
                </div>
              )}
            </div>
            
            {loadingColumns ? (
              <div className="flex items-center justify-center py-4">
                <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
              </div>
            ) : sortedColumns.length > 0 ? (
              <div className="flex gap-3 items-stretch">
                {/* 왼쪽: 컬럼 목록 */}
                <div className="flex-1 space-y-1 pr-1 max-h-[350px] overflow-y-auto">
                  {(() => {
                    // 드래그 중일 때 로컬 순서 적용
                    let displayColumns = sortedColumns;
                    if (localColumnOrder && localColumnOrder.length > 0) {
                      // 사용 중인 컬럼들을 localColumnOrder에 따라 재정렬
                      const usedCols = sortedColumns.filter(col => columnMappingMap.has(col.columnName.toLowerCase()));
                      const unusedCols = sortedColumns.filter(col => !columnMappingMap.has(col.columnName.toLowerCase()));
                      
                      const reorderedUsed = localColumnOrder
                        .map(name => usedCols.find(col => col.columnName.toLowerCase() === name.toLowerCase()))
                        .filter(Boolean) as typeof usedCols;
                      
                      displayColumns = [...reorderedUsed, ...unusedCols];
                    }
                    
                    return displayColumns.map((col, cIdx) => {
                    const colNameLower = col.columnName.toLowerCase();
                    const { isFilterKey, isJoinKey, isUsed, mapping } = getColumnState(colNameLower);
                    const isSelected = editingField === (mapping?.fieldLabel || col.columnName);
                    const isDragging = draggedIndex === cIdx;
                    
                    // 드래그 가능 여부 (사용 중인 컬럼만)
                    const canDrag = isUsed && !!onColumnReorder;
                    
                    // 스타일 결정
                    let baseClass = "";
                    let leftBorderClass = "";
                    
                    if (isUsed) {
                      baseClass = isSelected
                        ? "bg-primary/10 border-primary/40"
                        : "bg-primary/10 border-primary/20 hover:bg-primary/10 hover:border-primary/40";
                      if (isJoinKey) {
                        leftBorderClass = "border-l-4 border-l-orange-500";
                      } else if (isFilterKey) {
                        leftBorderClass = "border-l-4 border-l-purple-400";
                      }
                    } else if (isJoinKey) {
                      baseClass = isSelected
                        ? "bg-amber-100 border-orange-400"
                        : "bg-amber-50 border-orange-200 hover:bg-amber-100 hover:border-orange-300";
                    } else if (isFilterKey) {
                      baseClass = isSelected
                        ? "bg-purple-100 border-purple-400"
                        : "bg-purple-50 border-purple-200 hover:bg-purple-100 hover:border-purple-300";
                    } else {
                      baseClass = isSelected
                        ? "bg-muted border-input"
                        : "bg-muted border-border hover:bg-muted";
                    }
                    
                    return (
                      <div
                        key={cIdx}
                        draggable={canDrag}
                        onDragStart={canDrag ? (e) => handleDragStart(e, cIdx) : undefined}
                        onDragOver={canDrag ? (e) => handleDragOver(e, cIdx) : undefined}
                        onDrop={canDrag ? handleDrop : undefined}
                        onDragEnd={canDrag ? handleDragEnd : undefined}
                        onClick={() => {
                          setEditingField(mapping?.fieldLabel || col.columnName);
                          setEditingJoin(null);
                        }}
                        className={`flex items-center justify-between gap-2 text-xs rounded px-2 py-1.5 border transition-all cursor-pointer ${baseClass} ${leftBorderClass} ${isDragging ? "opacity-50 scale-95" : ""} ${canDrag ? "cursor-grab active:cursor-grabbing" : ""}`}
                      >
                        <span className={`font-medium truncate flex-1 min-w-0 ${
                          isUsed ? "text-primary"
                          : isJoinKey ? "text-orange-800"
                          : isFilterKey ? "text-purple-800"
                          : "text-muted-foreground"
                        }`}>
                          {col.displayName || col.columnName}
                        </span>
                        <div className="flex items-center gap-2 flex-shrink-0">
                          {isFilterKey && (
                            <Badge variant="outline" className="h-4 px-1 text-[8px] bg-purple-200 text-purple-700 border-purple-300">필터</Badge>
                          )}
                          {isJoinKey && (
                            <Badge variant="outline" className="h-4 px-1 text-[8px] bg-orange-200 text-orange-700 border-orange-300">조인</Badge>
                          )}
                          {isUsed && (
                            <Badge className="text-white text-[8px] px-1 py-0 h-4 bg-primary">필드</Badge>
                          )}
                          <span className="text-muted-foreground text-[10px] w-20 truncate text-right" title={col.dataType}>
                            {col.dataType?.split("(")[0]}
                          </span>
                        </div>
                      </div>
                    );
                  });
                  })()}
                </div>

                {/* 오른쪽: 컬럼 설정 패널 */}
                <div className="w-52 border-l pl-3 flex-shrink-0 max-h-[350px] overflow-y-auto">
                  {editingField ? (() => {
                    const selectedMapping = columnMappings.find(m => m.fieldLabel === editingField);
                    const selectedColumn = selectedMapping 
                      ? columns.find(c => c.columnName.toLowerCase() === selectedMapping.columnName?.toLowerCase())
                      : columns.find(c => (c.displayName || c.columnName) === editingField || c.columnName === editingField);
                    const colNameLower = selectedColumn?.columnName?.toLowerCase() || editingField.toLowerCase();
                    const { isFilterKey, isJoinKey, joinRef, isUsed } = getColumnState(colNameLower);
                    
                    // 조인 정보 - joinColumnRefs에서 먼저 찾고, 없으면 selectedColumn에서 가져옴
                    const hasJoinSetting = isJoinKey || !!selectedColumn?.referenceTable;
                    
                    return (
                      <div className="space-y-3">
                        <div className="text-xs font-medium text-foreground">컬럼 설정</div>
                        
                        {/* 화면 필드 정보 (필드인 경우만) */}
                        {isUsed && (
                          <>
                            <div className="space-y-1">
                              <span className="text-[10px] text-muted-foreground">화면 필드</span>
                              <div className="text-sm font-medium text-primary">
                                {selectedColumn?.displayName || selectedMapping?.columnName || editingField}
                              </div>
                            </div>
                            
                            <div className="space-y-1">
                              <span className="text-[10px] text-muted-foreground">현재 컬럼</span>
                              <div className="text-sm font-mono text-muted-foreground">
                                {selectedMapping?.columnName || "-"}
                              </div>
                            </div>
                            
                            <div className="space-y-1">
                              <span className="text-[10px] text-muted-foreground">컬럼 변경</span>
                              <Popover>
                                <PopoverTrigger asChild>
                                  <Button variant="outline" size="sm" className="w-full justify-between h-7 text-xs">
                                    {selectedColumn?.displayName || selectedMapping?.columnName || "컬럼 선택"}
                                    <ChevronsUpDown className="h-3 w-3 opacity-50" />
                                  </Button>
                                </PopoverTrigger>
                                <PopoverContent className="p-0 w-48" align="start">
                                  <Command>
                                    <CommandInput placeholder="컬럼 검색..." className="h-8 text-xs" />
                                    <CommandList className="max-h-32">
                                      <CommandEmpty className="text-xs py-2">없음</CommandEmpty>
                                      <CommandGroup>
                                        {columns.map((c) => (
                                          <CommandItem
                                            key={c.columnName}
                                            value={c.displayName || c.columnName}
                                            onSelect={() => {
                                              if (onColumnChange && selectedMapping) {
                                                onColumnChange(editingField, selectedMapping.columnName, c.columnName);
                                              }
                                              setEditingField(null);
                                            }}
                                          >
                                            <Check className={`mr-2 h-3 w-3 ${c.columnName.toLowerCase() === selectedMapping?.columnName?.toLowerCase() ? "opacity-100" : "opacity-0"}`} />
                                            {c.displayName || c.columnName}
                                          </CommandItem>
                                        ))}
                                      </CommandGroup>
                                    </CommandList>
                                  </Command>
                                </PopoverContent>
                              </Popover>
                            </div>
                            
                            {/* 필드에서 제거 */}
                            <Button
                              variant="outline"
                              size="sm"
                              className="w-full h-7 text-xs text-destructive border-destructive/30 hover:bg-destructive/10"
                              onClick={() => {
                                if (selectedMapping && onColumnChange) {
                                  onColumnChange(selectedMapping.fieldLabel!, selectedMapping.columnName, "__REMOVE_FIELD__");
                                  toast.success(`"${selectedColumn?.displayName || selectedMapping.columnName}" 필드가 제거되었습니다.`);
                                  setEditingField(null);
                                }
                              }}
                            >
                              <X className="h-3 w-3 mr-1" />
                              필드에서 제거
                            </Button>
                          </>
                        )}
                        
                        {/* 컬럼 기본 정보 (필드가 아닌 경우) */}
                        {!isUsed && (
                          <div className="space-y-3">
                            <div className="text-xs text-muted-foreground">
                              <div className="space-y-1">
                                <span className="text-[10px]">컬럼명</span>
                                <div className="font-mono">{selectedColumn?.columnName || editingField}</div>
                              </div>
                              <div className="space-y-1 mt-2">
                                <span className="text-[10px]">데이터 타입</span>
                                <div>{selectedColumn?.dataType || "-"}</div>
                              </div>
                            </div>
                            
                            <Button
                              variant="outline"
                              size="sm"
                              className="w-full h-7 text-xs text-primary border-primary/40 hover:bg-primary/10"
                              onClick={() => {
                                if (selectedColumn?.columnName && onColumnChange) {
                                  onColumnChange("__NEW_FIELD__", "", selectedColumn.columnName);
                                  toast.success(`"${selectedColumn.displayName || selectedColumn.columnName}" 필드가 추가되었습니다.`);
                                  setEditingField(null);
                                }
                              }}
                            >
                              <Plus className="h-3 w-3 mr-1" />
                              필드로 추가
                            </Button>
                          </div>
                        )}
                        
                        {/* 조인 설정 */}
                        <div className="space-y-2 pt-2 border-t border-orange-200">
                          <div className="flex items-center justify-between">
                            <div className="flex items-center gap-1">
                              <Badge variant="outline" className={`h-4 px-1 text-[8px] ${hasJoinSetting ? "bg-orange-200 text-orange-700 border-orange-300" : "bg-muted text-muted-foreground border-input"}`}>
                                조인
                              </Badge>
                              <span className={`text-[10px] font-medium ${hasJoinSetting ? "text-orange-700" : "text-muted-foreground"}`}>
                                {editingJoin && editingJoin.columnName === (selectedColumn?.columnName || editingField) ? "연결 편집" : (hasJoinSetting ? "연결 정보" : "연결 설정")}
                              </span>
                            </div>
                            {editingJoin && editingJoin.columnName === (selectedColumn?.columnName || editingField) ? (
                              <div className="flex gap-1">
                                <Button variant="ghost" size="sm" className="h-5 px-1.5 text-[10px] text-muted-foreground hover:text-foreground" onClick={() => setEditingJoin(null)}>
                                  취소
                                </Button>
                                <Button size="sm" className="h-5 px-1.5 text-[10px] bg-amber-500 hover:bg-orange-600 text-white" onClick={handleSaveJoinSetting} disabled={!editingJoin.referenceTable || !editingJoin.referenceColumn || savingJoinSetting}>
                                  {savingJoinSetting ? "..." : "저장"}
                                </Button>
                              </div>
                            ) : (
                              <Button
                                variant="ghost"
                                size="sm"
                                className={`h-5 px-1 text-[10px] ${hasJoinSetting ? "text-amber-600 hover:text-orange-800" : "text-muted-foreground hover:text-foreground"}`}
                                onClick={() => startEditingJoin(
                                  selectedColumn?.columnName || editingField,
                                  isJoinKey && joinRef ? joinRef.refTable : (selectedColumn?.referenceTable || ""),
                                  isJoinKey && joinRef ? joinRef.refColumn : (selectedColumn?.referenceColumn || ""),
                                  selectedColumn?.displayColumn || ""
                                )}
                              >
                                <Settings2 className="h-3 w-3 mr-0.5" />
                                {hasJoinSetting ? "편집" : "추가"}
                              </Button>
                            )}
                          </div>
                          
                          {editingJoin && editingJoin.columnName === (selectedColumn?.columnName || editingField) ? (
                            <JoinSettingEditor
                              editingJoin={editingJoin}
                              setEditingJoin={setEditingJoin}
                              allTables={allTables}
                              refTableColumns={refTableColumns}
                              loadingRefColumns={loadingRefColumns}
                              savingJoinSetting={savingJoinSetting}
                              loadRefTableColumns={loadRefTableColumns}
                              handleSaveJoinSetting={handleSaveJoinSetting}
                            />
                          ) : hasJoinSetting ? (
                            <div className="space-y-1.5 text-xs">
                              <div>
                                <span className="text-muted-foreground">대상 테이블: </span>
                                <span className="font-mono text-orange-800">{isJoinKey && joinRef ? joinRef.refTable : selectedColumn?.referenceTable}</span>
                              </div>
                              <div>
                                <span className="text-muted-foreground">연결 컬럼: </span>
                                <span className="font-mono text-orange-800">{isJoinKey && joinRef ? joinRef.refColumn : selectedColumn?.referenceColumn}</span>
                              </div>
                            </div>
                          ) : (
                            <div className="text-[10px] text-muted-foreground">조인 설정이 없습니다.</div>
                          )}
                        </div>
                        
                        {/* 필터 정보 (필터 키인 경우) - 필터 테이블에서만 */}
                        {!isMain && isFilterKey && filterKeyMapping && (
                          <div className="space-y-2 pt-2 border-t border-purple-200">
                            <div className="flex items-center gap-1">
                              <Badge variant="outline" className="h-4 px-1 text-[8px] bg-purple-200 text-purple-700 border-purple-300">필터</Badge>
                              <span className="text-[10px] text-purple-700 font-medium">필터링 정보</span>
                            </div>
                            <div className="space-y-1.5 text-xs">
                              <div>
                                <span className="text-muted-foreground">대상 테이블: </span>
                                <span className="font-mono text-purple-800">{mainTable}</span>
                              </div>
                              <div>
                                <span className="text-muted-foreground">연결 컬럼: </span>
                                <span className="font-mono text-purple-800">{filterKeyMapping.mainTableColumn}</span>
                              </div>
                            </div>
                          </div>
                        )}
                      </div>
                    );
                  })() : (
                    <div className="flex items-center justify-center h-full text-xs text-muted-foreground">
                      필드를 선택하세요
                    </div>
                  )}
                </div>
              </div>
            ) : (
              <div className="text-xs text-muted-foreground text-center py-2">컬럼 정보 없음</div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

// ============================================================
// 조인 설정 편집 컴포넌트 (검색 가능한 Combobox 사용)
// ============================================================

interface JoinSettingEditorProps {
  editingJoin: {
    columnName: string;
    referenceTable: string;
    referenceColumn: string;
    displayColumn: string;
  };
  setEditingJoin: React.Dispatch<React.SetStateAction<{
    columnName: string;
    referenceTable: string;
    referenceColumn: string;
    displayColumn: string;
  } | null>>;
  allTables: TableInfo[];
  refTableColumns: ColumnTypeInfo[];
  loadingRefColumns: boolean;
  savingJoinSetting: boolean;
  loadRefTableColumns: (tableName: string) => void;
  handleSaveJoinSetting: () => void;
}

function JoinSettingEditor({
  editingJoin,
  setEditingJoin,
  allTables,
  refTableColumns,
  loadingRefColumns,
  savingJoinSetting,
  loadRefTableColumns,
  handleSaveJoinSetting,
}: JoinSettingEditorProps) {
  const [tableSearchOpen, setTableSearchOpen] = useState(false);
  const [refColSearchOpen, setRefColSearchOpen] = useState(false);
  const [displayColSearchOpen, setDisplayColSearchOpen] = useState(false);
  
  const selectedTable = allTables.find(t => t.tableName === editingJoin.referenceTable);
  const selectedRefCol = refTableColumns.find(c => c.columnName === editingJoin.referenceColumn);
  const selectedDisplayCol = refTableColumns.find(c => c.columnName === editingJoin.displayColumn);
  
  return (
    <div className="space-y-2">
      {/* 대상 테이블 선택 - 검색 가능 Combobox */}
      <div className="space-y-1">
        <span className="text-[10px] text-muted-foreground">대상 테이블</span>
        <Popover open={tableSearchOpen} onOpenChange={setTableSearchOpen}>
          <PopoverTrigger asChild>
            <Button
              variant="outline"
              size="sm"
              className="w-full justify-between h-7 text-xs font-normal"
            >
              {selectedTable?.displayName || editingJoin.referenceTable || "테이블 선택"}
              <ChevronsUpDown className="h-3 w-3 opacity-50" />
            </Button>
          </PopoverTrigger>
          <PopoverContent className="p-0 w-56" align="start">
            <Command>
              <CommandInput placeholder="테이블 검색..." className="h-8 text-xs" />
              <CommandList>
                <CommandEmpty className="text-xs py-2">테이블을 찾을 수 없습니다.</CommandEmpty>
                <CommandGroup>
                  {allTables.map((t, idx) => (
                    <CommandItem
                      key={`${t.tableName}-${idx}`}
                      value={t.displayName || t.tableName}
                      onSelect={() => {
                        setEditingJoin({ ...editingJoin, referenceTable: t.tableName, referenceColumn: "", displayColumn: "" });
                        loadRefTableColumns(t.tableName);
                        setTableSearchOpen(false);
                      }}
                      className="text-xs"
                    >
                      <Check
                        className={cn(
                          "mr-2 h-3 w-3",
                          editingJoin.referenceTable === t.tableName ? "opacity-100" : "opacity-0"
                        )}
                      />
                      {t.displayName || t.tableName}
                    </CommandItem>
                  ))}
                </CommandGroup>
              </CommandList>
            </Command>
          </PopoverContent>
        </Popover>
      </div>
      
      {/* 연결 컬럼 선택 - 검색 가능 Combobox */}
      <div className="space-y-1">
        <span className="text-[10px] text-muted-foreground">연결 컬럼 (PK)</span>
        <Popover open={refColSearchOpen} onOpenChange={setRefColSearchOpen}>
          <PopoverTrigger asChild>
            <Button
              variant="outline"
              size="sm"
              className="w-full justify-between h-7 text-xs font-normal"
              disabled={!editingJoin.referenceTable || loadingRefColumns}
            >
              {loadingRefColumns ? "로딩중..." : (selectedRefCol?.displayName || editingJoin.referenceColumn || "컬럼 선택")}
              <ChevronsUpDown className="h-3 w-3 opacity-50" />
            </Button>
          </PopoverTrigger>
          <PopoverContent className="p-0 w-56" align="start">
            <Command>
              <CommandInput placeholder="컬럼 검색..." className="h-8 text-xs" />
              <CommandList>
                <CommandEmpty className="text-xs py-2">컬럼을 찾을 수 없습니다.</CommandEmpty>
                <CommandGroup>
                  {refTableColumns.map(c => (
                    <CommandItem
                      key={c.columnName}
                      value={c.displayName || c.columnName}
                      onSelect={() => {
                        setEditingJoin({ ...editingJoin, referenceColumn: c.columnName });
                        setRefColSearchOpen(false);
                      }}
                      className="text-xs"
                    >
                      <Check
                        className={cn(
                          "mr-2 h-3 w-3",
                          editingJoin.referenceColumn === c.columnName ? "opacity-100" : "opacity-0"
                        )}
                      />
                      {c.displayName || c.columnName}
                    </CommandItem>
                  ))}
                </CommandGroup>
              </CommandList>
            </Command>
          </PopoverContent>
        </Popover>
      </div>
      
      {/* 표시 컬럼 선택 - 검색 가능 Combobox */}
      <div className="space-y-1">
        <span className="text-[10px] text-muted-foreground">표시 컬럼</span>
        <Popover open={displayColSearchOpen} onOpenChange={setDisplayColSearchOpen}>
          <PopoverTrigger asChild>
            <Button
              variant="outline"
              size="sm"
              className="w-full justify-between h-7 text-xs font-normal"
              disabled={!editingJoin.referenceTable || loadingRefColumns}
            >
              {selectedDisplayCol?.displayName || editingJoin.displayColumn || "컬럼 선택"}
              <ChevronsUpDown className="h-3 w-3 opacity-50" />
            </Button>
          </PopoverTrigger>
          <PopoverContent className="p-0 w-56" align="start">
            <Command>
              <CommandInput placeholder="컬럼 검색..." className="h-8 text-xs" />
              <CommandList>
                <CommandEmpty className="text-xs py-2">컬럼을 찾을 수 없습니다.</CommandEmpty>
                <CommandGroup>
                  {refTableColumns.map(c => (
                    <CommandItem
                      key={c.columnName}
                      value={c.displayName || c.columnName}
                      onSelect={() => {
                        setEditingJoin({ ...editingJoin, displayColumn: c.columnName });
                        setDisplayColSearchOpen(false);
                      }}
                      className="text-xs"
                    >
                      <Check
                        className={cn(
                          "mr-2 h-3 w-3",
                          editingJoin.displayColumn === c.columnName ? "opacity-100" : "opacity-0"
                        )}
                      />
                      {c.displayName || c.columnName}
                    </CommandItem>
                  ))}
                </CommandGroup>
              </CommandList>
            </Command>
          </PopoverContent>
        </Popover>
      </div>
      
    </div>
  );
}

// ============================================================
// 탭 1: 화면 개요
// ============================================================

interface OverviewTabProps {
  screenId: number;
  screenName: string;
  mainTable?: string;
  mainTableLabel?: string;
  filterTables: FilterTableInfo[];
  fieldMappings: FieldMappingInfo[];
  componentCount: number;
  dataFlows: DataFlow[];
  layoutItems: LayoutItem[]; // 컴포넌트 컬럼 정보 추가
  loading: boolean;
  onRefresh?: () => void; // 컬럼 변경 후 새로고침 콜백
  onOpenTableSetting?: (tableName: string, tableLabel?: string) => void; // 테이블 설정 모달 열기
}

function OverviewTab({
  screenId,
  screenName,
  mainTable,
  mainTableLabel,
  filterTables,
  fieldMappings,
  componentCount,
  dataFlows,
  layoutItems,
  loading,
  onRefresh,
  onOpenTableSetting,
}: OverviewTabProps) {
  const [isSavingColumn, setIsSavingColumn] = useState(false);

  // 컬럼 변경 저장 함수 - 화면 디자이너와 동일한 방식
  const handleColumnChange = useCallback(async (fieldLabel: string, oldColumn: string, newColumn: string) => {
    console.log("[handleColumnChange] 시작", { screenId, fieldLabel, oldColumn, newColumn });
    
    if (!screenId) {
      toast.error("화면 정보가 없습니다.");
      return;
    }

    // 필드 추가/제거 처리
    const isAddingField = fieldLabel === "__NEW_FIELD__";
    const isRemovingField = newColumn === "__REMOVE_FIELD__";

    setIsSavingColumn(true);
    try {
      // 1. 현재 레이아웃 가져오기
      console.log("[handleColumnChange] 레이아웃 조회 시작", { screenId });
      const currentLayout = await screenApi.getLayout(screenId);
      console.log("[handleColumnChange] 레이아웃 조회 완료", { 
        hasLayout: !!currentLayout, 
        hasComponents: !!currentLayout?.components,
        componentCount: currentLayout?.components?.length 
      });
      
      if (!currentLayout?.components) {
        toast.error("레이아웃 정보를 불러올 수 없습니다.");
        console.error("[handleColumnChange] 레이아웃 정보 없음", { currentLayout });
        return;
      }

      // 2. 레이아웃에서 해당 컬럼 변경
      let columnChanged = false;
      
      // 디버깅: 각 컴포넌트의 구조 확인
      console.log("[handleColumnChange] 컴포넌트 구조 분석 시작");
      currentLayout.components.forEach((comp: any, i: number) => {
        console.log(`[handleColumnChange] 컴포넌트 ${i}:`, {
          id: comp.id,
          componentType: comp.componentType,
          hasUsedColumns: !!comp.usedColumns,
          usedColumns: comp.usedColumns,
          hasComponentConfig: !!comp.componentConfig,
          componentConfigKeys: comp.componentConfig ? Object.keys(comp.componentConfig) : [],
          componentConfigColumns: comp.componentConfig?.columns,
          componentConfigUsedColumns: comp.componentConfig?.usedColumns,
          columnName: comp.columnName,
          bindField: comp.bindField,
        });
      });
      
      let updatedComponents = currentLayout.components.map((comp: any) => {
        // usedColumns 배열이 있는 컴포넌트에서 oldColumn을 newColumn으로 교체
        if (comp.usedColumns && Array.isArray(comp.usedColumns)) {
          // 필드 추가
          if (isAddingField) {
            console.log("[handleColumnChange] usedColumns에 필드 추가", { compId: comp.id, newColumn });
            columnChanged = true;
            return {
              ...comp,
              usedColumns: [...comp.usedColumns, newColumn],
            };
          }
          
          const idx = comp.usedColumns.findIndex(
            (col: string) => col.toLowerCase() === oldColumn.toLowerCase()
          );
          if (idx !== -1) {
            console.log("[handleColumnChange] usedColumns에서 찾음", { compId: comp.id, idx, isRemovingField });
            columnChanged = true;
            
            // 필드 제거
            if (isRemovingField) {
              return {
                ...comp,
                usedColumns: comp.usedColumns.filter((_: string, i: number) => i !== idx),
              };
            }
            
            // 컬럼 변경
            return {
              ...comp,
              usedColumns: comp.usedColumns.map((col: string, i: number) =>
                i === idx ? newColumn : col
              ),
            };
          }
        }
        
        // componentConfig 내부의 usedColumns도 확인
        if (comp.componentConfig?.usedColumns && Array.isArray(comp.componentConfig.usedColumns)) {
          // 필드 추가
          if (isAddingField && !columnChanged) {
            console.log("[handleColumnChange] componentConfig.usedColumns에 필드 추가", { compId: comp.id, newColumn });
            columnChanged = true;
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                usedColumns: [...comp.componentConfig.usedColumns, newColumn],
              },
            };
          }
          
          const idx = comp.componentConfig.usedColumns.findIndex(
            (col: string) => col.toLowerCase() === oldColumn.toLowerCase()
          );
          if (idx !== -1) {
            console.log("[handleColumnChange] componentConfig.usedColumns에서 찾음", { compId: comp.id, idx, isRemovingField });
            columnChanged = true;
            
            // 필드 제거
            if (isRemovingField) {
              return {
                ...comp,
                componentConfig: {
                  ...comp.componentConfig,
                  usedColumns: comp.componentConfig.usedColumns.filter((_: string, i: number) => i !== idx),
                },
              };
            }
            
            // 컬럼 변경
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                usedColumns: comp.componentConfig.usedColumns.map((col: string, i: number) =>
                  i === idx ? newColumn : col
                ),
              },
            };
          }
        }
        
        // componentConfig.columns 배열도 확인 (컬럼 설정 형태)
        if (comp.componentConfig?.columns && Array.isArray(comp.componentConfig.columns)) {
          // 필드 추가
          if (isAddingField && !columnChanged) {
            console.log("[handleColumnChange] componentConfig.columns에 필드 추가", { compId: comp.id, newColumn });
            columnChanged = true;
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                columns: [...comp.componentConfig.columns, { field: newColumn, columnName: newColumn }],
              },
            };
          }
          
          const columnIdx = comp.componentConfig.columns.findIndex(
            (col: any) => {
              const colName = typeof col === 'string' ? col : (col.field || col.columnName || col.name);
              return colName?.toLowerCase() === oldColumn.toLowerCase();
            }
          );
          if (columnIdx !== -1) {
            console.log("[handleColumnChange] componentConfig.columns에서 찾음", { compId: comp.id, columnIdx, isRemovingField });
            columnChanged = true;
            
            // 필드 제거
            if (isRemovingField) {
              return {
                ...comp,
                componentConfig: {
                  ...comp.componentConfig,
                  columns: comp.componentConfig.columns.filter((_: any, i: number) => i !== columnIdx),
                },
              };
            }
            
            // 컬럼 변경
            const updatedColumns = comp.componentConfig.columns.map((col: any, i: number) => {
              if (i !== columnIdx) return col;
              if (typeof col === 'string') return newColumn;
              return { ...col, field: newColumn, columnName: newColumn };
            });
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                columns: updatedColumns,
              },
            };
          }
        }

        // columnName 필드 체크 (위젯 컴포넌트)
        if (comp.columnName?.toLowerCase() === oldColumn.toLowerCase()) {
          console.log("[handleColumnChange] columnName에서 찾음", { compId: comp.id });
          columnChanged = true;
          return {
            ...comp,
            columnName: newColumn,
          };
        }
        
        // bindField 필드 체크 (바인딩 필드)
        if (comp.bindField?.toLowerCase() === oldColumn.toLowerCase()) {
          console.log("[handleColumnChange] bindField에서 찾음", { compId: comp.id });
          columnChanged = true;
          return {
            ...comp,
            bindField: newColumn,
          };
        }
        
        // split-panel-layout의 leftPanel.columns 검사
        if (comp.componentConfig?.leftPanel?.columns && Array.isArray(comp.componentConfig.leftPanel.columns)) {
          const leftColumns = comp.componentConfig.leftPanel.columns;
          console.log("[handleColumnChange] leftPanel.columns 검사:", {
            compId: comp.id,
            leftColumnsCount: leftColumns.length,
            leftColumnsContent: leftColumns.map((col: any) => typeof col === 'string' ? col : (col.name || col.columnName || col.field)),
            searchingFor: isAddingField ? newColumn : oldColumn.toLowerCase(),
            isAddingField,
            isRemovingField,
          });
          
          // 필드 추가: 배열에 새 컬럼 추가
          if (isAddingField) {
            console.log("[handleColumnChange] 필드 추가", { compId: comp.id, newColumn });
            columnChanged = true;
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                leftPanel: {
                  ...comp.componentConfig.leftPanel,
                  columns: [...leftColumns, { name: newColumn, columnName: newColumn }],
                },
              },
            };
          }
          
          const columnIdx = leftColumns.findIndex((col: any) => {
            const colName = typeof col === 'string' ? col : (col.name || col.columnName || col.field);
            return colName?.toLowerCase() === oldColumn.toLowerCase();
          });
          if (columnIdx !== -1) {
            console.log("[handleColumnChange] leftPanel.columns에서 찾음", { compId: comp.id, columnIdx, isRemovingField });
            columnChanged = true;
            
            // 필드 제거: 배열에서 해당 컬럼 제거
            if (isRemovingField) {
              const filteredColumns = leftColumns.filter((_: any, i: number) => i !== columnIdx);
              return {
                ...comp,
                componentConfig: {
                  ...comp.componentConfig,
                  leftPanel: {
                    ...comp.componentConfig.leftPanel,
                    columns: filteredColumns,
                  },
                },
              };
            }
            
            // 컬럼 변경
            const updatedLeftColumns = leftColumns.map((col: any, i: number) => {
              if (i !== columnIdx) return col;
              if (typeof col === 'string') return newColumn;
              // 객체인 경우 name/columnName 필드 업데이트
              return { ...col, name: newColumn, columnName: newColumn };
            });
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                leftPanel: {
                  ...comp.componentConfig.leftPanel,
                  columns: updatedLeftColumns,
                },
              },
            };
          }
        }
        
        // split-panel-layout의 rightPanel.columns 검사
        if (comp.componentConfig?.rightPanel?.columns && Array.isArray(comp.componentConfig.rightPanel.columns)) {
          const rightColumns = comp.componentConfig.rightPanel.columns;
          
          // 필드 추가: 배열에 새 컬럼 추가
          if (isAddingField && !columnChanged) {
            console.log("[handleColumnChange] 필드 추가 (rightPanel)", { compId: comp.id, newColumn });
            columnChanged = true;
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                rightPanel: {
                  ...comp.componentConfig.rightPanel,
                  columns: [...rightColumns, { name: newColumn, columnName: newColumn }],
                },
              },
            };
          }
          
          const columnIdx = rightColumns.findIndex((col: any) => {
            const colName = typeof col === 'string' ? col : (col.name || col.columnName || col.field);
            return colName?.toLowerCase() === oldColumn.toLowerCase();
          });
          if (columnIdx !== -1) {
            console.log("[handleColumnChange] rightPanel.columns에서 찾음", { compId: comp.id, columnIdx, isRemovingField });
            columnChanged = true;
            
            // 필드 제거
            if (isRemovingField) {
              const filteredColumns = rightColumns.filter((_: any, i: number) => i !== columnIdx);
              return {
                ...comp,
                componentConfig: {
                  ...comp.componentConfig,
                  rightPanel: {
                    ...comp.componentConfig.rightPanel,
                    columns: filteredColumns,
                  },
                },
              };
            }
            
            // 컬럼 변경
            const updatedRightColumns = rightColumns.map((col: any, i: number) => {
              if (i !== columnIdx) return col;
              if (typeof col === 'string') return newColumn;
              return { ...col, name: newColumn, columnName: newColumn };
            });
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                rightPanel: {
                  ...comp.componentConfig.rightPanel,
                  columns: updatedRightColumns,
                },
              },
            };
          }
        }

        return comp;
      });

      // 폼 화면용 필드 추가/제거 처리 (개별 input 컴포넌트)
      if (!columnChanged) {
        // 폼 화면 필드 추가: 새 text-input 컴포넌트 생성
        if (isAddingField && newColumn) {
          console.log("[handleColumnChange] 폼 화면 필드 추가 시도", { newColumn });
          
          // 마지막 컴포넌트 위치 계산
          let maxY = 50; // 기본 시작 위치
          let lastComponentHeight = 30;
          currentLayout.components.forEach((comp: any) => {
            const compY = comp.position?.y || 0;
            const compHeight = comp.size?.height || 30;
            if (compY + compHeight > maxY) {
              maxY = compY + compHeight;
              lastComponentHeight = compHeight;
            }
          });
          
          // 새 컴포넌트 위치: 마지막 컴포넌트 아래 + 간격
          const newY = maxY + 10;
          const newComponentId = `comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
          
          // 새 text-input 컴포넌트 생성
          const newComponent = {
            id: newComponentId,
            type: "component",
            label: newColumn,
            columnName: newColumn,
            bindField: newColumn,
            widgetType: "text-input",
            componentType: "text-input",
            position: { x: 20, y: newY, z: 1 },
            size: { width: 300, height: 30 },
            gridColumns: 4,
            componentConfig: {
              type: "text-input",
              webType: "text-input",
              placeholder: `${newColumn}을(를) 입력하세요`,
            },
            webTypeConfig: {},
            style: {
              labelDisplay: true,
              labelFontSize: "14px",
              labelColor: "#212121",
              width: "300px",
              height: "30px",
            },
          };
          
          updatedComponents = [...updatedComponents, newComponent];
          columnChanged = true;
          console.log("[handleColumnChange] 폼 화면 필드 추가 완료", { newComponentId, newY });
        }
        
        // 폼 화면 필드 제거: bindField가 일치하는 컴포넌트 삭제
        if (isRemovingField && oldColumn) {
          console.log("[handleColumnChange] 폼 화면 필드 제거 시도", { oldColumn });
          
          const beforeCount = updatedComponents.length;
          updatedComponents = updatedComponents.filter((comp: any) => {
            // bindField, columnName, 또는 properties.columnName으로 매칭
            const compBindField = comp.bindField || comp.columnName || comp.properties?.columnName;
            if (compBindField?.toLowerCase() === oldColumn.toLowerCase()) {
              console.log("[handleColumnChange] 폼 컴포넌트 제거", { compId: comp.id, compBindField });
              return false; // 제거
            }
            return true; // 유지
          });
          
          if (beforeCount > updatedComponents.length) {
            columnChanged = true;
            console.log("[handleColumnChange] 폼 화면 필드 제거 완료", { 
              beforeCount, 
              afterCount: updatedComponents.length 
            });
          }
        }
      }

      if (!columnChanged) {
        toast.warning("변경할 컬럼을 찾을 수 없습니다.");
        console.warn("[handleColumnChange] 변경할 컬럼 없음", { oldColumn, newColumn });
        return;
      }

      // 3. 저장
      console.log("[handleColumnChange] 저장 시작", { 
        screenId, 
        componentCount: updatedComponents.length 
      });
      await screenApi.saveLayout(screenId, {
        ...currentLayout,
        components: updatedComponents,
      });
      console.log("[handleColumnChange] 저장 완료");

      if (isAddingField) {
        toast.success(`필드가 추가되었습니다: ${newColumn}`);
      } else if (isRemovingField) {
        toast.success(`필드가 제거되었습니다: ${oldColumn}`);
      } else {
        toast.success(`컬럼이 변경되었습니다: ${oldColumn} → ${newColumn}`);
      }
      
      // 실시간 반영을 위해 콜백 호출
      onRefresh?.();
    } catch (error) {
      console.error("컬럼 변경 저장 실패:", error);
      toast.error("컬럼 변경 저장에 실패했습니다.");
    } finally {
      setIsSavingColumn(false);
    }
  }, [screenId, onRefresh]);

  // 컬럼 순서 변경 저장 함수
  const handleColumnReorder = useCallback(async (tableType: "main" | "filter", newOrder: string[]) => {
    console.log("[handleColumnReorder] 시작", { screenId, tableType, newOrder });
    
    if (!screenId) {
      console.warn("[handleColumnReorder] screenId 없음");
      return;
    }

    try {
      // 1. 현재 레이아웃 가져오기
      const currentLayout = await screenApi.getLayout(screenId);
      
      if (!currentLayout?.components) {
        console.error("[handleColumnReorder] 레이아웃 정보 없음");
        return;
      }

      // 2. 레이아웃에서 해당 컬럼들의 순서 변경
      let orderChanged = false;
      
      const updatedComponents = currentLayout.components.map((comp: any) => {
        // split-panel-layout의 leftPanel.columns 순서 변경
        if (comp.componentConfig?.leftPanel?.columns && Array.isArray(comp.componentConfig.leftPanel.columns)) {
          const leftColumns = comp.componentConfig.leftPanel.columns as any[];
          
          // newOrder에 따라 leftColumns 재정렬
          const reorderedColumns = newOrder.map(colName => {
            return leftColumns.find((col: any) => {
              const name = typeof col === 'string' ? col : (col.name || col.columnName || col.field);
              return name?.toLowerCase() === colName.toLowerCase();
            });
          }).filter(Boolean);
          
          // 원래 없던 컬럼들 유지 (newOrder에 없는 컬럼들)
          const remainingColumns = leftColumns.filter((col: any) => {
            const name = typeof col === 'string' ? col : (col.name || col.columnName || col.field);
            return !newOrder.some(n => n.toLowerCase() === name?.toLowerCase());
          });
          
          if (reorderedColumns.length > 0) {
            orderChanged = true;
            console.log("[handleColumnReorder] leftPanel.columns 순서 변경", {
              compId: comp.id,
              before: leftColumns.map((c: any) => typeof c === 'string' ? c : (c.name || c.columnName)),
              after: [...reorderedColumns, ...remainingColumns].map((c: any) => typeof c === 'string' ? c : (c.name || c.columnName)),
            });
            
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                leftPanel: {
                  ...comp.componentConfig.leftPanel,
                  columns: [...reorderedColumns, ...remainingColumns],
                },
              },
            };
          }
        }
        
        // rightPanel.columns 순서 변경
        if (comp.componentConfig?.rightPanel?.columns && Array.isArray(comp.componentConfig.rightPanel.columns)) {
          const rightColumns = comp.componentConfig.rightPanel.columns as any[];
          
          const reorderedColumns = newOrder.map(colName => {
            return rightColumns.find((col: any) => {
              const name = typeof col === 'string' ? col : (col.name || col.columnName || col.field);
              return name?.toLowerCase() === colName.toLowerCase();
            });
          }).filter(Boolean);
          
          const remainingColumns = rightColumns.filter((col: any) => {
            const name = typeof col === 'string' ? col : (col.name || col.columnName || col.field);
            return !newOrder.some(n => n.toLowerCase() === name?.toLowerCase());
          });
          
          if (reorderedColumns.length > 0) {
            orderChanged = true;
            console.log("[handleColumnReorder] rightPanel.columns 순서 변경", {
              compId: comp.id,
              before: rightColumns.map((c: any) => typeof c === 'string' ? c : (c.name || c.columnName)),
              after: [...reorderedColumns, ...remainingColumns].map((c: any) => typeof c === 'string' ? c : (c.name || c.columnName)),
            });
            
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                rightPanel: {
                  ...comp.componentConfig.rightPanel,
                  columns: [...reorderedColumns, ...remainingColumns],
                },
              },
            };
          }
        }
        
        // componentConfig.usedColumns 순서 변경
        if (comp.componentConfig?.usedColumns && Array.isArray(comp.componentConfig.usedColumns)) {
          const usedColumns = comp.componentConfig.usedColumns as string[];
          
          const reorderedColumns = newOrder.filter(colName => 
            usedColumns.some(c => c.toLowerCase() === colName.toLowerCase())
          );
          
          const remainingColumns = usedColumns.filter(c => 
            !newOrder.some(n => n.toLowerCase() === c.toLowerCase())
          );
          
          if (reorderedColumns.length > 0) {
            orderChanged = true;
            console.log("[handleColumnReorder] usedColumns 순서 변경", {
              compId: comp.id,
              before: usedColumns,
              after: [...reorderedColumns, ...remainingColumns],
            });
            
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                usedColumns: [...reorderedColumns, ...remainingColumns],
              },
            };
          }
        }
        
        // componentConfig.columns 순서 변경
        if (comp.componentConfig?.columns && Array.isArray(comp.componentConfig.columns)) {
          const columns = comp.componentConfig.columns as any[];
          
          const reorderedColumns = newOrder.map(colName => {
            return columns.find((col: any) => {
              const name = typeof col === 'string' ? col : (col.field || col.columnName || col.name);
              return name?.toLowerCase() === colName.toLowerCase();
            });
          }).filter(Boolean);
          
          const remainingColumns = columns.filter((col: any) => {
            const name = typeof col === 'string' ? col : (col.field || col.columnName || col.name);
            return !newOrder.some(n => n.toLowerCase() === name?.toLowerCase());
          });
          
          if (reorderedColumns.length > 0) {
            orderChanged = true;
            console.log("[handleColumnReorder] componentConfig.columns 순서 변경", {
              compId: comp.id,
              before: columns.map((c: any) => typeof c === 'string' ? c : (c.field || c.columnName)),
              after: [...reorderedColumns, ...remainingColumns].map((c: any) => typeof c === 'string' ? c : (c.field || c.columnName)),
            });
            
            return {
              ...comp,
              componentConfig: {
                ...comp.componentConfig,
                columns: [...reorderedColumns, ...remainingColumns],
              },
            };
          }
        }
        
        return comp;
      });

      if (!orderChanged) {
        console.log("[handleColumnReorder] 순서 변경 없음");
        return;
      }

      // 3. 레이아웃 저장
      console.log("[handleColumnReorder] 레이아웃 저장");
      await screenApi.saveLayout(screenId, {
        ...currentLayout,
        components: updatedComponents,
      });

      console.log("[handleColumnReorder] 순서 변경 저장 완료");
      
      // 실시간 반영을 위해 콜백 호출
      onRefresh?.();
    } catch (error) {
      console.error("[handleColumnReorder] 순서 변경 저장 실패:", error);
      toast.error("컬럼 순서 변경 저장에 실패했습니다.");
    }
  }, [screenId, onRefresh]);

  // 통계 계산 (layoutItems의 컬럼 수도 포함)
  const stats = useMemo(() => {
    const totalJoins = filterTables.reduce(
      (sum, ft) => sum + (ft.joinColumnRefs?.length || 0),
      0
    );
    const totalFilters = filterTables.reduce(
      (sum, ft) => sum + (ft.filterColumns?.length || 0),
      0
    );

    // layoutItems에서 사용하는 컬럼 수 계산 (usedColumns + bindField)
    const layoutColumnsSet = new Set<string>();
    layoutItems.forEach((item) => {
      if (item.usedColumns) {
        item.usedColumns.forEach((col) => layoutColumnsSet.add(col));
      }
      // bindField도 포함 (인풋 필드 등)
      if (item.bindField) {
        layoutColumnsSet.add(item.bindField);
      }
    });
    const layoutColumnCount = layoutColumnsSet.size;

    return {
      tableCount: 1 + filterTables.length, // 메인 + 필터
      fieldCount: layoutColumnCount > 0 ? layoutColumnCount : fieldMappings.length,
      joinCount: totalJoins,
      filterCount: totalFilters,
      flowCount: dataFlows.length,
      usedFields: layoutColumnsSet, // 사용 중인 컬럼 Set
    };
  }, [filterTables, fieldMappings, dataFlows, layoutItems]);

  return (
    <div className="space-y-6">
      {/* 기본 정보 카드 */}
      <div className="grid grid-cols-2 gap-4 md:grid-cols-5">
        <div className="rounded-lg border bg-primary/10 p-4">
          <div className="text-2xl font-bold text-primary">{stats.tableCount}</div>
          <div className="text-xs text-primary">연결된 테이블</div>
        </div>
        <div className="rounded-lg border bg-purple-50 p-4">
          <div className="text-2xl font-bold text-purple-600">{stats.fieldCount}</div>
          <div className="text-xs text-purple-700">필드 매핑</div>
        </div>
        <div className="rounded-lg border bg-amber-50 p-4">
          <div className="text-2xl font-bold text-amber-600">{stats.joinCount}</div>
          <div className="text-xs text-orange-700">조인 설정</div>
        </div>
        <div className="rounded-lg border bg-emerald-50 p-4">
          <div className="text-2xl font-bold text-emerald-600">{stats.filterCount}</div>
          <div className="text-xs text-emerald-700">필터 컬럼</div>
        </div>
        <div className="rounded-lg border bg-pink-50 p-4">
          <div className="text-2xl font-bold text-pink-600">{stats.flowCount}</div>
          <div className="text-xs text-pink-700">데이터 흐름</div>
        </div>
      </div>

      {/* 메인 테이블 (아코디언 형식) */}
      <div className="space-y-2">
        <div className="flex items-center justify-between">
          <h3 className="flex items-center gap-2 text-sm font-semibold">
            <Database className="h-4 w-4 text-primary" />
            메인 테이블
          </h3>
        </div>
        {mainTable ? (
          <TableColumnAccordion 
            tableName={mainTable} 
            tableLabel={mainTableLabel}
            tableType="main"
            usedFields={stats.usedFields}
            columnMappings={
              // layoutItems에서 컬럼 매핑 정보 추출 (y 좌표 순서대로)
              layoutItems
                .slice()
                .sort((a, b) => a.y - b.y) // 화면 순서대로 정렬
                .flatMap((item, idx) => {
                  const cols: string[] = [];
                  // usedColumns에서 가져오기
                  if (item.usedColumns) {
                    cols.push(...item.usedColumns);
                  }
                  // bindField도 포함
                  if (item.bindField && !cols.includes(item.bindField)) {
                    cols.push(item.bindField);
                  }
                  return cols.map(col => ({
                    columnName: col,
                    fieldLabel: col,
                    order: idx * 100 + cols.indexOf(col),
                  }));
                })
                // 중복 제거 (첫 번째 매핑만 유지)
                .filter((mapping, idx, arr) => 
                  arr.findIndex(m => m.columnName.toLowerCase() === mapping.columnName.toLowerCase()) === idx
                )
            }
            onColumnChange={handleColumnChange}
            onColumnReorder={(newOrder) => handleColumnReorder("main", newOrder)}
            onJoinSettingSaved={onRefresh}
          />
        ) : (
          <div className="rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground">
            메인 테이블이 설정되지 않았습니다.
          </div>
        )}
      </div>

      {/* 연결된 필터 테이블 (아코디언 형식) */}
      <div className="space-y-2">
        <h3 className="flex items-center gap-2 text-sm font-semibold">
          <Link2 className="h-4 w-4 text-purple-500" />
          필터 테이블 ({filterTables.length}개)
        </h3>
        {filterTables.length > 0 ? (
          <div className="space-y-2">
            {filterTables.map((ft, idx) => {
              // 이 필터 테이블에서 사용되는 컬럼 매핑 정보 추출
              // 1. layoutItems의 usedColumns에서 추출
              const usedColumnMappings: ColumnMapping[] = layoutItems
                .slice()
                .sort((a, b) => a.y - b.y)
                .flatMap((item, itemIdx) => 
                  (item.usedColumns || []).map(col => ({
                    columnName: col,
                    fieldLabel: col,
                    order: itemIdx * 100 + (item.usedColumns?.indexOf(col) || 0),
                  }))
                );
              
              // 2. 조인 컬럼도 필드로 추가 (화면에서 조인 테이블 데이터를 보여주므로)
              const joinColumnMappings: ColumnMapping[] = (ft.joinColumnRefs || []).map((ref, refIdx) => ({
                columnName: ref.column,
                fieldLabel: ref.column,
                order: 1000 + refIdx, // 조인 컬럼은 후순위
              }));
              
              // 3. 합치고 중복 제거
              const filterTableColumnMappings: ColumnMapping[] = [...usedColumnMappings, ...joinColumnMappings]
                .filter((mapping, i, arr) => 
                  arr.findIndex(m => m.columnName.toLowerCase() === mapping.columnName.toLowerCase()) === i
                );
              
              return (
                <TableColumnAccordion
                  key={`${ft.tableName}-${idx}`}
                  tableName={ft.tableName}
                  tableLabel={ft.tableLabel}
                  tableType="filter"
                  mainTable={mainTable}
                  filterKeyMapping={ft.filterKeyMapping}
                  joinColumnRefs={ft.joinColumnRefs}
                  columnMappings={filterTableColumnMappings}
                  onColumnChange={handleColumnChange}
                  onColumnReorder={(newOrder) => handleColumnReorder("filter", newOrder)}
                  onJoinSettingSaved={onRefresh}
                />
              );
            })}
          </div>
        ) : (
          <div className="rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground">
            연결된 필터 테이블이 없습니다.
          </div>
        )}
      </div>

      {/* 데이터 흐름 요약 */}
      <div className="space-y-2">
        <h3 className="flex items-center gap-2 text-sm font-semibold">
          <GitBranch className="h-4 w-4 text-pink-500" />
          데이터 흐름 ({dataFlows.length}개)
        </h3>
        {dataFlows.length > 0 ? (
          <div className="space-y-2">
            {dataFlows.slice(0, 3).map((flow) => (
              <div
                key={flow.id}
                className="flex items-center gap-2 rounded-lg border bg-pink-50/50 p-3 text-sm"
              >
                <Badge variant="outline" className="bg-pink-100 text-pink-700">
                  {flow.flow_type}
                </Badge>
                <span className="flex-1">{flow.description || "설명 없음"}</span>
                <ArrowRight className="h-4 w-4 text-muted-foreground" />
                <span className="text-muted-foreground">화면 {flow.target_screen_id}</span>
              </div>
            ))}
            {dataFlows.length > 3 && (
              <div className="text-center text-xs text-muted-foreground">
                +{dataFlows.length - 3}개 더 있음
              </div>
            )}
          </div>
        ) : (
          <div className="rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground">
            설정된 데이터 흐름이 없습니다.
          </div>
        )}
      </div>
    </div>
  );
}

// ============================================================
// 탭 2: 필드 매핑
// ============================================================

interface FieldMappingTabProps {
  screenId: number;
  mainTable?: string;
  fieldMappings: FieldMappingInfo[];
  layoutItems: LayoutItem[];
  loading: boolean;
}

function FieldMappingTab({
  screenId,
  mainTable,
  fieldMappings,
  layoutItems,
  loading,
}: FieldMappingTabProps) {
  // 편집 모드 상태
  const [isEditMode, setIsEditMode] = useState(false);
  // 테이블 컬럼 목록 (편집용)
  const [tableColumns, setTableColumns] = useState<ColumnTypeInfo[]>([]);
  const [loadingTableColumns, setLoadingTableColumns] = useState(false);
  // 편집 중인 컬럼 정보
  const [editingColumn, setEditingColumn] = useState<{
    componentIdx: number;
    columnIdx: number;
    currentColumn: string;
  } | null>(null);
  const [editPopoverOpen, setEditPopoverOpen] = useState(false);
  
  // 테이블 컬럼 로드
  const loadTableColumns = useCallback(async () => {
    if (!mainTable || tableColumns.length > 0) return;
    
    setLoadingTableColumns(true);
    try {
      const result = await tableManagementApi.getColumnList(mainTable);
      if (result.success && result.data?.columns) {
        setTableColumns(result.data.columns);
      }
    } catch (error) {
      console.error("테이블 컬럼 로드 실패:", error);
    } finally {
      setLoadingTableColumns(false);
    }
  }, [mainTable, tableColumns.length]);
  
  // 편집 모드 진입 시 컬럼 로드
  useEffect(() => {
    if (isEditMode) {
      loadTableColumns();
    }
  }, [isEditMode, loadTableColumns]);

  // 화면 컴포넌트에서 사용하는 컬럼 정보 추출
  const componentColumns = useMemo(() => {
    const result: Array<{
      componentKind: string;
      componentLabel?: string;
      columns: string[];
      joinColumns: string[];
    }> = [];

    layoutItems.forEach((item) => {
      if (item.usedColumns && item.usedColumns.length > 0) {
        result.push({
          componentKind: item.componentKind,
          componentLabel: item.label,
          columns: item.usedColumns,
          joinColumns: item.joinColumns || [],
        });
      }
    });

    return result;
  }, [layoutItems]);

  // 전체 컬럼 수 계산
  const totalColumns = useMemo(() => {
    const allColumns = new Set<string>();
    componentColumns.forEach((comp) => {
      comp.columns.forEach((col) => allColumns.add(col));
    });
    return allColumns.size;
  }, [componentColumns]);
  
  // 컬럼명 → 표시명 매핑 (테이블 컬럼에서 추출)
  const columnDisplayMap = useMemo(() => {
    const map: Record<string, string> = {};
    tableColumns.forEach((tc) => {
      map[tc.columnName] = tc.displayName || tc.columnName;
    });
    return map;
  }, [tableColumns]);

  // 컴포넌트 타입별 그룹핑 (기존 fieldMappings용)
  const groupedMappings = useMemo(() => {
    const grouped: Record<string, FieldMappingInfo[]> = {};

    fieldMappings.forEach((mapping) => {
      const type = mapping.componentType || "기타";
      if (!grouped[type]) {
        grouped[type] = [];
      }
      grouped[type].push(mapping);
    });

    return grouped;
  }, [fieldMappings]);

  const componentTypes = Object.keys(groupedMappings);

  if (loading) {
    return (
      <div className="flex h-64 items-center justify-center">
        <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
      </div>
    );
  }

  return (
    <div className="space-y-6">
      {/* 화면 컴포넌트별 컬럼 사용 현황 */}
      <div className="space-y-4">
        <div className="flex items-center justify-between">
          <div>
            <h3 className="text-sm font-semibold">화면 컴포넌트별 컬럼 사용 현황</h3>
            <p className="text-xs text-muted-foreground">
              {isEditMode 
                ? "컬럼을 클릭하여 매핑을 변경할 수 있습니다."
                : "각 컴포넌트에서 사용하는 테이블 컬럼을 확인합니다."}
            </p>
          </div>
          <div className="flex items-center gap-2">
            <Badge variant="outline" className="text-xs">
              총 {totalColumns}개 컬럼
            </Badge>
            <Button
              variant={isEditMode ? "default" : "outline"}
              size="sm"
              onClick={() => setIsEditMode(!isEditMode)}
              className="h-7 text-xs"
            >
              {isEditMode ? (
                <>
                  <Eye className="mr-1 h-3 w-3" />
                  보기 모드
                </>
              ) : (
                <>
                  <Pencil className="mr-1 h-3 w-3" />
                  편집 모드
                </>
              )}
            </Button>
          </div>
        </div>

        {componentColumns.length === 0 ? (
          <div className="rounded-lg border border-dashed p-8 text-center text-muted-foreground">
            <Columns3 className="mx-auto mb-2 h-8 w-8" />
            <p className="text-sm">화면 컴포넌트에서 사용하는 컬럼 정보가 없습니다.</p>
          </div>
        ) : (
          <div className="space-y-3">
            {componentColumns.map((comp, idx) => (
              <div
                key={idx}
                className="rounded-lg border bg-card overflow-hidden"
              >
                {/* 컴포넌트 헤더 */}
                <div className="flex items-center justify-between px-3 py-2 bg-muted border-b">
                  <div className="flex items-center gap-2">
                    <Table2 className="h-4 w-4 text-primary" />
                    <span className="text-sm font-medium">
                      {comp.componentLabel || comp.componentKind}
                    </span>
                    <Badge variant="outline" className="text-[10px]">
                      {comp.componentKind}
                    </Badge>
                  </div>
                  <Badge variant="outline" className="text-xs">
                    {comp.columns.length}개 필드
                  </Badge>
                </div>
                
                {/* 필드 → 컬럼 매핑 테이블 */}
                <div className="divide-y">
                  {/* 테이블 헤더 */}
                  <div className="grid grid-cols-[1fr_28px_1fr] gap-1 px-3 py-1.5 bg-muted text-[10px] font-medium text-muted-foreground uppercase">
                    <span>필드명 (화면 표시)</span>
                    <span></span>
                    <span>컬럼명 (데이터베이스)</span>
                  </div>
                  
                  {/* 매핑 행들 */}
                  {comp.columns.map((col, cIdx) => {
                    const isJoinColumn = comp.joinColumns.includes(col);
                    const displayName = columnDisplayMap[col] || col;
                    const isEditing = editingColumn?.componentIdx === idx && editingColumn?.columnIdx === cIdx;
                    
                    return (
                      <div
                        key={cIdx}
                        className={cn(
                          "grid grid-cols-[1fr_28px_1fr] gap-1 px-3 py-1.5 items-center text-xs",
                          isJoinColumn && "bg-amber-50"
                        )}
                      >
                        {/* 필드명 (화면 표시) */}
                        <div className="flex items-center gap-1.5 min-w-0">
                          <span className="font-medium text-foreground truncate">
                            {displayName}
                          </span>
                          {isJoinColumn && (
                            <Badge variant="outline" className="text-[9px] bg-amber-100 text-orange-700 px-1 py-0 flex-shrink-0">
                              조인
                            </Badge>
                          )}
                        </div>
                        
                        {/* 화살표 */}
                        <div className="flex justify-center">
                          <ArrowRight className="h-3 w-3 text-muted-foreground/70" />
                        </div>
                        
                        {/* 컬럼명 (데이터베이스) */}
                        {isEditMode ? (
                          <Popover
                            open={isEditing && editPopoverOpen}
                            onOpenChange={(open) => {
                              if (open) {
                                setEditingColumn({ componentIdx: idx, columnIdx: cIdx, currentColumn: col });
                              } else {
                                setEditingColumn(null);
                              }
                              setEditPopoverOpen(open);
                            }}
                          >
                            <PopoverTrigger asChild>
                              <button
                                className={cn(
                                  "flex items-center gap-1 px-2 py-0.5 rounded text-left min-w-0",
                                  "hover:bg-primary/10 border border-transparent hover:border-primary/40",
                                  "transition-colors cursor-pointer group"
                                )}
                              >
                                <code className="text-primary font-mono text-[11px] truncate">{col}</code>
                                <Pencil className="h-3 w-3 text-muted-foreground/70 group-hover:text-primary flex-shrink-0" />
                              </button>
                            </PopoverTrigger>
                            <PopoverContent className="w-64 p-0" align="start">
                              <Command>
                                <CommandInput 
                                  placeholder="컬럼 검색..." 
                                  className="text-xs"
                                />
                                <CommandList>
                                  <CommandEmpty className="text-xs py-2 text-center">
                                    컬럼을 찾을 수 없습니다.
                                  </CommandEmpty>
                                  <CommandGroup heading="테이블 컬럼">
                                    {loadingTableColumns ? (
                                      <div className="flex items-center justify-center py-4">
                                        <Loader2 className="h-4 w-4 animate-spin" />
                                      </div>
                                    ) : (
                                      tableColumns.map((tableCol) => (
                                        <CommandItem
                                          key={tableCol.columnName}
                                          value={tableCol.columnName}
                                          onSelect={(value) => {
                                            toast.info(`컬럼 변경: ${col} → ${value}`, {
                                              description: "저장 기능은 아직 구현 중입니다."
                                            });
                                            setEditPopoverOpen(false);
                                            setEditingColumn(null);
                                          }}
                                          className="text-xs"
                                        >
                                          <div className="flex flex-col">
                                            <span className={cn(
                                              "font-medium",
                                              tableCol.columnName === col && "text-primary"
                                            )}>
                                              {tableCol.displayName || tableCol.columnName}
                                            </span>
                                            {tableCol.displayName && tableCol.displayName !== tableCol.columnName && (
                                              <span className="text-[10px] text-muted-foreground font-mono">
                                                {tableCol.columnName}
                                              </span>
                                            )}
                                          </div>
                                          {tableCol.columnName === col && (
                                            <Check className="ml-auto h-3 w-3 text-primary" />
                                          )}
                                        </CommandItem>
                                      ))
                                    )}
                                  </CommandGroup>
                                </CommandList>
                              </Command>
                            </PopoverContent>
                          </Popover>
                        ) : (
                          <code className="text-primary font-mono text-[11px] truncate">{col}</code>
                        )}
                      </div>
                    );
                  })}
                </div>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* 서브 테이블 연결 관계 (기존 fieldMappings) */}
      {fieldMappings.length > 0 && (
        <div className="space-y-4">
          <div className="flex items-center justify-between">
            <div>
              <h3 className="text-sm font-semibold">서브 테이블 연결 관계</h3>
              <p className="text-xs text-muted-foreground">
                메인 테이블과 서브 테이블 간의 필드 연결 관계입니다.
              </p>
            </div>
            <Badge variant="outline" className="text-xs">
              총 {fieldMappings.length}개 연결
            </Badge>
          </div>

          <div className="rounded-lg border">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-[50px] text-xs">#</TableHead>
                  <TableHead className="text-xs">메인 테이블 컬럼</TableHead>
                  <TableHead className="w-[60px] text-center text-xs"></TableHead>
                  <TableHead className="text-xs">서브 테이블</TableHead>
                  <TableHead className="text-xs">서브 테이블 컬럼</TableHead>
                  <TableHead className="text-xs">연결 타입</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {fieldMappings.map((mapping, idx) => (
                  <TableRow key={idx}>
                    <TableCell className="text-xs text-muted-foreground">
                      {idx + 1}
                    </TableCell>
                    <TableCell className="text-xs font-medium">
                      <Badge variant="outline" className="bg-primary/10 text-primary">
                        {mainTable}.{mapping.targetField}
                      </Badge>
                    </TableCell>
                    <TableCell className="text-center">
                      <ArrowRight className="mx-auto h-3 w-3 text-muted-foreground/70" />
                    </TableCell>
                    <TableCell className="text-xs">
                      <Badge variant="outline" className="bg-purple-50 text-purple-700">
                        {mapping.sourceTable || "-"}
                      </Badge>
                    </TableCell>
                    <TableCell className="text-xs">
                      <Badge variant="outline" className="bg-emerald-50 text-emerald-700">
                        {mapping.sourceField}
                      </Badge>
                    </TableCell>
                    <TableCell className="text-xs text-muted-foreground">
                      {mapping.componentType || "-"}
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>

          {/* 컴포넌트 타입별 요약 */}
          {componentTypes.length > 0 && (
            <div className="space-y-2">
              <h4 className="text-xs font-medium text-muted-foreground">연결 타입별 분류</h4>
              <div className="flex flex-wrap gap-2">
                {componentTypes.map((type) => (
                  <Badge
                    key={type}
                    variant="outline"
                    className="gap-1 bg-muted"
                  >
                    {type}
                    <span className="rounded-full bg-muted/80 px-1.5 text-[10px]">
                      {groupedMappings[type].length}
                    </span>
                  </Badge>
                ))}
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ============================================================
// 탭 3: 데이터 흐름
// ============================================================

interface DataFlowTabProps {
  screenId: number;
  groupId?: number;
  dataFlows: DataFlow[];
  loading: boolean;
  onReload: () => void;
  onSaveSuccess?: () => void;
}

function DataFlowTab({
  screenId,
  groupId,
  dataFlows,
  loading,
  onReload,
  onSaveSuccess,
}: DataFlowTabProps) {
  const [isEditing, setIsEditing] = useState(false);
  const [editItem, setEditItem] = useState<DataFlow | null>(null);
  const [formData, setFormData] = useState({
    target_screen_id: "",
    action_type: "navigate",
    data_mapping: "",
    flow_type: "forward",
    description: "",
    is_active: "Y",
  });

  // 폼 초기화
  const resetForm = () => {
    setFormData({
      target_screen_id: "",
      action_type: "navigate",
      data_mapping: "",
      flow_type: "forward",
      description: "",
      is_active: "Y",
    });
    setEditItem(null);
    setIsEditing(false);
  };

  // 수정 모드
  const handleEdit = (item: DataFlow) => {
    setEditItem(item);
    setFormData({
      target_screen_id: String(item.target_screen_id),
      action_type: item.action_type,
      data_mapping: item.data_mapping || "",
      flow_type: item.flow_type,
      description: item.description || "",
      is_active: item.is_active,
    });
    setIsEditing(true);
  };

  // 저장
  const handleSave = async () => {
    if (!formData.target_screen_id) {
      toast.error("대상 화면을 선택해주세요.");
      return;
    }

    try {
      const payload = {
        source_screen_id: screenId,
        target_screen_id: parseInt(formData.target_screen_id),
        action_type: formData.action_type,
        data_mapping: formData.data_mapping || null,
        flow_type: formData.flow_type,
        description: formData.description || null,
        is_active: formData.is_active,
      };

      let response;
      if (editItem) {
        response = await updateDataFlow(editItem.id, payload);
      } else {
        response = await createDataFlow(payload);
      }

      if (response.success) {
        toast.success(editItem ? "데이터 흐름이 수정되었습니다." : "데이터 흐름이 추가되었습니다.");
        resetForm();
        onReload();
        onSaveSuccess?.();
      } else {
        toast.error(response.message || "저장에 실패했습니다.");
      }
    } catch (error) {
      console.error("저장 오류:", error);
      toast.error("저장 중 오류가 발생했습니다.");
    }
  };

  // 삭제
  const handleDelete = async (id: number) => {
    if (!confirm("정말로 삭제하시겠습니까?")) return;

    try {
      const response = await deleteDataFlow(id);
      if (response.success) {
        toast.success("데이터 흐름이 삭제되었습니다.");
        onReload();
        onSaveSuccess?.();
      } else {
        toast.error(response.message || "삭제에 실패했습니다.");
      }
    } catch (error) {
      console.error("삭제 오류:", error);
      toast.error("삭제 중 오류가 발생했습니다.");
    }
  };

  if (loading) {
    return (
      <div className="flex h-64 items-center justify-center">
        <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
      </div>
    );
  }

  return (
    <div className="space-y-4">
      {/* 입력 폼 */}
      <div className="space-y-3 rounded-lg bg-muted/50 p-4">
        <div className="text-sm font-medium">
          {isEditing ? "데이터 흐름 수정" : "새 데이터 흐름 추가"}
        </div>

        <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
          <div>
            <Label className="text-xs">대상 화면 ID *</Label>
            <Input
              type="number"
              value={formData.target_screen_id}
              onChange={(e) =>
                setFormData({ ...formData, target_screen_id: e.target.value })
              }
              placeholder="화면 ID"
              className="h-8 text-xs"
            />
          </div>
          <div>
            <Label className="text-xs">액션 타입</Label>
            <SearchableSelect
              value={formData.action_type}
              onValueChange={(v) => setFormData({ ...formData, action_type: v })}
              options={[
                { value: "navigate", label: "화면 이동" },
                { value: "modal", label: "모달 열기" },
                { value: "callback", label: "콜백" },
                { value: "refresh", label: "새로고침" },
              ]}
              placeholder="액션 선택"
            />
          </div>
          <div>
            <Label className="text-xs">흐름 타입</Label>
            <SearchableSelect
              value={formData.flow_type}
              onValueChange={(v) => setFormData({ ...formData, flow_type: v })}
              options={[
                { value: "forward", label: "전달 (Forward)" },
                { value: "return", label: "반환 (Return)" },
                { value: "broadcast", label: "브로드캐스트" },
              ]}
              placeholder="흐름 선택"
            />
          </div>
        </div>

        <div>
          <Label className="text-xs">설명</Label>
          <Textarea
            value={formData.description}
            onChange={(e) =>
              setFormData({ ...formData, description: e.target.value })
            }
            placeholder="데이터 흐름에 대한 설명"
            className="h-16 resize-none text-xs"
          />
        </div>

        <div className="flex justify-end gap-2">
          {isEditing && (
            <Button variant="outline" size="sm" onClick={resetForm}>
              취소
            </Button>
          )}
          <Button size="sm" onClick={handleSave} className="gap-1">
            <Save className="h-4 w-4" />
            {isEditing ? "수정" : "추가"}
          </Button>
        </div>
      </div>

      {/* 목록 */}
      <div className="rounded-lg border">
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead className="text-xs">대상 화면</TableHead>
              <TableHead className="text-xs">액션</TableHead>
              <TableHead className="text-xs">흐름 타입</TableHead>
              <TableHead className="text-xs">설명</TableHead>
              <TableHead className="w-[100px] text-xs">작업</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {dataFlows.length === 0 ? (
              <TableRow>
                <TableCell
                  colSpan={5}
                  className="py-8 text-center text-sm text-muted-foreground"
                >
                  등록된 데이터 흐름이 없습니다.
                </TableCell>
              </TableRow>
            ) : (
              dataFlows.map((flow) => (
                <TableRow key={flow.id}>
                  <TableCell className="text-xs font-medium">
                    화면 {flow.target_screen_id}
                  </TableCell>
                  <TableCell className="text-xs">
                    <Badge variant="outline" className="text-xs">
                      {flow.action_type}
                    </Badge>
                  </TableCell>
                  <TableCell className="text-xs">
                    <Badge
                      variant="outline"
                      className={cn(
                        "text-xs",
                        flow.flow_type === "forward" && "bg-primary/10 text-primary",
                        flow.flow_type === "return" && "bg-emerald-50 text-emerald-700",
                        flow.flow_type === "broadcast" && "bg-purple-50 text-purple-700"
                      )}
                    >
                      {flow.flow_type}
                    </Badge>
                  </TableCell>
                  <TableCell className="text-xs text-muted-foreground">
                    {flow.description || "-"}
                  </TableCell>
                  <TableCell>
                    <div className="flex gap-1">
                      <Button
                        variant="ghost"
                        size="icon"
                        className="h-7 w-7"
                        onClick={() => handleEdit(flow)}
                      >
                        <Pencil className="h-3 w-3" />
                      </Button>
                      <Button
                        variant="ghost"
                        size="icon"
                        className="h-7 w-7 text-destructive"
                        onClick={() => handleDelete(flow.id)}
                      >
                        <Trash2 className="h-3 w-3" />
                      </Button>
                    </div>
                  </TableCell>
                </TableRow>
              ))
            )}
          </TableBody>
        </Table>
      </div>
    </div>
  );
}

// ============================================================
// 탭: 제어 관리
// ============================================================

interface ButtonControlInfo {
  id: string;
  label: string;
  actionType: string;
  targetTable?: string;
  operations?: string[];
  confirmMessage?: string;
  confirmationEnabled?: boolean;
  // 버튼 스타일
  backgroundColor?: string;
  textColor?: string;
  borderRadius?: string;
  // 모달/네비게이션 관련
  modalScreenId?: number;
  navigateScreenId?: number;
  // 데이터 흐름 제어
  hasDataflowControl?: boolean;
  dataflowControlMode?: string;
  flowTiming?: "before" | "after";
  linkedExternalCall?: {
    id: number;
    name: string;
  };
  // 다중 플로우 지원
  linkedFlows?: {
    id: number;
    name: string;
    timing?: "before" | "after";
  }[];
  // 레거시 호환 (단일 플로우)
  linkedFlow?: {
    id: number;
    name: string;
  };
}

interface ControlManagementTabProps {
  screenId: number;
  groupId?: number;
  layoutItems: LayoutItem[];
  loading: boolean;
  onRefresh: () => void;
}

function ControlManagementTab({
  screenId,
  groupId,
  layoutItems,
  loading: parentLoading,
  onRefresh,
}: ControlManagementTabProps) {
  const [buttonControls, setButtonControls] = useState<ButtonControlInfo[]>([]);
  const [flows, setFlows] = useState<NodeFlow[]>([]);
  const [loading, setLoading] = useState(false);
  const [expandedButton, setExpandedButton] = useState<string | null>(null);
  const [editingButton, setEditingButton] = useState<string | null>(null);
  const [editedValues, setEditedValues] = useState<Record<string, any>>({});

  // 화면 목록 조회 (inGroup: 같은 그룹 내 화면인지)
  const [screenList, setScreenList] = useState<{ id: number; name: string; inGroup?: boolean }[]>([]);
  // 화면 검색 팝오버 상태
  const [openModalScreenSearch, setOpenModalScreenSearch] = useState<string | null>(null);
  const [openNavigateScreenSearch, setOpenNavigateScreenSearch] = useState<string | null>(null);
  const [openFlowSearch, setOpenFlowSearch] = useState<string | null>(null);
  
  // 플로우 에디터 모달 상태 (전체 화면 임베드)
  const [showFlowEditorModal, setShowFlowEditorModal] = useState(false);
  const [flowEditorTargetButtonId, setFlowEditorTargetButtonId] = useState<string | null>(null);
  
  // 플로우 빠른 생성 다이얼로그 상태 (골격 생성용 - 레거시)
  const [showQuickFlowDialog, setShowQuickFlowDialog] = useState(false);
  const [quickFlowData, setQuickFlowData] = useState({
    name: "",
    description: "",
    tableName: "",
    tableLabel: "",
    actionType: "update" as "insert" | "update" | "delete",
    autoLink: true,
    targetButtonId: null as string | null,
  });
  const [isCreatingFlow, setIsCreatingFlow] = useState(false);
  
  // 대기 중인 버튼 ID (새 창에서 플로우 생성 후 연동할 버튼)
  const [pendingLinkButtonId, setPendingLinkButtonId] = useState<string | null>(null);

  // postMessage 이벤트 리스너 (새 창에서 플로우 저장 완료 시)
  useEffect(() => {
    const handleMessage = async (event: MessageEvent) => {
      if (event.data?.type === "FLOW_SAVED") {
        const { flowId, flowName } = event.data;
        
        // 플로우 목록 새로고침
        const flowList = await getNodeFlows();
        setFlows(flowList);
        
        // 대기 중인 버튼에 연동
        if (pendingLinkButtonId) {
          const newFlow = {
            id: flowId,
            name: flowName,
            timing: "after" as const,
          };
          
          setEditedValues(prev => ({
            ...prev,
            [pendingLinkButtonId]: {
              ...prev[pendingLinkButtonId],
              linkedFlows: [
                ...(prev[pendingLinkButtonId]?.linkedFlows || 
                    buttonControls.find(b => b.id === pendingLinkButtonId)?.linkedFlows || []),
                newFlow,
              ],
            },
          }));
          
          toast.success(`플로우 "${flowName}"이(가) 버튼에 연동되었습니다`);
          setPendingLinkButtonId(null);
        } else {
          toast.success(`플로우 "${flowName}"이(가) 생성되었습니다`);
        }
      }
    };
    
    window.addEventListener("message", handleMessage);
    return () => window.removeEventListener("message", handleMessage);
  }, [pendingLinkButtonId, buttonControls]);
  
  // 제어 관리 페이지를 새 창으로 열기
  const openFlowEditorInNewWindow = (buttonId?: string) => {
    if (buttonId) {
      setPendingLinkButtonId(buttonId);
    }
    window.open("/admin/systemMng/dataflow", "_blank", "width=1400,height=900");
  };

  // 데이터 로드
  const loadData = useCallback(async () => {
    setLoading(true);
    try {
      // 1. 화면 레이아웃에서 버튼 정보 추출
      const layoutResponse = await screenApi.getLayout(screenId);
      
      if (layoutResponse?.components) {
        const buttons: ButtonControlInfo[] = [];
        
        // 컴포넌트에서 버튼 추출 (화면 디자이너 구조 기준)
        const extractButtons = (components: any[], depth = 0) => {
          for (const comp of components) {
            const config = comp.componentConfig || {};
            
            // 버튼 컴포넌트 필터링 (화면 디자이너 저장 구조 기준)
            // 1. 새 시스템: type="component" && widgetType="button"
            // 2. 새 시스템: componentConfig.webType="button"
            // 3. 레거시: type="button"
            const isButton = 
              comp.widgetType === "button" ||
              comp.webType === "button" ||
              comp.type === "button" ||
              config.webType === "button" ||
              comp.componentType?.includes("button") ||
              comp.componentKind?.includes("button");
            
            if (isButton) {
              const webTypeConfig = comp.webTypeConfig || {};
              const action = config.action || {};
              const style = comp.style || {};
              
              buttons.push({
                id: comp.id || comp.componentId || `btn-${buttons.length}`,
                label: config.text || comp.label || comp.title || comp.name || "버튼",
                actionType: typeof action === "string" ? action : (action.type || "custom"),
                targetTable: config.tableName || webTypeConfig.tableName || comp.tableName,
                operations: action.operations || [],
                confirmMessage: action.confirmationMessage || action.confirmMessage || config.confirmMessage,
                confirmationEnabled: action.confirmationEnabled ?? (!!action.confirmationMessage || !!action.confirmMessage),
                // 버튼 스타일 (webTypeConfig 우선)
                backgroundColor: webTypeConfig.backgroundColor || config.backgroundColor || style.backgroundColor,
                textColor: webTypeConfig.textColor || config.textColor || style.color || style.labelColor,
                borderRadius: webTypeConfig.borderRadius || config.borderRadius || style.borderRadius,
                // 모달/네비게이션 관련 (화면 디자이너는 targetScreenId 사용)
                modalScreenId: action.targetScreenId || action.modalScreenId,
                navigateScreenId: action.navigateScreenId || action.targetScreenId,
                // 데이터 흐름 제어
                hasDataflowControl: webTypeConfig.enableDataflowControl,
                dataflowControlMode: webTypeConfig.dataflowConfig?.controlMode,
                flowTiming: webTypeConfig.dataflowConfig?.flowConfig?.executionTiming,
                linkedExternalCall: undefined, // TODO: 연결 정보 조회
                // 다중 플로우 지원 (flowConfigs 배열 또는 단일 flowConfig)
                linkedFlows: webTypeConfig.dataflowConfig?.flowConfigs?.map((fc: any) => ({
                  id: fc.flowId,
                  name: fc.flowName,
                  timing: fc.executionTiming || "after",
                })) || (webTypeConfig.dataflowConfig?.flowConfig ? [{
                  id: webTypeConfig.dataflowConfig.flowConfig.flowId,
                  name: webTypeConfig.dataflowConfig.flowConfig.flowName,
                  timing: webTypeConfig.dataflowConfig.flowConfig.executionTiming || "after",
                }] : []),
                // 레거시 호환 (단일 플로우)
                linkedFlow: webTypeConfig.dataflowConfig?.flowConfig ? {
                  id: webTypeConfig.dataflowConfig.flowConfig.flowId,
                  name: webTypeConfig.dataflowConfig.flowConfig.flowName,
                } : undefined,
              });
            }
            
            // 자식 컴포넌트 처리 (여러 필드 확인)
            if (comp.children && Array.isArray(comp.children)) {
              extractButtons(comp.children, depth + 1);
            }
            // componentConfig 내 중첩된 컴포넌트 확인
            if (comp.componentConfig?.children && Array.isArray(comp.componentConfig.children)) {
              extractButtons(comp.componentConfig.children, depth + 1);
            }
            // items 배열 확인 (일부 레이아웃에서 사용)
            if (comp.items && Array.isArray(comp.items)) {
              extractButtons(comp.items, depth + 1);
            }
          }
        };
        
        extractButtons(layoutResponse.components);
        setButtonControls(buttons);
      }

      // 2. 플로우 목록 조회 (버튼 연동용) - node_flows 테이블에서 가져옴
      try {
        const flowList = await getNodeFlows();
        console.log("플로우 목록 응답:", flowList);
        setFlows(flowList);
      } catch (flowError) {
        console.error("플로우 목록 조회 실패:", flowError);
      }

      // 3. 화면 목록 조회 (모달/네비게이션용)
      // 먼저 전체 화면 목록 가져오기 (기존 연결된 화면이 다른 그룹에 있을 수 있음)
      // 모든 화면 데이터를 가져오기 위해 최대 크기로 조회
      const allScreensResponse = await screenApi.getScreens({ size: 1000 });
      const allScreensMap = new Map<number, string>();
      if (allScreensResponse.data && allScreensResponse.data.length > 0) {
        allScreensResponse.data.forEach((s: any) => {
          // ScreenDefinition 타입: screenId, screenName 필드 사용
          const sid = Number(s.screenId || s.screen_id || s.id);
          const sname = s.screenName || s.screen_name || s.name || `화면 ${sid}`;
          if (!isNaN(sid)) {
            allScreensMap.set(sid, sname);
          }
        });
      }

      // 그룹 내 화면 목록
      let groupScreenIds: number[] = [];
      if (groupId) {
        const groupResponse = await getScreenGroup(groupId);
        if (groupResponse.success && groupResponse.data?.screens) {
          // API 응답 필드명: screen_id, screen_name (snake_case) - 문자열일 수 있으므로 Number()로 변환
          groupScreenIds = groupResponse.data.screens.map((s: any) => Number(s.screen_id || s.screenId || s.id)).filter(id => !isNaN(id));
        }
      }

      // 그룹 내 화면 우선, 전체 화면도 포함
      const screenListResult: { id: number; name: string; inGroup: boolean }[] = [];
      
      // 그룹 내 화면 먼저 추가 (숫자로 변환된 ID로 Map에서 조회)
      groupScreenIds.forEach(sid => {
        const name = allScreensMap.get(sid) || `화면 ${sid}`;
        screenListResult.push({ id: sid, name, inGroup: true });
        allScreensMap.delete(sid); // 중복 제거
      });

      // 나머지 전체 화면 추가 (다른 그룹에 있는 화면도 선택 가능하게)
      allScreensMap.forEach((name, id) => {
        screenListResult.push({ id, name, inGroup: false });
      });

      setScreenList(screenListResult);
    } catch (error) {
      console.error("제어 관리 데이터 로드 실패:", error);
      toast.error("데이터 로드 실패");
    } finally {
      setLoading(false);
    }
  }, [screenId, groupId]);

  useEffect(() => {
    loadData();
  }, [loadData]);

  // 플로우 빠른 생성 함수
  const handleQuickCreateFlow = async () => {
    if (!quickFlowData.name.trim()) {
      toast.error("플로우 이름을 입력해주세요");
      return;
    }
    if (!quickFlowData.tableName) {
      toast.error("테이블을 선택해주세요");
      return;
    }

    setIsCreatingFlow(true);
    try {
      // 제어 플로우 에디터(FlowEditor.tsx onDrop)와 동일한 형식으로 flowData 생성
      const timestamp = Date.now();
      const sourceNodeId = `tableSource_${timestamp}`;
      const actionNodeId = `${quickFlowData.actionType}Action_${timestamp}`;
      
      // 액션 타입별 노드 타입 결정
      let actionNodeType: string;
      
      switch (quickFlowData.actionType) {
        case "insert":
          actionNodeType = "insertAction";
          break;
        case "update":
          actionNodeType = "updateAction";
          break;
        case "delete":
          actionNodeType = "deleteAction";
          break;
        default:
          actionNodeType = "updateAction";
      }

      // 액션 노드 기본 데이터 (FlowEditor.tsx onDrop 패턴과 동일)
      const actionNodeData: any = {
        displayName: quickFlowData.actionType === "insert" ? "데이터 추가" 
          : quickFlowData.actionType === "update" ? "데이터 수정" 
          : "데이터 삭제",
        // 🔥 FlowEditor.tsx와 동일한 기본값
        targetType: "internal",
        targetTable: quickFlowData.tableName,
        targetTableLabel: quickFlowData.tableLabel || quickFlowData.tableName,
        fieldMappings: [],
        options: {},
      };

      // update/delete는 whereConditions 추가
      if (quickFlowData.actionType === "update" || quickFlowData.actionType === "delete") {
        actionNodeData.whereConditions = [];
      }

      // delete는 fieldMappings 제거 (삭제에는 필드 매핑 불필요)
      if (quickFlowData.actionType === "delete") {
        delete actionNodeData.fieldMappings;
      }

      const flowData = {
        nodes: [
          {
            id: sourceNodeId,
            type: "tableSource",
            position: { x: 100, y: 150 },
            data: {
              // 🔥 FlowEditor.tsx와 동일한 기본값 (TableSourceProperties에서 테이블 선택 시 설정됨)
              displayName: quickFlowData.tableLabel || quickFlowData.tableName || "테이블 소스",
              tableName: quickFlowData.tableName,
              fields: [],
              // dataSourceType은 TableSourceProperties에서 기본값 "context-data" 사용
            },
          },
          {
            id: actionNodeId,
            type: actionNodeType,
            position: { x: 450, y: 150 },
            data: actionNodeData,
          },
        ],
        edges: [
          {
            id: `edge_${timestamp}`,
            source: sourceNodeId,
            target: actionNodeId,
            sourceHandle: null,
            targetHandle: null,
          },
        ],
      };

      // 플로우 생성 API 호출
      const actionLabel = quickFlowData.actionType === "insert" ? "데이터 추가" 
        : quickFlowData.actionType === "update" ? "데이터 수정" 
        : "데이터 삭제";
      
      const result = await createNodeFlow({
        flowName: quickFlowData.name,
        flowDescription: quickFlowData.description || `${quickFlowData.tableLabel || quickFlowData.tableName} ${actionLabel} 플로우`,
        flowData: JSON.stringify(flowData),
      });

      toast.success(`플로우 "${quickFlowData.name}" 생성 완료`);

      // 자동 연동 옵션이 켜져 있고 대상 버튼이 있으면 연동
      if (quickFlowData.autoLink && quickFlowData.targetButtonId) {
        const newFlow = {
          id: result.flowId,
          name: quickFlowData.name,
          timing: "after" as const,
        };
        
        // 해당 버튼의 linkedFlows에 추가
        setEditedValues(prev => ({
          ...prev,
          [quickFlowData.targetButtonId!]: {
            ...prev[quickFlowData.targetButtonId!],
            linkedFlows: [
              ...(prev[quickFlowData.targetButtonId!]?.linkedFlows || 
                  buttonControls.find(b => b.id === quickFlowData.targetButtonId)?.linkedFlows || []),
              newFlow,
            ],
          },
        }));
        
        toast.success(`버튼에 플로우 자동 연동 완료`);
      }

      // 플로우 목록 새로고침
      const flowList = await getNodeFlows();
      setFlows(flowList);

      // 다이얼로그 닫기 및 상태 초기화
      setShowQuickFlowDialog(false);
      setQuickFlowData({
        name: "",
        description: "",
        tableName: "",
        tableLabel: "",
        actionType: "update",
        autoLink: true,
        targetButtonId: null,
      });
    } catch (error) {
      console.error("플로우 생성 실패:", error);
      toast.error("플로우 생성 실패");
    } finally {
      setIsCreatingFlow(false);
    }
  };

  // 버튼 설정 저장
  const handleSaveButton = async (buttonId: string) => {
    const values = editedValues[buttonId];
    if (!values) return;

    try {
      // 레이아웃에서 해당 버튼 찾아서 업데이트
      const layoutResponse = await screenApi.getLayout(screenId);
      if (!layoutResponse?.components) {
        toast.error("레이아웃을 불러올 수 없습니다");
        return;
      }

      // 버튼 컴포넌트 업데이트 (화면 디자이너 구조 기준)
      const updateButton = (components: any[]): boolean => {
        for (const comp of components) {
          const config = comp.componentConfig || {};
          
          // 버튼 식별 조건 (화면 디자이너 저장 구조 기준)
          const isButton = 
            comp.widgetType === "button" ||
            comp.webType === "button" ||
            comp.type === "button" ||
            config.webType === "button" ||
            comp.componentType?.includes("button") ||
            comp.componentKind?.includes("button");
          
          if ((comp.id === buttonId || comp.componentId === buttonId) && isButton) {
            // componentConfig 업데이트
            if (!comp.componentConfig) comp.componentConfig = {};
            if (!comp.componentConfig.action) comp.componentConfig.action = {};
            
            // 버튼 라벨(텍스트) 업데이트
            if (values.label !== undefined) {
              comp.componentConfig.text = values.label;
              // 레거시 호환: 여러 위치에 저장
              comp.label = values.label;
              comp.title = values.label;
            }
            
            // 버튼 스타일(색상) 업데이트 (webTypeConfig에 저장해야 실제 버튼에 반영됨)
            if (!comp.webTypeConfig) comp.webTypeConfig = {};
            if (!comp.style) comp.style = {};
            if (values.backgroundColor !== undefined) {
              comp.webTypeConfig.backgroundColor = values.backgroundColor;
              comp.componentConfig.backgroundColor = values.backgroundColor;
              comp.style.backgroundColor = values.backgroundColor;
            }
            if (values.textColor !== undefined) {
              comp.webTypeConfig.textColor = values.textColor;
              comp.componentConfig.textColor = values.textColor;
              comp.style.color = values.textColor;
              comp.style.labelColor = values.textColor;
            }
            if (values.borderRadius !== undefined) {
              comp.webTypeConfig.borderRadius = values.borderRadius;
              comp.componentConfig.borderRadius = values.borderRadius;
              comp.style.borderRadius = values.borderRadius;
            }
            
            // 액션 타입 업데이트
            if (values.actionType) {
              comp.componentConfig.action.type = values.actionType;
            }
            
            // 대상 테이블 업데이트
            if (values.targetTable !== undefined) {
              comp.componentConfig.tableName = values.targetTable;
            }
            
            // 확인 다이얼로그 설정 (save/delete 액션에서만 유효)
            const currentActionType = values.actionType || comp.componentConfig.action?.type;
            if (currentActionType === "save" || currentActionType === "delete") {
              if (values.confirmMessage !== undefined) {
                comp.componentConfig.action.confirmMessage = values.confirmMessage;
              }
            } else {
              // save/delete가 아닌 경우 confirmMessage 제거
              if (comp.componentConfig.action) {
                delete comp.componentConfig.action.confirmMessage;
              }
            }
            
            // 모달/네비게이션 화면 설정 (화면 디자이너는 targetScreenId 사용)
            if (values.modalScreenId !== undefined) {
              comp.componentConfig.action.targetScreenId = values.modalScreenId || null;
            }
            
            if (values.navigateScreenId !== undefined) {
              comp.componentConfig.action.targetScreenId = values.navigateScreenId || null;
            }
            
            if (values.operations) {
              comp.componentConfig.action.operations = values.operations;
            }
            
            // webTypeConfig 업데이트 (플로우 연동 - 다중 플로우 지원)
            if (!comp.webTypeConfig) comp.webTypeConfig = {};
            
            // 다중 플로우 처리 (linkedFlows 배열)
            if (values.linkedFlows !== undefined) {
              if (values.linkedFlows && values.linkedFlows.length > 0) {
                comp.webTypeConfig.enableDataflowControl = true;
                comp.webTypeConfig.dataflowConfig = {
                  controlMode: "flow",
                  // 다중 플로우 저장
                  flowConfigs: values.linkedFlows.map((lf: any) => ({
                    flowId: lf.id,
                    flowName: lf.name,
                    executionTiming: lf.timing || "after",
                  })),
                  // 레거시 호환 - 첫 번째 플로우를 단일 flowConfig로도 저장
                  flowConfig: {
                    flowId: values.linkedFlows[0].id,
                    flowName: values.linkedFlows[0].name,
                    executionTiming: values.linkedFlows[0].timing || "after",
                  },
                };
              } else {
                // 플로우 연동 해제 (빈 배열)
                comp.webTypeConfig.enableDataflowControl = false;
                delete comp.webTypeConfig.dataflowConfig;
              }
            }
            // 레거시 단일 플로우 처리
            else if (values.linkedFlowId) {
              comp.webTypeConfig.enableDataflowControl = true;
              comp.webTypeConfig.dataflowConfig = {
                controlMode: "flow",
                flowConfig: {
                  flowId: values.linkedFlowId,
                  flowName: flows.find(f => f.flowId === values.linkedFlowId)?.flowName || "",
                  executionTiming: values.flowTiming || "after",
                },
              };
            } else if (values.linkedFlowId === null) {
              // 플로우 연동 해제
              comp.webTypeConfig.enableDataflowControl = false;
              delete comp.webTypeConfig.dataflowConfig;
            }
            
            return true;
          }
          
          // 자식 컴포넌트 처리
          if (comp.children && Array.isArray(comp.children)) {
            if (updateButton(comp.children)) return true;
          }
          if (comp.componentConfig?.children && Array.isArray(comp.componentConfig.children)) {
            if (updateButton(comp.componentConfig.children)) return true;
          }
          if (comp.items && Array.isArray(comp.items)) {
            if (updateButton(comp.items)) return true;
          }
        }
        return false;
      };

      if (updateButton(layoutResponse.components)) {
        // 레이아웃 저장
        await screenApi.saveLayout(screenId, layoutResponse);
        toast.success("버튼 설정이 저장되었습니다");
        setEditingButton(null);
        setEditedValues(prev => {
          const next = { ...prev };
          delete next[buttonId];
          return next;
        });
        loadData();
        onRefresh();
      } else {
        toast.error("버튼을 찾을 수 없습니다");
      }
    } catch (error) {
      console.error("버튼 설정 저장 실패:", error);
      toast.error("저장 실패");
    }
  };

  // 액션 타입 라벨 (화면 디자이너와 동일)
  const getActionTypeLabel = (type: string) => {
    const labels: Record<string, string> = {
      save: "저장",
      delete: "삭제",
      edit: "편집",
      copy: "복사",
      navigate: "페이지 이동",
      modal: "모달 열기",
      openModalWithData: "데이터+모달",
      openRelatedModal: "연관모달",
      transferData: "데이터전달",
      quickInsert: "즉시저장",
      control: "제어흐름",
      view_table_history: "이력보기",
      excel_download: "엑셀다운",
      excel_upload: "엑셀업로드",
      barcode_scan: "바코드스캔",
      code_merge: "코드병합",
      operation_control: "운행제어",
    };
    return labels[type] || type;
  };

  // 액션 타입 색상 (화면 디자이너와 동일) - hover 상태 포함
  const getActionTypeColor = (type: string) => {
    switch (type) {
      case "save":
      case "quickInsert":
        return "bg-emerald-100 text-emerald-700 hover:bg-emerald-100 hover:text-emerald-700";
      case "delete":
        return "bg-destructive/10 text-destructive hover:bg-destructive/10 hover:text-destructive";
      case "edit":
      case "copy":
        return "bg-primary/10 text-primary hover:bg-primary/10 hover:text-primary";
      case "modal":
      case "openModalWithData":
      case "openRelatedModal":
        return "bg-purple-100 text-purple-700 hover:bg-purple-100 hover:text-purple-700";
      case "navigate":
        return "bg-cyan-100 text-cyan-700 hover:bg-cyan-100 hover:text-cyan-700";
      case "transferData":
      case "control":
        return "bg-amber-100 text-amber-700 hover:bg-amber-100 hover:text-amber-700";
      case "excel_download":
      case "excel_upload":
        return "bg-emerald-100 text-emerald-700 hover:bg-emerald-100 hover:text-emerald-700";
      case "view_table_history":
        return "bg-slate-100 text-slate-700 hover:bg-slate-100 hover:text-slate-700";
      default:
        return "bg-muted text-foreground hover:bg-muted hover:text-foreground";
    }
  };

  if (loading || parentLoading) {
    return (
      <div className="flex h-full items-center justify-center">
        <Loader2 className="h-6 w-6 animate-spin text-primary" />
      </div>
    );
  }

  return (
    <div className="space-y-6">
      {/* 버튼 액션 설정 - 구분된 섹션 */}
      <div className="rounded-lg border border-primary/20 bg-primary/10/30">
        <div className="flex items-center gap-2 px-3 py-2 border-b border-primary/20 bg-primary/10/50 rounded-t-lg">
          <MousePointer className="h-4 w-4 text-primary" />
          <span className="text-sm font-semibold text-primary">버튼 액션 설정</span>
          <Badge className="h-5 text-[10px] bg-primary text-white hover:bg-primary">
            {buttonControls.length}개
          </Badge>
        </div>
        
        <div className="max-h-[350px] overflow-y-auto p-2">
          {buttonControls.length === 0 ? (
            <div className="flex flex-col items-center justify-center py-6 text-center">
              <MousePointer className="mb-2 h-6 w-6 text-muted-foreground/50" />
              <p className="text-sm text-muted-foreground">버튼이 없습니다</p>
              <p className="text-xs text-muted-foreground">화면 디자이너에서 버튼을 추가하세요</p>
            </div>
          ) : (
            <div className="divide-y">
              {buttonControls.map((btn) => {
                // 현재 편집 중인 값 또는 기본값
                const currentLabel = editedValues[btn.id]?.label ?? btn.label;
                const currentBgColor = editedValues[btn.id]?.backgroundColor ?? btn.backgroundColor ?? "#3b82f6";
                const currentTextColor = editedValues[btn.id]?.textColor ?? btn.textColor ?? "#ffffff";
                const currentBorderRadius = editedValues[btn.id]?.borderRadius ?? btn.borderRadius ?? "4px";
                
                return (
                <div key={btn.id} className="py-3 px-1">
                  {/* 버튼 헤더: 프리뷰 + 이름 입력 + 저장 버튼 */}
                  <div className="flex items-center gap-3 mb-3">
                    {/* 버튼 프리뷰 */}
                    <div
                      className="flex items-center justify-center px-3 py-1.5 text-xs font-medium min-w-[60px] shrink-0"
                      style={{
                        backgroundColor: currentBgColor,
                        color: currentTextColor,
                        borderRadius: currentBorderRadius,
                      }}
                    >
                      {currentLabel || "버튼"}
                    </div>
                    
                    {/* 버튼 이름 입력 */}
                    <div className="flex-1">
                      <Input
                        value={currentLabel}
                        onChange={(e) => setEditedValues(prev => ({
                          ...prev,
                          [btn.id]: { ...prev[btn.id], label: e.target.value }
                        }))}
                        className="h-7 text-sm"
                        placeholder="버튼 이름"
                      />
                    </div>
                    
                    {btn.hasDataflowControl && (
                      <Badge variant="outline" className="h-5 text-[10px] border-purple-300 text-purple-600 shrink-0">
                        <Zap className="mr-1 h-2.5 w-2.5" />
                        제어
                      </Badge>
                    )}
                    <Button
                      size="sm"
                      className="h-7 text-xs px-3 shrink-0"
                      onClick={() => handleSaveButton(btn.id)}
                      disabled={!editedValues[btn.id]}
                    >
                      <Save className="mr-1 h-3 w-3" />
                      저장
                    </Button>
                  </div>

                  {/* 버튼 설정 (상시 편집) */}
                  <div className="space-y-2">
                    {/* 액션 타입 */}
                    <div className="grid grid-cols-[80px_1fr] items-center gap-2">
                      <Label className="text-xs text-muted-foreground">액션 타입</Label>
                      <Select
                        value={editedValues[btn.id]?.actionType || btn.actionType || "save"}
                        onValueChange={(val) => setEditedValues(prev => ({
                          ...prev,
                          [btn.id]: { ...prev[btn.id], actionType: val }
                        }))}
                      >
                        <SelectTrigger className="h-7 text-xs">
                          <SelectValue placeholder="액션 선택" />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="save" className="text-xs">저장</SelectItem>
                          <SelectItem value="delete" className="text-xs">삭제</SelectItem>
                          <SelectItem value="edit" className="text-xs">편집</SelectItem>
                          <SelectItem value="copy" className="text-xs">복사</SelectItem>
                          <SelectItem value="navigate" className="text-xs">페이지 이동</SelectItem>
                          <SelectItem value="modal" className="text-xs">모달 열기</SelectItem>
                          <SelectItem value="openModalWithData" className="text-xs">데이터 전달 + 모달</SelectItem>
                          <SelectItem value="openRelatedModal" className="text-xs">연관 데이터 모달</SelectItem>
                          <SelectItem value="transferData" className="text-xs">데이터 전달</SelectItem>
                          <SelectItem value="quickInsert" className="text-xs">즉시 저장</SelectItem>
                          <SelectItem value="control" className="text-xs">제어 흐름</SelectItem>
                          <SelectItem value="view_table_history" className="text-xs">테이블 이력</SelectItem>
                          <SelectItem value="excel_download" className="text-xs">엑셀 다운로드</SelectItem>
                          <SelectItem value="excel_upload" className="text-xs">엑셀 업로드</SelectItem>
                        </SelectContent>
                      </Select>
                    </div>
                    
                    {/* 버튼 스타일 (배경색 + 글자색) */}
                    <div className="grid grid-cols-[80px_1fr] items-center gap-2">
                      <Label className="text-xs text-muted-foreground">버튼 색상</Label>
                      <div className="flex items-center gap-2">
                        {/* 배경색 */}
                        <div className="flex items-center gap-1">
                          <span className="text-[10px] text-muted-foreground">배경</span>
                          <input
                            type="color"
                            value={currentBgColor}
                            onChange={(e) => setEditedValues(prev => ({
                              ...prev,
                              [btn.id]: { ...prev[btn.id], backgroundColor: e.target.value }
                            }))}
                            className="h-6 w-8 rounded border cursor-pointer"
                          />
                        </div>
                        {/* 글자색 */}
                        <div className="flex items-center gap-1">
                          <span className="text-[10px] text-muted-foreground">글자</span>
                          <input
                            type="color"
                            value={currentTextColor}
                            onChange={(e) => setEditedValues(prev => ({
                              ...prev,
                              [btn.id]: { ...prev[btn.id], textColor: e.target.value }
                            }))}
                            className="h-6 w-8 rounded border cursor-pointer"
                          />
                        </div>
                        {/* 프리셋 색상 */}
                        <div className="flex items-center gap-1 ml-2">
                          {[
                            { bg: "#3b82f6", text: "#ffffff", name: "파랑" },
                            { bg: "#22c55e", text: "#ffffff", name: "초록" },
                            { bg: "#ef4444", text: "#ffffff", name: "빨강" },
                            { bg: "#6b7280", text: "#ffffff", name: "회색" },
                            { bg: "#ffffff", text: "#374151", name: "흰색" },
                          ].map((preset) => (
                            <button
                              key={preset.name}
                              type="button"
                              onClick={() => setEditedValues(prev => ({
                                ...prev,
                                [btn.id]: { ...prev[btn.id], backgroundColor: preset.bg, textColor: preset.text }
                              }))}
                              className="h-5 w-5 rounded border border-input hover:ring-2 hover:ring-blue-300 transition-all"
                              style={{ backgroundColor: preset.bg }}
                              title={preset.name}
                            />
                          ))}
                        </div>
                      </div>
                    </div>

                    {/* 버튼 모서리 (borderRadius) */}
                    <div className="grid grid-cols-[80px_1fr] items-center gap-2">
                      <Label className="text-xs text-muted-foreground">모서리</Label>
                      <div className="flex items-center gap-2">
                        <Select
                          value={editedValues[btn.id]?.borderRadius ?? btn.borderRadius ?? "4px"}
                          onValueChange={(val) => setEditedValues(prev => ({
                            ...prev,
                            [btn.id]: { ...prev[btn.id], borderRadius: val }
                          }))}
                        >
                          <SelectTrigger className="h-7 w-[100px] text-xs">
                            <SelectValue placeholder="선택" />
                          </SelectTrigger>
                          <SelectContent>
                            <SelectItem value="0px" className="text-xs">없음 (0px)</SelectItem>
                            <SelectItem value="2px" className="text-xs">약간 (2px)</SelectItem>
                            <SelectItem value="4px" className="text-xs">기본 (4px)</SelectItem>
                            <SelectItem value="6px" className="text-xs">둥글게 (6px)</SelectItem>
                            <SelectItem value="8px" className="text-xs">더 둥글게 (8px)</SelectItem>
                            <SelectItem value="12px" className="text-xs">많이 (12px)</SelectItem>
                            <SelectItem value="9999px" className="text-xs">원형</SelectItem>
                          </SelectContent>
                        </Select>
                        <span className="text-[10px] text-muted-foreground">버튼 모서리 둥글기</span>
                      </div>
                    </div>

                    {/* 확인 메시지 설정 (save/delete 액션에서만 표시) */}
                    {((editedValues[btn.id]?.actionType || btn.actionType) === "save" ||
                      (editedValues[btn.id]?.actionType || btn.actionType) === "delete") && (
                      <div className="grid grid-cols-[80px_1fr] items-center gap-2">
                        <Label className="text-xs text-muted-foreground">확인 메시지</Label>
                        <Input
                          value={editedValues[btn.id]?.confirmMessage ?? btn.confirmMessage ?? ""}
                          onChange={(e) => setEditedValues(prev => ({
                            ...prev,
                            [btn.id]: { ...prev[btn.id], confirmMessage: e.target.value }
                          }))}
                          placeholder="커스텀 메시지 (예: 정말 삭제하시겠습니까?)"
                          className="h-7 text-xs"
                        />
                      </div>
                    )}

                    {/* 모달 화면 선택 (modal, openModalWithData, openRelatedModal 액션) */}
                    {((editedValues[btn.id]?.actionType || btn.actionType) === "modal" || 
                      (editedValues[btn.id]?.actionType || btn.actionType) === "openModalWithData" ||
                      (editedValues[btn.id]?.actionType || btn.actionType) === "openRelatedModal") && (
                      <div className="grid grid-cols-[80px_1fr] items-center gap-2">
                        <Label className="text-xs text-muted-foreground">모달 화면</Label>
                        <Popover open={openModalScreenSearch === btn.id} onOpenChange={(open) => setOpenModalScreenSearch(open ? btn.id : null)}>
                          <PopoverTrigger asChild>
                            <Button variant="outline" role="combobox" className="h-7 w-full justify-between text-xs">
                              {editedValues[btn.id]?.modalScreenId || btn.modalScreenId
                                ? screenList.find(s => s.id === Number(editedValues[btn.id]?.modalScreenId || btn.modalScreenId))?.name || "화면 선택"
                                : "화면 선택"
                              }
                              <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                            </Button>
                          </PopoverTrigger>
                          <PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
                            <Command>
                              <CommandInput placeholder="화면 검색..." className="text-xs" />
                              <CommandList>
                                <CommandEmpty className="text-xs py-2 text-center">화면을 찾을 수 없습니다</CommandEmpty>
                                <CommandItem 
                                  value="__none__"
                                  onSelect={() => {
                                    setEditedValues(prev => ({ ...prev, [btn.id]: { ...prev[btn.id], modalScreenId: null } }));
                                    setOpenModalScreenSearch(null);
                                  }}
                                  className="text-xs text-muted-foreground"
                                >
                                  <Check className={cn("mr-2 h-3 w-3", !(editedValues[btn.id]?.modalScreenId || btn.modalScreenId) ? "opacity-100" : "opacity-0")} />
                                  미설정
                                </CommandItem>
                                {screenList.filter(s => s && s.id != null && s.inGroup).length > 0 && (
                                  <CommandGroup heading="현재 그룹">
                                    {screenList.filter(s => s && s.id != null && s.inGroup).map((s) => (
                                      <CommandItem
                                        key={s.id}
                                        value={s.name}
                                        onSelect={() => {
                                          setEditedValues(prev => ({ ...prev, [btn.id]: { ...prev[btn.id], modalScreenId: s.id } }));
                                          setOpenModalScreenSearch(null);
                                        }}
                                        className="text-xs"
                                      >
                                        <Check className={cn("mr-2 h-3 w-3", Number(editedValues[btn.id]?.modalScreenId || btn.modalScreenId) === s.id ? "opacity-100" : "opacity-0")} />
                                        {s.name}
                                      </CommandItem>
                                    ))}
                                  </CommandGroup>
                                )}
                                {screenList.filter(s => s && s.id != null && !s.inGroup).length > 0 && (
                                  <CommandGroup heading="다른 그룹">
                                    {screenList.filter(s => s && s.id != null && !s.inGroup).map((s) => (
                                      <CommandItem
                                        key={s.id}
                                        value={s.name}
                                        onSelect={() => {
                                          setEditedValues(prev => ({ ...prev, [btn.id]: { ...prev[btn.id], modalScreenId: s.id } }));
                                          setOpenModalScreenSearch(null);
                                        }}
                                        className="text-xs text-muted-foreground"
                                      >
                                        <Check className={cn("mr-2 h-3 w-3", Number(editedValues[btn.id]?.modalScreenId || btn.modalScreenId) === s.id ? "opacity-100" : "opacity-0")} />
                                        {s.name}
                                      </CommandItem>
                                    ))}
                                  </CommandGroup>
                                )}
                              </CommandList>
                            </Command>
                          </PopoverContent>
                        </Popover>
                      </div>
                    )}

                    {/* 네비게이션 화면 선택 (navigate 액션) */}
                    {(editedValues[btn.id]?.actionType || btn.actionType) === "navigate" && (
                      <div className="grid grid-cols-[80px_1fr] items-center gap-2">
                        <Label className="text-xs text-muted-foreground">이동 화면</Label>
                        <Popover open={openNavigateScreenSearch === btn.id} onOpenChange={(open) => setOpenNavigateScreenSearch(open ? btn.id : null)}>
                          <PopoverTrigger asChild>
                            <Button variant="outline" role="combobox" className="h-7 w-full justify-between text-xs">
                              {editedValues[btn.id]?.navigateScreenId || btn.navigateScreenId
                                ? screenList.find(s => s.id === Number(editedValues[btn.id]?.navigateScreenId || btn.navigateScreenId))?.name || "화면 선택"
                                : "화면 선택"
                              }
                              <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                            </Button>
                          </PopoverTrigger>
                          <PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
                            <Command>
                              <CommandInput placeholder="화면 검색..." className="text-xs" />
                              <CommandList>
                                <CommandEmpty className="text-xs py-2 text-center">화면을 찾을 수 없습니다</CommandEmpty>
                                <CommandItem 
                                  value="__none__"
                                  onSelect={() => {
                                    setEditedValues(prev => ({ ...prev, [btn.id]: { ...prev[btn.id], navigateScreenId: null } }));
                                    setOpenNavigateScreenSearch(null);
                                  }}
                                  className="text-xs text-muted-foreground"
                                >
                                  <Check className={cn("mr-2 h-3 w-3", !(editedValues[btn.id]?.navigateScreenId || btn.navigateScreenId) ? "opacity-100" : "opacity-0")} />
                                  미설정
                                </CommandItem>
                                {screenList.filter(s => s && s.id != null && s.inGroup).length > 0 && (
                                  <CommandGroup heading="현재 그룹">
                                    {screenList.filter(s => s && s.id != null && s.inGroup).map((s) => (
                                      <CommandItem
                                        key={s.id}
                                        value={s.name}
                                        onSelect={() => {
                                          setEditedValues(prev => ({ ...prev, [btn.id]: { ...prev[btn.id], navigateScreenId: s.id } }));
                                          setOpenNavigateScreenSearch(null);
                                        }}
                                        className="text-xs"
                                      >
                                        <Check className={cn("mr-2 h-3 w-3", Number(editedValues[btn.id]?.navigateScreenId || btn.navigateScreenId) === s.id ? "opacity-100" : "opacity-0")} />
                                        {s.name}
                                      </CommandItem>
                                    ))}
                                  </CommandGroup>
                                )}
                                {screenList.filter(s => s && s.id != null && !s.inGroup).length > 0 && (
                                  <CommandGroup heading="다른 그룹">
                                    {screenList.filter(s => s && s.id != null && !s.inGroup).map((s) => (
                                      <CommandItem
                                        key={s.id}
                                        value={s.name}
                                        onSelect={() => {
                                          setEditedValues(prev => ({ ...prev, [btn.id]: { ...prev[btn.id], navigateScreenId: s.id } }));
                                          setOpenNavigateScreenSearch(null);
                                        }}
                                        className="text-xs text-muted-foreground"
                                      >
                                        <Check className={cn("mr-2 h-3 w-3", Number(editedValues[btn.id]?.navigateScreenId || btn.navigateScreenId) === s.id ? "opacity-100" : "opacity-0")} />
                                        {s.name}
                                      </CommandItem>
                                    ))}
                                  </CommandGroup>
                                )}
                              </CommandList>
                            </Command>
                          </PopoverContent>
                        </Popover>
                      </div>
                    )}

                    {/* 플로우 연동 - 세로 목록 형식 */}
                    <div className="grid grid-cols-[80px_1fr] items-start gap-2">
                      <Label className="text-xs text-muted-foreground pt-1">플로우</Label>
                      <div className="space-y-2">
                        {/* 연동된 플로우 목록 (세로 형식, 각각 타이밍 선택) */}
                        {(() => {
                          const currentFlows = editedValues[btn.id]?.linkedFlows || btn.linkedFlows || [];
                          return currentFlows.length > 0 ? (
                            <div className="space-y-1.5">
                              {currentFlows.map((lf: { id: number; name: string; timing?: string }, idx: number) => (
                                <div key={lf.id} className="flex items-center gap-2 p-1.5 border rounded-md bg-muted/30">
                                  <Workflow className="h-3 w-3 text-purple-500 shrink-0" />
                                  <span className="text-xs font-medium text-foreground flex-1 truncate">
                                    {lf.name}
                                  </span>
                                  {/* 타이밍 선택 */}
                                  <Select
                                    value={lf.timing || "after"}
                                    onValueChange={(val) => {
                                      const newFlows = [...currentFlows];
                                      newFlows[idx] = { ...lf, timing: val };
                                      setEditedValues(prev => ({ 
                                        ...prev, 
                                        [btn.id]: { ...prev[btn.id], linkedFlows: newFlows }
                                      }));
                                    }}
                                  >
                                    <SelectTrigger className="h-6 w-[70px] text-[10px]">
                                      <SelectValue />
                                    </SelectTrigger>
                                    <SelectContent>
                                      <SelectItem value="before" className="text-[10px]">실행 전</SelectItem>
                                      <SelectItem value="after" className="text-[10px]">실행 후</SelectItem>
                                    </SelectContent>
                                  </Select>
                                  {/* 삭제 버튼 */}
                                  <button
                                    type="button"
                                    className="h-5 w-5 rounded hover:bg-destructive/10 flex items-center justify-center text-muted-foreground/70 hover:text-destructive"
                                    onClick={() => {
                                      const newFlows = currentFlows.filter((f: any) => f.id !== lf.id);
                                      setEditedValues(prev => ({ 
                                        ...prev, 
                                        [btn.id]: { ...prev[btn.id], linkedFlows: newFlows }
                                      }));
                                    }}
                                  >
                                    <X className="h-3 w-3" />
                                  </button>
                                </div>
                              ))}
                            </div>
                          ) : null;
                        })()}
                        
                        {/* 플로우 추가 버튼 */}
                        <Popover open={openFlowSearch === btn.id} onOpenChange={(open) => setOpenFlowSearch(open ? btn.id : null)}>
                          <PopoverTrigger asChild>
                            <Button variant="outline" role="combobox" className="h-7 w-full justify-between text-xs">
                              <span className="flex items-center gap-1">
                                <Plus className="h-3 w-3" />
                                플로우 추가
                              </span>
                              <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                            </Button>
                          </PopoverTrigger>
                          <PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
                            <Command>
                              <CommandInput placeholder="플로우 검색..." className="text-xs" />
                              <CommandList>
                                <CommandEmpty className="text-xs py-2 text-center">플로우를 찾을 수 없습니다</CommandEmpty>
                                {/* 빠른 생성 옵션 */}
                                <CommandGroup>
                                  <CommandItem
                                    onSelect={() => {
                                      setOpenFlowSearch(null);
                                      // FlowEditor 모달 열기 (버튼 연동)
                                      setFlowEditorTargetButtonId(btn.id);
                                      setShowFlowEditorModal(true);
                                      setOpenFlowSearch(null);
                                    }}
                                    className="text-xs text-purple-700 bg-purple-50 hover:bg-purple-100"
                                  >
                                    <Plus className="mr-2 h-3 w-3 text-purple-500" />
                                    <div className="flex flex-col">
                                      <span className="font-medium">새 플로우 생성</span>
                                      <span className="text-[10px] text-purple-500">여기서 직접 만들고 자동 연동</span>
                                    </div>
                                  </CommandItem>
                                </CommandGroup>
                                {flows.length > 0 ? (
                                  <CommandGroup heading="플로우 목록">
                                    {flows.map((f) => {
                                      const currentFlows = editedValues[btn.id]?.linkedFlows || btn.linkedFlows || [];
                                      const isLinked = currentFlows.some((lf: any) => lf.id === f.flowId);
                                      const tableName = typeof f.flowData === 'object' 
                                        ? f.flowData?.nodes?.find((n: any) => n.type === 'tableSource')?.data?.tableName 
                                        : null;
                                      return (
                                        <CommandItem
                                          key={f.flowId}
                                          value={f.flowName}
                                          onSelect={() => {
                                            if (!isLinked) {
                                              const newFlows = [...currentFlows, { id: f.flowId, name: f.flowName, timing: "after" }];
                                              setEditedValues(prev => ({ 
                                                ...prev, 
                                                [btn.id]: { ...prev[btn.id], linkedFlows: newFlows }
                                              }));
                                            }
                                            setOpenFlowSearch(null);
                                          }}
                                          className={cn("text-xs", isLinked && "opacity-50")}
                                          disabled={isLinked}
                                        >
                                          <Check className={cn("mr-2 h-3 w-3", isLinked ? "opacity-100" : "opacity-0")} />
                                          <div className="flex flex-col">
                                            <span>{f.flowName}</span>
                                            {tableName && <span className="text-[10px] text-muted-foreground">{tableName}</span>}
                                          </div>
                                          {isLinked && <span className="ml-auto text-[10px] text-muted-foreground">연동됨</span>}
                                        </CommandItem>
                                      );
                                    })}
                                  </CommandGroup>
                                ) : (
                                  <div className="py-2 px-2 text-xs text-muted-foreground text-center">
                                    등록된 플로우가 없습니다
                                  </div>
                                )}
                              </CommandList>
                            </Command>
                          </PopoverContent>
                        </Popover>
                        
                      </div>
                    </div>
                  </div>
                </div>
              );
              })}
            </div>
          )}
        </div>
      </div>

      {/* 플로우 연동 - 구분된 섹션 */}
      <div className="rounded-lg border border-purple-200 bg-purple-50/30">
        <div className="flex items-center gap-2 px-3 py-2 border-b border-purple-200 bg-purple-100/50 rounded-t-lg">
          <Workflow className="h-4 w-4 text-purple-600" />
          <span className="text-sm font-semibold text-purple-900">플로우 연동 현황</span>
          <Badge className="h-5 text-[10px] bg-purple-600 text-white hover:bg-purple-600">
            {flows.length}개 플로우
          </Badge>
          <Badge className="h-5 text-[10px] bg-emerald-600 text-white hover:bg-emerald-600">
            {buttonControls.filter(b => (b.linkedFlows && b.linkedFlows.length > 0) || b.linkedFlow).length}개 연동
          </Badge>
          <span className="flex-1" />
          <Button
            variant="outline"
            size="sm"
            className="h-5 px-1.5 text-[10px] border-purple-300 text-purple-700 hover:text-purple-900 hover:bg-purple-100"
            onClick={() => {
              // FlowEditor 모달 열기 (버튼 연동 없이)
              setFlowEditorTargetButtonId(null);
              setShowFlowEditorModal(true);
            }}
            title="플로우 생성"
          >
            <Plus className="mr-1 h-3 w-3" />
            새 플로우
          </Button>
          <Button
            variant="ghost"
            size="sm"
            className="h-5 px-1.5 text-[10px] text-purple-700 hover:text-purple-900 hover:bg-purple-200"
            onClick={() => window.open("/admin/systemMng/dataflow", "_blank")}
            title="플로우 관리"
          >
            <ExternalLink className="mr-1 h-3 w-3" />
            상세 관리
          </Button>
        </div>
        
        <div className="max-h-[180px] overflow-y-auto p-2">
          {flows.length === 0 ? (
            <div className="flex flex-col items-center justify-center py-4 text-center">
              <Workflow className="mb-1 h-5 w-5 text-muted-foreground/50" />
              <p className="text-xs text-muted-foreground">사용 가능한 플로우가 없습니다</p>
            </div>
          ) : (
            <div className="space-y-1">
              {flows.map((flow) => {
                // 이 플로우가 연동된 버튼들 찾기 (다중 플로우 지원)
                const linkedButtons = buttonControls.filter(b => 
                  (b.linkedFlows && b.linkedFlows.some(lf => lf.id === flow.flowId)) ||
                  b.linkedFlow?.id === flow.flowId
                );
                const tableName = (flow as any).tableType || (flow as any).tableName;
                return (
                  <div key={`flow-list-${flow.flowId}`} className="flex items-center gap-2 px-2 py-1.5 rounded bg-card/50 hover:bg-card">
                    {/* 플로우 이름 - 일반 텍스트 */}
                    <Workflow className="h-3.5 w-3.5 text-purple-500 shrink-0" />
                    <span className="text-xs font-medium text-foreground shrink-0">
                      {flow.flowName}
                    </span>
                    {tableName && (
                      <span className="text-[10px] text-muted-foreground shrink-0">
                        ({tableName})
                      </span>
                    )}
                    <span className="flex-1" />
                    {linkedButtons.length > 0 ? (
                      <div className="flex items-center gap-1 shrink-0 flex-wrap justify-end">
                        {linkedButtons.map((btn, idx) => {
                          // 해당 버튼에서 이 플로우의 타이밍 정보 추출
                          const flowInfo = btn.linkedFlows?.find(lf => lf.id === flow.flowId);
                          const timing = flowInfo?.timing || btn.flowTiming || "after";
                          return (
                            <div key={`${flow.flowId}-${btn.id}`} className="flex items-center gap-1">
                              {idx === 0 && <ArrowRight className="h-3 w-3 text-emerald-500" />}
                              <span className="text-xs text-emerald-600 font-medium">
                                [{btn.label}]
                              </span>
                              <Badge className={cn("h-4 text-[9px]", getActionTypeColor(btn.actionType))}>
                                {getActionTypeLabel(btn.actionType)}
                              </Badge>
                              <span className="text-[10px] text-muted-foreground">
                                ({timing === "before" ? "전" : "후"})
                              </span>
                            </div>
                          );
                        })}
                      </div>
                    ) : (
                      /* 미연동 - 보라색 뱃지 */
                      <Badge variant="outline" className="h-5 text-[10px] border-purple-300 bg-purple-100 text-purple-600 shrink-0">
                        미연동
                      </Badge>
                    )}
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>

      {/* 플로우 빠른 생성 다이얼로그 */}
      <Dialog open={showQuickFlowDialog} onOpenChange={setShowQuickFlowDialog}>
        <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle className="text-base sm:text-lg">플로우 빠른 생성</DialogTitle>
            <DialogDescription className="text-xs sm:text-sm">
              플로우의 <strong>기본 골격</strong>만 생성합니다.
            </DialogDescription>
          </DialogHeader>
          
          {/* 중요 안내 */}
          <div className="p-2 rounded-md bg-amber-50 border border-amber-200 text-xs text-amber-800">
            <div className="flex items-start gap-2">
              <span className="text-amber-500 mt-0.5">&#9888;</span>
              <div>
                <p className="font-medium">생성 후 제어 관리에서 추가 설정이 필요합니다</p>
                <p className="mt-1 text-amber-700">
                  필드 매핑, WHERE 조건 등을 설정해야 실제로 동작합니다.
                </p>
              </div>
            </div>
          </div>

          <div className="space-y-4">
            {/* 플로우 이름 */}
            <div>
              <Label className="text-xs sm:text-sm">플로우 이름 *</Label>
              <Input
                value={quickFlowData.name}
                onChange={(e) => setQuickFlowData(prev => ({ ...prev, name: e.target.value }))}
                placeholder="예: 고객정보 수정 플로우"
                className="h-8 text-xs sm:h-10 sm:text-sm mt-1"
              />
            </div>

            {/* 테이블 선택/입력 */}
            <div>
              <Label className="text-xs sm:text-sm">대상 테이블 *</Label>
              {(() => {
                const availableTables = Array.from(new Set(buttonControls.filter(b => b.targetTable).map(b => b.targetTable)));
                
                return availableTables.length > 0 ? (
                  <>
                    <Popover>
                      <PopoverTrigger asChild>
                        <Button
                          variant="outline"
                          role="combobox"
                          className="h-8 w-full justify-between text-xs sm:h-10 sm:text-sm mt-1"
                        >
                          {quickFlowData.tableName 
                            ? (quickFlowData.tableLabel || quickFlowData.tableName)
                            : "테이블 선택..."}
                          <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                        </Button>
                      </PopoverTrigger>
                      <PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
                        <Command>
                          <CommandInput placeholder="테이블 검색..." className="text-xs" />
                          <CommandList>
                            <CommandEmpty className="text-xs py-2 text-center">테이블을 찾을 수 없습니다</CommandEmpty>
                            <CommandGroup>
                              {availableTables.map((table) => (
                                <CommandItem
                                  key={table}
                                  value={table}
                                  onSelect={() => {
                                    setQuickFlowData(prev => ({ 
                                      ...prev, 
                                      tableName: table || "",
                                      tableLabel: table || "",
                                    }));
                                  }}
                                  className="text-xs"
                                >
                                  <Check className={cn("mr-2 h-3 w-3", quickFlowData.tableName === table ? "opacity-100" : "opacity-0")} />
                                  <Database className="mr-2 h-3 w-3 text-primary" />
                                  {table}
                                </CommandItem>
                              ))}
                            </CommandGroup>
                          </CommandList>
                        </Command>
                      </PopoverContent>
                    </Popover>
                    <p className="text-[10px] text-muted-foreground mt-1">화면에서 사용 중인 테이블 목록입니다</p>
                  </>
                ) : (
                  <>
                    <Input
                      value={quickFlowData.tableName}
                      onChange={(e) => setQuickFlowData(prev => ({ 
                        ...prev, 
                        tableName: e.target.value,
                        tableLabel: e.target.value,
                      }))}
                      placeholder="테이블명 입력 (예: customer_mng)"
                      className="h-8 text-xs sm:h-10 sm:text-sm mt-1"
                    />
                    <p className="text-[10px] text-muted-foreground mt-1">테이블명을 직접 입력하세요</p>
                  </>
                );
              })()}
            </div>

            {/* 액션 타입 */}
            <div>
              <Label className="text-xs sm:text-sm">액션 타입</Label>
              <div className="flex gap-2 mt-2">
                {[
                  { value: "insert", label: "INSERT", color: "bg-emerald-100 text-emerald-700 border-green-300" },
                  { value: "update", label: "UPDATE", color: "bg-primary/10 text-primary border-primary/40" },
                  { value: "delete", label: "DELETE", color: "bg-destructive/10 text-destructive border-destructive/30" },
                ].map((action) => (
                  <button
                    key={action.value}
                    type="button"
                    onClick={() => setQuickFlowData(prev => ({ ...prev, actionType: action.value as any }))}
                    className={cn(
                      "flex-1 py-2 px-3 text-xs font-medium rounded-md border transition-all",
                      quickFlowData.actionType === action.value
                        ? action.color + " ring-2 ring-offset-1"
                        : "bg-muted text-muted-foreground border-border hover:bg-muted"
                    )}
                  >
                    {action.label}
                  </button>
                ))}
              </div>
            </div>

            {/* 설명 (선택) */}
            <div>
              <Label className="text-xs sm:text-sm">설명 (선택)</Label>
              <Textarea
                value={quickFlowData.description}
                onChange={(e) => setQuickFlowData(prev => ({ ...prev, description: e.target.value }))}
                placeholder="플로우에 대한 설명을 입력하세요"
                className="h-16 text-xs sm:text-sm mt-1 resize-none"
              />
            </div>

            {/* 자동 연동 옵션 */}
            {quickFlowData.targetButtonId && (
              <div className="flex items-center gap-2 p-2 rounded-md bg-purple-50 border border-purple-200">
                <input
                  type="checkbox"
                  id="autoLink"
                  checked={quickFlowData.autoLink}
                  onChange={(e) => setQuickFlowData(prev => ({ ...prev, autoLink: e.target.checked }))}
                  className="h-4 w-4 rounded border-input"
                />
                <label htmlFor="autoLink" className="text-xs text-purple-700">
                  생성 후 [{buttonControls.find(b => b.id === quickFlowData.targetButtonId)?.label}] 버튼에 자동 연동
                </label>
              </div>
            )}
          </div>

          {/* 버튼 영역 */}
          <div className="flex flex-col gap-2 pt-2 border-t">
            {/* 제어 관리에서 직접 생성 (권장) */}
            <Button
              variant="default"
              onClick={() => {
                if (quickFlowData.targetButtonId) {
                  setPendingLinkButtonId(quickFlowData.targetButtonId);
                }
                setShowQuickFlowDialog(false);
                openFlowEditorInNewWindow(quickFlowData.targetButtonId || undefined);
              }}
              className="h-10 w-full text-sm font-medium"
            >
              <ExternalLink className="mr-2 h-4 w-4" />
              제어 관리에서 직접 생성 (권장)
            </Button>
            <p className="text-[10px] text-center text-muted-foreground -mt-1">
              필드 매핑, WHERE 조건 등을 직접 설정할 수 있습니다. 저장 시 자동 연동됩니다.
            </p>
            
            {/* 구분선 */}
            <div className="flex items-center gap-2 my-1">
              <div className="flex-1 h-px bg-border" />
              <span className="text-[10px] text-muted-foreground">또는</span>
              <div className="flex-1 h-px bg-border" />
            </div>
            
            {/* 하단 버튼들 */}
            <div className="flex justify-end gap-2">
              <Button
                variant="outline"
                onClick={() => setShowQuickFlowDialog(false)}
                className="h-8 text-xs"
              >
                취소
              </Button>
              <Button
                variant="outline"
                onClick={handleQuickCreateFlow}
                disabled={isCreatingFlow || !quickFlowData.name.trim() || !quickFlowData.tableName}
                className="h-8 text-xs"
              >
                {isCreatingFlow ? (
                  <>
                    <Loader2 className="mr-1 h-3 w-3 animate-spin" />
                    생성 중...
                  </>
                ) : (
                  "골격만 생성"
                )}
              </Button>
            </div>
          </div>
        </DialogContent>
      </Dialog>

      {/* FlowEditor 전체 화면 모달 */}
      <Dialog open={showFlowEditorModal} onOpenChange={setShowFlowEditorModal}>
        <DialogContent className="max-w-[98vw] h-[95vh] p-0 overflow-hidden">
          <DialogTitle className="sr-only">플로우 편집기</DialogTitle>
          <div className="flex flex-col h-full">
            {/* 헤더 */}
            <div className="flex items-center justify-between px-4 py-3 border-b bg-background">
              <div>
                <h2 className="text-lg font-semibold">플로우 생성</h2>
                <p className="text-xs text-muted-foreground">
                  저장하면 자동으로 버튼에 연동됩니다
                  {flowEditorTargetButtonId && (
                    <span className="ml-1 text-purple-600">
                      (대상: {buttonControls.find(b => b.id === flowEditorTargetButtonId)?.label})
                    </span>
                  )}
                </p>
              </div>
              <Button
                variant="ghost"
                size="sm"
                onClick={() => setShowFlowEditorModal(false)}
              >
                <X className="h-4 w-4" />
              </Button>
            </div>
            
            {/* FlowEditor */}
            <div className="flex-1 overflow-hidden">
              <FlowEditor
                embedded={true}
                onSaveComplete={(flowId, flowName) => {
                  // 플로우 목록 새로고침
                  getNodeFlows().then(setFlows);
                  
                  // 대상 버튼에 연동
                  if (flowEditorTargetButtonId) {
                    const newFlow = {
                      id: flowId,
                      name: flowName,
                      timing: "after" as const,
                    };
                    
                    setEditedValues(prev => ({
                      ...prev,
                      [flowEditorTargetButtonId]: {
                        ...prev[flowEditorTargetButtonId],
                        linkedFlows: [
                          ...(prev[flowEditorTargetButtonId]?.linkedFlows || 
                              buttonControls.find(b => b.id === flowEditorTargetButtonId)?.linkedFlows || []),
                          newFlow,
                        ],
                      },
                    }));
                    
                    toast.success(`플로우 "${flowName}"이(가) 버튼에 연동되었습니다`);
                  } else {
                    toast.success(`플로우 "${flowName}"이(가) 생성되었습니다`);
                  }
                  
                  // 모달 닫기
                  setShowFlowEditorModal(false);
                  setFlowEditorTargetButtonId(null);
                }}
              />
            </div>
          </div>
        </DialogContent>
      </Dialog>

    </div>
  );
}

// ============================================================
// 탭 4: 화면 프리뷰 (iframe)
// ============================================================

interface PreviewTabProps {
  screenId: number;
  screenName: string;
  companyCode?: string;
  iframeKey?: number; // iframe 새로고침용 키
  canvasWidth?: number; // 화면 캔버스 너비
  canvasHeight?: number; // 화면 캔버스 높이
}

function PreviewTab({ screenId, screenName, companyCode, iframeKey = 0, canvasWidth, canvasHeight }: PreviewTabProps) {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  
  // 화면 디자인 크기 (실제 캔버스 크기 사용, 없으면 기본값)
  // 좌우/상하 여유 마진 추가: 모달 패딩, 헤더, 하단 체크박스 등
  // 좌우: +120px (양쪽 패딩 + 여유), 상하: +250px (헤더 + 버튼 + 체크박스 + 패딩)
  const designWidth = Math.max((canvasWidth || 400) + 120, 500);
  const designHeight = Math.max((canvasHeight || 400) + 250, 650);
  
  // 컨테이너에 맞는 초기 스케일 계산
  const [initialScale, setInitialScale] = useState(0.7);
  
  // 컨테이너 크기에 맞춰 초기 스케일 계산
  useEffect(() => {
    const updateInitialScale = () => {
      if (containerRef.current) {
        const containerWidth = containerRef.current.offsetWidth;
        const containerHeight = containerRef.current.offsetHeight;
        
        // 여백 5px씩만 적용하여 꽉 차게
        const scaleX = (containerWidth - 10) / designWidth;
        const scaleY = (containerHeight - 10) / designHeight;
        const newScale = Math.min(scaleX, scaleY);
        
        setInitialScale(newScale);
      }
    };
    
    // 초기 측정 (약간의 딜레이)
    const timer = setTimeout(updateInitialScale, 200);
    
    // 리사이즈 감지
    const resizeObserver = new ResizeObserver(updateInitialScale);
    if (containerRef.current) {
      resizeObserver.observe(containerRef.current);
    }
    
    return () => {
      clearTimeout(timer);
      resizeObserver.disconnect();
    };
  }, []);
  

  // 화면 URL 생성 (preview=true로 사이드바 없이 화면만 표시, company_code 전달)
  const previewUrl = useMemo(() => {
    // 현재 호스트 기반으로 URL 생성
    const params = new URLSearchParams({ preview: "true" });
    // 프리뷰용 회사 코드 추가 (데이터 조회에 필요)
    if (companyCode) {
      params.set("company_code", companyCode);
    }
    if (typeof window !== "undefined") {
      const baseUrl = window.location.origin;
      return `${baseUrl}/screens/${screenId}?${params.toString()}`;
    }
    return `/screens/${screenId}?${params.toString()}`;
  }, [screenId, companyCode]);

  const handleIframeLoad = () => {
    setLoading(false);
  };

  const handleIframeError = () => {
    setLoading(false);
    setError("화면을 불러오는데 실패했습니다.");
  };

  const openInNewTab = () => {
    window.open(previewUrl, "_blank");
  };

  return (
    <div className="flex min-h-0 flex-1 flex-col">
      {/* 상단 툴바 (최소화) */}
      <div className="flex h-7 shrink-0 items-center justify-between border-b px-2">
        <div className="flex items-center gap-1.5">
          <Eye className="h-3 w-3 text-primary" />
          <span className="truncate text-xs font-medium">{screenName}</span>
          <span className="text-[10px] text-muted-foreground">(휠: 확대/축소, 드래그: 이동)</span>
        </div>
        <div className="flex items-center gap-1">
          <Button
            variant="ghost"
            size="sm"
            onClick={() => {
              setLoading(true);
              const iframe = document.getElementById("screen-preview-iframe") as HTMLIFrameElement;
              if (iframe) {
                iframe.src = iframe.src;
              }
            }}
            className="h-5 w-5 p-0"
            title="새로고침"
          >
            <RefreshCw className={cn("h-3 w-3", loading && "animate-spin")} />
          </Button>
          <Button variant="ghost" size="sm" onClick={openInNewTab} className="h-5 w-5 p-0" title="새 탭에서 열기">
            <ExternalLink className="h-3 w-3" />
          </Button>
        </div>
      </div>

      {/* iframe 영역 - Ctrl+휠로 확대/축소, 내부 버튼/목록 클릭 가능 */}
      <div 
        ref={containerRef} 
        className="relative min-h-0 flex-1 overflow-hidden flex items-center justify-center bg-muted"
      >
        {loading && (
          <div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80">
            <div className="text-center">
              <Loader2 className="mx-auto h-8 w-8 animate-spin text-primary" />
              <p className="mt-2 text-sm text-muted-foreground">화면 로딩 중...</p>
            </div>
          </div>
        )}

        {error ? (
          <div className="flex h-full items-center justify-center">
            <div className="text-center">
              <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-destructive/10">
                <span className="text-2xl">⚠️</span>
              </div>
              <p className="text-sm text-destructive">{error}</p>
              <Button
                variant="outline"
                size="sm"
                className="mt-4"
                onClick={() => {
                  setError(null);
                  setLoading(true);
                }}
              >
                다시 시도
              </Button>
            </div>
          </div>
        ) : (
          <TransformWrapper
            initialScale={initialScale}
            minScale={0.2}
            maxScale={3}
            centerOnInit={true}
            wheel={{ step: 0.05 }}
            panning={{ velocityDisabled: true }}
          >
            {({ state }) => (
              <TransformComponent
                wrapperStyle={{ width: "100%", height: "100%" }}
                contentStyle={{ display: "flex", alignItems: "center", justifyContent: "center" }}
              >
                <div 
                  className="relative"
                  style={{
                    width: `${designWidth}px`,
                    height: `${designHeight}px`,
                  }}
                >
                  <iframe
                    key={iframeKey}
                    id="screen-preview-iframe"
                    src={previewUrl}
                    className="border-0 shadow-lg rounded bg-card pointer-events-none"
                    style={{
                      width: "100%",
                      height: "100%",
                    }}
                    onLoad={handleIframeLoad}
                    onError={handleIframeError}
                    title={`화면 프리뷰: ${screenName}`}
                    sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
                  />
                  {/* 클릭/드래그 분리 오버레이 */}
                  <div
                    className="absolute inset-0"
                    style={{ cursor: "grab" }}
                    onMouseDown={(e) => {
                      const overlay = e.currentTarget;
                      const iframe = overlay.previousElementSibling as HTMLIFrameElement;
                      const startX = e.clientX;
                      const startY = e.clientY;
                      let moved = false;

                      const handleMouseMove = (moveEvent: MouseEvent) => {
                        const dx = Math.abs(moveEvent.clientX - startX);
                        const dy = Math.abs(moveEvent.clientY - startY);
                        if (dx > 5 || dy > 5) {
                          moved = true;
                          overlay.style.cursor = "grabbing";
                        }
                      };

                      const handleMouseUp = (upEvent: MouseEvent) => {
                        document.removeEventListener("mousemove", handleMouseMove);
                        document.removeEventListener("mouseup", handleMouseUp);
                        overlay.style.cursor = "grab";

                        // 이동 없이 클릭만 했으면 iframe에 클릭 전달
                        if (!moved) {
                          const rect = iframe.getBoundingClientRect();
                          // 실제 표시된 크기와 원본 크기의 비율로 좌표 변환
                          const scaleX = designWidth / rect.width;
                          const scaleY = designHeight / rect.height;
                          const x = (upEvent.clientX - rect.left) * scaleX;
                          const y = (upEvent.clientY - rect.top) * scaleY;
                          
                          // iframe 내부로 클릭 이벤트 전달
                          try {
                            const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
                            if (iframeDoc) {
                              let elem = iframeDoc.elementFromPoint(x, y) as HTMLElement | null;
                              if (elem) {
                                // SVG 내부 요소(path, line 등)면 가장 가까운 버튼/앵커 찾기
                                const clickable = elem.closest("button, a, [role='button'], [onclick]") as HTMLElement | null;
                                const target = clickable || elem;
                                
                                // 인풋 요소면 포커스 먼저
                                if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT") {
                                  target.focus();
                                }
                                // 전체 마우스 이벤트 시퀀스 발생
                                target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true, view: iframe.contentWindow }));
                                target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, cancelable: true, view: iframe.contentWindow }));
                                target.click();
                              }
                            }
                          } catch {
                            // cross-origin 제한시 무시
                          }
                        }
                      };

                      document.addEventListener("mousemove", handleMouseMove);
                      document.addEventListener("mouseup", handleMouseUp);
                    }}
                  />
                </div>
              </TransformComponent>
            )}
          </TransformWrapper>
        )}
      </div>
    </div>
  );
}

export default ScreenSettingModal;

