"use client";

import React, { useState, useCallback, useEffect, useMemo } from "react";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { CalendarIcon, File, Upload, X, Loader2 } from "lucide-react";
import { format } from "date-fns";
import { ko } from "date-fns/locale";
import { useAuth } from "@/hooks/useAuth";
import { uploadFilesAndCreateData } from "@/lib/api/file";
import { toast } from "sonner";
import { showErrorToast } from "@/lib/utils/toastUtils";
import { useCascadingDropdown } from "@/hooks/useCascadingDropdown";
import { CascadingDropdownConfig, LayerDefinition } from "@/types/screen-management";
import {
  ComponentData,
  WidgetComponent,
  DataTableComponent,
  FileComponent,
  TextTypeConfig,
  NumberTypeConfig,
  DateTypeConfig,
  SelectTypeConfig,
  RadioTypeConfig,
  CheckboxTypeConfig,
  TextareaTypeConfig,
  FileTypeConfig,
  CodeTypeConfig,
  EntityTypeConfig,
  ButtonTypeConfig,
} from "@/types";
import { InteractiveDataTable } from "./InteractiveDataTable";
import { FileUpload } from "./widgets/FileUpload";
import { dynamicFormApi, DynamicFormData } from "@/lib/api/dynamicForm";
import { useParams } from "next/navigation";
import { screenApi, tableTypeApi } from "@/lib/api/screen";
import { DynamicWebTypeRenderer } from "@/lib/registry/DynamicWebTypeRenderer";
import { enhancedFormService } from "@/lib/services/enhancedFormService";
import { FormValidationIndicator } from "@/components/common/FormValidationIndicator";
import { useFormValidation } from "@/hooks/useFormValidation";
import { V2ColumnInfo as ColumnInfo } from "@/types";
import { isFileComponent } from "@/lib/utils/componentTypeUtils";
import { buildGridClasses } from "@/lib/constants/columnSpans";
import { ButtonIconRenderer } from "@/lib/button-icon-map";
import { cn } from "@/lib/utils";
import { useScreenPreview } from "@/contexts/ScreenPreviewContext";
import { TableOptionsProvider } from "@/contexts/TableOptionsContext";
import { TableOptionsToolbar } from "./table-options/TableOptionsToolbar";
import { SplitPanelProvider } from "@/lib/registry/components/split-panel-layout/SplitPanelContext";
import { ActiveTabProvider } from "@/contexts/ActiveTabContext";

/**
 * 🔗 연쇄 드롭다운 래퍼 컴포넌트
 * InteractiveScreenViewer 내에서 사용
 */
interface CascadingDropdownWrapperProps {
  /** 직접 설정 방식 */
  config?: CascadingDropdownConfig;
  /** 공통 관리 방식 (관계 코드) */
  relationCode?: string;
  /** 부모 필드명 (relationCode 사용 시 필요) */
  parentFieldName?: string;
  parentValue?: string | number | null;
  value?: string;
  onChange?: (value: string) => void;
  placeholder?: string;
  disabled?: boolean;
  required?: boolean;
}

const CascadingDropdownWrapper: React.FC<CascadingDropdownWrapperProps> = ({
  config,
  relationCode,
  parentFieldName,
  parentValue,
  value,
  onChange,
  placeholder,
  disabled,
  required,
}) => {
  const { options, loading, error, relationConfig } = useCascadingDropdown({
    config,
    relationCode,
    parentValue,
  });
  
  // 실제 사용할 설정 (직접 설정 또는 API에서 가져온 설정)
  const effectiveConfig = config || relationConfig;

  // 부모 값이 없을 때 메시지
  const getPlaceholder = () => {
    if (!parentValue) {
      return effectiveConfig?.emptyParentMessage || "상위 항목을 먼저 선택하세요";
    }
    if (loading) {
      return effectiveConfig?.loadingMessage || "로딩 중...";
    }
    if (options.length === 0) {
      return effectiveConfig?.noOptionsMessage || "선택 가능한 항목이 없습니다";
    }
    return placeholder || "선택하세요";
  };

  const isDisabled = disabled || !parentValue || loading;

  return (
    <Select
      value={value || ""}
      onValueChange={(newValue) => onChange?.(newValue)}
      disabled={isDisabled}
    >
      <SelectTrigger className="h-full w-full">
        {loading ? (
          <div className="flex items-center gap-2">
            <Loader2 className="h-4 w-4 animate-spin" />
            <span className="text-muted-foreground text-sm">로딩 중...</span>
          </div>
        ) : (
          <SelectValue placeholder={getPlaceholder()} />
        )}
      </SelectTrigger>
      <SelectContent>
        {options.length === 0 ? (
          <div className="text-muted-foreground px-2 py-4 text-center text-sm">
            {!parentValue
              ? config.emptyParentMessage || "상위 항목을 먼저 선택하세요"
              : config.noOptionsMessage || "선택 가능한 항목이 없습니다"}
          </div>
        ) : (
          options.map((option) => (
            <SelectItem key={option.value} value={option.value}>
              {option.label}
            </SelectItem>
          ))
        )}
      </SelectContent>
    </Select>
  );
};

interface InteractiveScreenViewerProps {
  component: ComponentData;
  allComponents: ComponentData[];
  formData?: Record<string, any>;
  onFormDataChange?: (fieldName: string, value: any) => void;
  hideLabel?: boolean;
  screenInfo?: {
    id: number;
    tableName?: string;
  };
  menuObjid?: number; // 🆕 메뉴 OBJID (코드 스코프용)
  // 새로운 검증 관련 옵션들
  enableEnhancedValidation?: boolean;
  tableColumns?: ColumnInfo[];
  showValidationPanel?: boolean;
  validationOptions?: {
    enableRealTimeValidation?: boolean;
    validationDelay?: number;
    enableAutoSave?: boolean;
    showToastMessages?: boolean;
  };
  // 🆕 레이어 시스템 지원
  layers?: LayerDefinition[];
}

export const InteractiveScreenViewer: React.FC<InteractiveScreenViewerProps> = ({
  component,
  allComponents,
  formData: externalFormData,
  onFormDataChange,
  hideLabel = false,
  screenInfo,
  menuObjid, // 🆕 메뉴 OBJID
  enableEnhancedValidation = false,
  tableColumns = [],
  showValidationPanel = false,
  validationOptions = {},
  layers = [], // 🆕 레이어 목록
}) => {
  // component가 없으면 빈 div 반환
  if (!component) {
    console.warn("⚠️ InteractiveScreenViewer: component가 undefined입니다.");
    return <div className="h-full w-full" />;
  }

  const { isPreviewMode } = useScreenPreview(); // 프리뷰 모드 확인
  const { userName, user } = useAuth(); // 현재 로그인한 사용자명과 사용자 정보 가져오기
  const [localFormData, setLocalFormData] = useState<Record<string, any>>({});
  const [dateValues, setDateValues] = useState<Record<string, Date | undefined>>({});
  
  // 팝업 화면 상태
  const [popupScreen, setPopupScreen] = useState<{
    screenId: number;
    title: string;
    size: string;
  } | null>(null);
  
  // 팝업 화면 레이아웃 상태
  const [popupLayout, setPopupLayout] = useState<ComponentData[]>([]);
  const [popupLoading, setPopupLoading] = useState(false);
  const [popupScreenResolution, setPopupScreenResolution] = useState<{ width: number; height: number } | null>(null);
  const [popupScreenInfo, setPopupScreenInfo] = useState<{ id: number; tableName?: string } | null>(null);
  
  // 팝업 전용 formData 상태
  const [popupFormData, setPopupFormData] = useState<Record<string, any>>({});

  // 🆕 레이어 상태 관리 (런타임용)
  const [activeLayerIds, setActiveLayerIds] = useState<string[]>([]);

  // 🆕 초기 레이어 설정 (visible인 레이어들)
  useEffect(() => {
    if (layers.length > 0) {
      const initialActiveLayers = layers.filter((l) => l.isVisible).map((l) => l.id);
      setActiveLayerIds(initialActiveLayers);
    }
  }, [layers]);

  // 🆕 레이어 제어 액션 핸들러
  const handleLayerAction = useCallback((action: string, layerId: string) => {
    setActiveLayerIds((prev) => {
      switch (action) {
        case "show":
          return [...new Set([...prev, layerId])];
        case "hide":
          return prev.filter((id) => id !== layerId);
        case "toggle":
          return prev.includes(layerId)
            ? prev.filter((id) => id !== layerId)
            : [...prev, layerId];
        case "exclusive":
          // 해당 레이어만 표시 (모달/드로어 같은 특수 레이어 처리에 활용)
          return [...prev, layerId];
        default:
          return prev;
      }
    });
  }, []);

  // 통합된 폼 데이터
  const finalFormData = { ...localFormData, ...externalFormData };

  // 테이블 타입관리 NOT NULL 기반 필수 여부 판단
  const isColumnRequired = useCallback((columnName: string): boolean => {
    if (!columnName || tableColumns.length === 0) return false;
    const colInfo = tableColumns.find(
      (c: any) => (c.columnName || c.column_name || "").toLowerCase() === columnName.toLowerCase()
    );
    if (!colInfo) return false;
    const nullable = (colInfo as any).isNullable || (colInfo as any).is_nullable;
    return nullable === "NO" || nullable === "N";
  }, [tableColumns]);

  // 🆕 조건부 레이어 로직 (formData 변경 시 자동 평가)
  useEffect(() => {
    layers.forEach((layer) => {
      if (layer.type === "conditional" && layer.condition) {
        const { targetComponentId, operator, value } = layer.condition;
        
        // 1. 컴포넌트 ID로 대상 컴포넌트 찾기
        const targetComponent = allComponents.find((c) => c.id === targetComponentId);
        
        // 2. 컴포넌트의 columnName으로 formData에서 값 조회
        // columnName이 없으면 컴포넌트 ID로 폴백
        const fieldKey = 
          (targetComponent as any)?.columnName || 
          (targetComponent as any)?.componentConfig?.columnName ||
          targetComponentId;
        
        const targetValue = finalFormData[fieldKey];

        let isMatch = false;
        switch (operator) {
          case "eq":
            isMatch = targetValue == value;
            break;
          case "neq":
            isMatch = targetValue != value;
            break;
          case "in":
            isMatch = Array.isArray(value) && value.includes(targetValue);
            break;
        }

        if (isMatch) {
          handleLayerAction("show", layer.id);
        } else {
          handleLayerAction("hide", layer.id);
        }
      }
    });
  }, [finalFormData, layers, allComponents, handleLayerAction]);

  // 🆕 Zone 기반 Y 오프셋 계산 (단순화)
  // Zone 단위로 활성 여부만 판단 → merge 로직 불필요
  const calculateYOffset = useCallback((componentY: number): number => {
    // layers에서 Zone 정보 추출 (displayRegion이 있는 레이어들을 zone 단위로 그룹핑)
    const zoneMap = new Map<number, { y: number; height: number; hasActive: boolean }>();
    
    for (const layer of layers) {
      if (layer.type !== "conditional" || !layer.zoneId || !layer.displayRegion) continue;
      const zid = layer.zoneId;
      if (!zoneMap.has(zid)) {
        zoneMap.set(zid, {
          y: layer.displayRegion.y,
          height: layer.displayRegion.height,
          hasActive: false,
        });
      }
      if (activeLayerIds.includes(layer.id)) {
        zoneMap.get(zid)!.hasActive = true;
      }
    }

    let totalOffset = 0;
    for (const [, zone] of zoneMap) {
      const zoneBottom = zone.y + zone.height;
      // 컴포넌트가 Zone 하단보다 아래에 있고, Zone에 활성 레이어가 없으면 접힘
      if (componentY >= zoneBottom && !zone.hasActive) {
        totalOffset += zone.height;
      }
    }

    return totalOffset;
  }, [layers, activeLayerIds]);

  // 개선된 검증 시스템 (선택적 활성화)
  const enhancedValidation = enableEnhancedValidation && screenInfo && tableColumns.length > 0 
    ? useFormValidation(
        finalFormData,
        allComponents.filter(c => c.type === 'widget') as WidgetComponent[],
        tableColumns,
        { 
          id: screenInfo.id, 
          screenName: screenInfo.tableName || "unknown",
          tableName: screenInfo.tableName,
          screenResolution: { width: 800, height: 600 },
          gridSettings: { size: 20, color: "#e0e0e0", opacity: 0.5 },
          description: "동적 화면"
        },
        {
          enableRealTimeValidation: true,
          validationDelay: 300,
          enableAutoSave: false,
          showToastMessages: true,
          ...validationOptions,
        }
      )
    : null;

  // 자동값 생성 함수
  const generateAutoValue = useCallback(async (autoValueType: string, ruleId?: string): Promise<string> => {
    const now = new Date();
    const pad = (n: number) => String(n).padStart(2, "0");
    const localDate = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
    const localTime = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
    switch (autoValueType) {
      case "current_datetime":
        return `${localDate} ${localTime}`;
      case "current_date":
        return localDate;
      case "current_time":
        return localTime;
      case "current_user":
        // 실제 접속중인 사용자명 사용
        return userName || "사용자"; // 사용자명이 없으면 기본값
      case "uuid":
        return crypto.randomUUID();
      case "sequence":
        return `SEQ_${Date.now()}`;
      case "numbering_rule":
        // 채번 규칙 사용
        if (ruleId) {
          try {
            const { generateNumberingCode } = await import("@/lib/api/numberingRule");
            const response = await generateNumberingCode(ruleId);
            if (response.success && response.data) {
              return response.data.generatedCode;
            }
          } catch (error) {
            console.error("채번 규칙 코드 생성 실패:", error);
          }
        }
        return "";
      default:
        return "";
    }
  }, [userName]); // userName 의존성 추가

  // 팝업 화면 레이아웃 로드
  React.useEffect(() => {
    if (popupScreen) {
      const loadPopupLayout = async () => {
        try {
          setPopupLoading(true);
          // console.log("🔍 팝업 화면 로드 시작:", popupScreen);
          
          // 화면 레이아웃과 화면 정보를 병렬로 가져오기
          const [layout, screen] = await Promise.all([
            screenApi.getLayout(popupScreen.screenId),
            screenApi.getScreen(popupScreen.screenId)
          ]);
          
          console.log("📊 팝업 화면 로드 완료:", {
            componentsCount: layout.components?.length || 0,
            screenInfo: {
              screenId: screen.screenId,
              tableName: screen.tableName
            },
            popupFormData: {}
          });
          
          setPopupLayout(layout.components || []);
          setPopupScreenResolution(layout.screenResolution || null);
          setPopupScreenInfo({
            id: popupScreen.screenId,
            tableName: screen.tableName
          });
          
          // 팝업 formData 초기화
          setPopupFormData({});
        } catch (error) {
          // console.error("❌ 팝업 화면 로드 실패:", error);
          setPopupLayout([]);
          setPopupScreenInfo(null);
        } finally {
          setPopupLoading(false);
        }
      };
      
      loadPopupLayout();
    }
  }, [popupScreen]);

  // 실제 사용할 폼 데이터 (외부와 로컬 데이터 병합)
  const formData = { ...localFormData, ...externalFormData };
  console.log("🔄 formData 구성:", {
    external: externalFormData,
    local: localFormData,
    merged: formData,
    hasExternalCallback: !!onFormDataChange
  });

  // 폼 데이터 업데이트
  const updateFormData = (fieldName: string, value: any) => {
    // 프리뷰 모드에서는 데이터 업데이트 하지 않음
    if (isPreviewMode) {
      return;
    }
    
    // console.log(`🔄 updateFormData: ${fieldName} = "${value}" (외부콜백: ${!!onFormDataChange})`);
    
    // 항상 로컬 상태도 업데이트
    setLocalFormData((prev) => ({
      ...prev,
      [fieldName]: value,
    }));
    // console.log(`💾 로컬 상태 업데이트: ${fieldName} = "${value}"`);
    
    // 외부 콜백이 있는 경우에도 전달 (개별 필드 단위로)
    if (onFormDataChange) {
      onFormDataChange(fieldName, value);
      // console.log(`📤 외부 콜백으로 전달: ${fieldName} = "${value}"`);
    }
  };

  // 자동입력 필드들의 값을 formData에 초기 설정
  React.useEffect(() => {
    // console.log("🚀 자동입력 초기화 useEffect 실행 - allComponents 개수:", allComponents.length);
    const initAutoInputFields = async () => {
      // console.log("🔧 initAutoInputFields 실행 시작");
      for (const comp of allComponents) {
        // 🆕 type: "component" 또는 type: "widget" 모두 처리
        if (comp.type === 'widget' || comp.type === 'component') {
          const widget = comp as WidgetComponent;
          const fieldName = widget.columnName || widget.id;
          
          // 🆕 autoFill 처리 (테이블 조회 기반 자동 입력)
          if (widget.autoFill?.enabled || (comp as any).autoFill?.enabled) {
            const autoFillConfig = widget.autoFill || (comp as any).autoFill;
            const currentValue = formData[fieldName];
            if (currentValue === undefined || currentValue === '') {
              const { sourceTable, filterColumn, userField, displayColumn } = autoFillConfig;
              
              // 사용자 정보에서 필터 값 가져오기
              const userValue = user?.[userField];
              
              if (userValue && sourceTable && filterColumn && displayColumn) {
                try {
                  const result = await tableTypeApi.getTableRecord(
                    sourceTable,
                    filterColumn,
                    userValue,
                    displayColumn
                  );
                  
                  updateFormData(fieldName, result.value);
                } catch (error) {
                  console.error(`autoFill 조회 실패: ${fieldName}`, error);
                }
              }
            }
            continue; // autoFill이 활성화되면 일반 자동입력은 건너뜀
          }
          
          // 기존 widget 타입 전용 로직은 widget인 경우만
          if (comp.type !== 'widget') continue;
          
          // 텍스트 타입 위젯의 자동입력 처리 (기존 로직)
          if ((widget.widgetType === 'text' || widget.widgetType === 'email' || widget.widgetType === 'tel') && 
              widget.webTypeConfig) {
            const config = widget.webTypeConfig as TextTypeConfig;
            const isAutoInput = config?.autoInput || false;
            
            if (isAutoInput && config?.autoValueType) {
              // 이미 값이 있으면 덮어쓰지 않음
              const currentValue = formData[fieldName];
              console.log(`🔍 자동입력 필드 체크: ${fieldName}`, {
                currentValue,
                isEmpty: currentValue === undefined || currentValue === '',
                isAutoInput,
                autoValueType: config.autoValueType
              });
              
              if (currentValue === undefined || currentValue === '') {
                const autoValue = config.autoValueType === "custom" 
                  ? config.customValue || ""
                  : generateAutoValue(config.autoValueType);
                
                console.log("🔄 자동입력 필드 초기화:", {
                  fieldName,
                  autoValueType: config.autoValueType,
                  autoValue
                });
                
                updateFormData(fieldName, autoValue);
              } else {
                // console.log(`⏭️ 자동입력 건너뜀 (값 있음): ${fieldName} = "${currentValue}"`);
              }
            }
          }
        }
      }
    };

    // 초기 로드 시 자동입력 필드들 설정
    initAutoInputFields();
  }, [allComponents, generateAutoValue, user]); // formData는 의존성에서 제외 (무한 루프 방지)

  // 날짜 값 업데이트
  const updateDateValue = (fieldName: string, date: Date | undefined) => {
    setDateValues((prev) => ({
      ...prev,
      [fieldName]: date,
    }));
    updateFormData(fieldName, date ? format(date, "yyyy-MM-dd") : "");
  };

  // 실제 사용 가능한 위젯 렌더링
  const renderInteractiveWidget = (comp: ComponentData) => {
    console.log("🎯 renderInteractiveWidget 호출:", {
      type: comp.type,
      id: comp.id,
      componentId: (comp as any).componentId,
      hasComponentConfig: !!(comp as any).componentConfig,
      componentConfig: (comp as any).componentConfig,
    });

    // 데이터 테이블 컴포넌트 처리
    if (comp.type === "datatable") {
      return (
        <InteractiveDataTable
          component={comp as DataTableComponent}
          className="h-full w-full"
          style={{
            width: "100%",
            height: "100%",
          }}
          onRefresh={() => {
            // 테이블 내부에서 loadData 호출하므로 여기서는 빈 함수
            console.log("🔄 InteractiveDataTable 새로고침 트리거됨");
          }}
        />
      );
    }

    // 플로우 위젯 컴포넌트 처리
    if (comp.type === "flow" || (comp.type === "component" && (comp as any).componentConfig?.type === "flow-widget")) {
      const FlowWidget = require("@/components/screen/widgets/FlowWidget").FlowWidget;
      // componentConfig에서 flowId 추출
      const flowConfig = (comp as any).componentConfig || {};
      
      console.log("🔍 InteractiveScreenViewer 플로우 위젯 변환:", {
        compType: comp.type,
        hasComponentConfig: !!(comp as any).componentConfig,
        flowConfig,
        flowConfigFlowId: flowConfig.flowId,
        finalFlowId: flowConfig.flowId,
      });
      
      const flowComponent = {
        ...comp,
        type: "flow" as const,
        flowId: flowConfig.flowId,
        flowName: flowConfig.flowName,
        showStepCount: flowConfig.showStepCount !== false,
        allowDataMove: flowConfig.allowDataMove || false,
        displayMode: flowConfig.displayMode || "horizontal",
      };
      
      console.log("🔍 InteractiveScreenViewer 최종 flowComponent:", flowComponent);
      
      return (
        <div className="w-full">
          <FlowWidget component={flowComponent as any} />
        </div>
      );
    }

    // 탭 컴포넌트 처리 (v1, v2 모두 지원)
    const componentType = (comp as any).componentType || (comp as any).componentId;
    if (comp.type === "tabs" || (comp.type === "component" && (componentType === "tabs-widget" || componentType === "v2-tabs-widget"))) {
      const TabsWidget = require("@/components/screen/widgets/TabsWidget").TabsWidget;
      
      // componentConfig에서 탭 정보 추출
      const tabsConfig = comp.componentConfig || {};
      const tabsComponent = {
        ...comp,
        type: "tabs" as const,
        tabs: tabsConfig.tabs || [],
        defaultTab: tabsConfig.defaultTab,
        orientation: tabsConfig.orientation || "horizontal",
        variant: tabsConfig.variant || "default",
        allowCloseable: tabsConfig.allowCloseable || false,
        persistSelection: tabsConfig.persistSelection || false,
      };
      
      return (
        <div className="h-full w-full">
          <TabsWidget 
            component={tabsComponent as any} 
            menuObjid={menuObjid}
            formData={formData}
            onFormDataChange={updateFormData}
          />
        </div>
      );
    }

    // 🆕 렉 구조 컴포넌트 처리 (v1, v2 모두 지원)
    if (comp.type === "component" && (componentType === "rack-structure" || componentType === "v2-rack-structure")) {
      // v2 컴포넌트 사용 (v1은 deprecated)
      const { RackStructureComponent } = require("@/lib/registry/components/v2-rack-structure/RackStructureComponent");
      const componentConfig = (comp as any).componentConfig || {};
      // config가 중첩되어 있을 수 있음: componentConfig.config 또는 componentConfig 직접
      const rackConfig = componentConfig.config || componentConfig;
      
      return (
        <div className="h-full w-full overflow-auto">
          <RackStructureComponent
            config={rackConfig}
            formData={formData}
            tableName={tableName}
            onChange={(locations: any[]) => {
              // 컴포넌트의 columnName을 키로 사용
              const fieldKey = (comp as any).columnName || "_rackStructureLocations";
              updateFormData(fieldKey, locations);
            }}
            isPreview={false}
          />
        </div>
      );
    }

    const { widgetType, label: originalLabel, placeholder, required, readonly, columnName } = comp;
    const fieldName = columnName || comp.id;
    const currentValue = formData[fieldName] || "";

    // 🆕 엔티티 조인 컬럼은 읽기 전용으로 처리
    const isEntityJoin = (comp as any).isEntityJoin === true;
    const isReadonly = readonly || isEntityJoin;

    // 다국어 라벨 적용 (langKey가 있으면 번역 텍스트 사용)
    const compLangKey = (comp as any).langKey;
    const label = compLangKey && translations[compLangKey] ? translations[compLangKey] : originalLabel;

    const applyStyles = (element: React.ReactElement) => {
      if (!comp.style) return element;

      // ✅ 격자 시스템 잔재 제거: style.width, style.height는 무시
      // size.width, size.height가 부모 컨테이너에서 적용되므로
      const { width, height, ...styleWithoutSize } = comp.style;

      return React.cloneElement(element, {
        style: {
          ...element.props.style, // 기존 스타일 유지
          ...styleWithoutSize,  // width/height 제외한 스타일만 적용
          boxSizing: "border-box",
        },
      });
    };

    switch (widgetType) {
      case "text":
      case "email":
      case "tel": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as TextTypeConfig | undefined;

        // 자동입력 관련 처리
        const isAutoInput = config?.autoInput || false;
        const autoValue = isAutoInput && config?.autoValueType
          ? config.autoValueType === "custom" 
            ? config.customValue || ""
            : generateAutoValue(config.autoValueType)
          : "";
        
        // 기본값 또는 자동값 설정
        const displayValue = isAutoInput ? autoValue : currentValue || config?.defaultValue || "";

        console.log("📝 InteractiveScreenViewer - Text 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            format: config?.format,
            minLength: config?.minLength,
            maxLength: config?.maxLength,
            pattern: config?.pattern,
            placeholder: config?.placeholder,
            defaultValue: config?.defaultValue,
            autoInput: isAutoInput,
            autoValueType: config?.autoValueType,
            autoValue,
            displayValue,
          },
        });

        // 형식별 패턴 생성
        const getPatternByFormat = (format: string) => {
          switch (format) {
            case "korean":
              return "[가-힣\\s]*";
            case "english":
              return "[a-zA-Z\\s]*";
            case "alphanumeric":
              return "[a-zA-Z0-9]*";
            case "numeric":
              return "[0-9]*";
            case "email":
              return "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}";
            case "phone":
              return "\\d{3}-\\d{4}-\\d{4}";
            case "url":
              return "https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?";
            default:
              return config?.pattern || undefined;
          }
        };

        // 입력 검증 함수
        const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
          const value = e.target.value;
          // console.log(`📝 입력 변경: ${fieldName} = "${value}"`);

          // 형식별 실시간 검증
          if (config?.format && config.format !== "none") {
            const pattern = getPatternByFormat(config.format);
            if (pattern) {
              const regex = new RegExp(`^${pattern}$`);
              if (value && !regex.test(value)) {
                // console.log(`❌ 형식 검증 실패: ${fieldName} = "${value}"`);
                return; // 유효하지 않은 입력 차단
              }
            }
          }

          // 길이 제한 검증
          if (config?.maxLength && value.length > config.maxLength) {
            // console.log(`❌ 길이 제한 초과: ${fieldName} = "${value}" (최대: ${config.maxLength})`);
            return; // 최대 길이 초과 차단
          }

          // console.log(`✅ updateFormData 호출: ${fieldName} = "${value}"`);
          updateFormData(fieldName, value);
        };

        const finalPlaceholder = config?.placeholder || placeholder || "입력하세요...";
        const inputType = widgetType === "email" ? "email" : widgetType === "tel" ? "tel" : "text";

        return applyStyles(
          <Input
            type={inputType}
            placeholder={isAutoInput ? `자동입력: ${config?.autoValueType}` : finalPlaceholder}
            value={displayValue}
            onChange={isAutoInput ? undefined : handleInputChange}
            disabled={isReadonly || isAutoInput}
            readOnly={isAutoInput}
            required={required}
            minLength={config?.minLength}
            maxLength={config?.maxLength}
            pattern={getPatternByFormat(config?.format || "none")}
            className={`w-full ${isAutoInput ? "bg-muted text-muted-foreground" : ""}`}
          />,
        );
      }

      case "number":
      case "decimal": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as NumberTypeConfig | undefined;

        console.log("🔢 InteractiveScreenViewer - Number 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            format: config?.format,
            min: config?.min,
            max: config?.max,
            step: config?.step,
            decimalPlaces: config?.decimalPlaces,
            thousandSeparator: config?.thousandSeparator,
            prefix: config?.prefix,
            suffix: config?.suffix,
          },
        });

        const step = config?.step || (widgetType === "decimal" ? 0.01 : 1);
        const finalPlaceholder = config?.placeholder || placeholder || "숫자를 입력하세요...";

        return applyStyles(
          <Input
            type="number"
            placeholder={finalPlaceholder}
            value={currentValue}
            onChange={(e) => updateFormData(fieldName, e.target.valueAsNumber || 0)}
            disabled={isReadonly}
            required={required}
            min={config?.min}
            max={config?.max}
            step={step}
            className="w-full"
            style={{ height: "100%" }}
          />,
        );
      }

      case "textarea":
      case "text_area": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as TextareaTypeConfig | undefined;

        console.log("📄 InteractiveScreenViewer - Textarea 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            rows: config?.rows,
            maxLength: config?.maxLength,
            minLength: config?.minLength,
            placeholder: config?.placeholder,
            defaultValue: config?.defaultValue,
            resizable: config?.resizable,
            wordWrap: config?.wordWrap,
          },
        });

        const finalPlaceholder = config?.placeholder || placeholder || "내용을 입력하세요...";
        const rows = config?.rows || 3;

        return applyStyles(
          <Textarea
            placeholder={finalPlaceholder}
            value={currentValue || config?.defaultValue || ""}
            onChange={(e) => updateFormData(fieldName, e.target.value)}
            disabled={isReadonly}
            required={required}
            minLength={config?.minLength}
            maxLength={config?.maxLength}
            rows={rows}
            className={`h-full w-full ${config?.resizable === false ? "resize-none" : ""}`}
            style={{
              whiteSpace: config?.wordWrap === false ? "nowrap" : "normal",
            }}
          />,
        );
      }

      case "select":
      case "dropdown": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as SelectTypeConfig | undefined;

        console.log("📋 InteractiveScreenViewer - Select 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            options: config?.options,
            multiple: config?.multiple,
            searchable: config?.searchable,
            placeholder: config?.placeholder,
            defaultValue: config?.defaultValue,
            cascading: config?.cascading,
          },
        });

        const finalPlaceholder = config?.placeholder || placeholder || "선택하세요...";
        
        // 🆕 연쇄 드롭다운 처리 (방법 1: 관계 코드 방식 - 권장)
        if (config?.cascadingRelationCode && config?.cascadingParentField) {
          const parentFieldValue = formData[config.cascadingParentField];
          
          console.log("🔗 연쇄 드롭다운 (관계코드 방식):", {
            relationCode: config.cascadingRelationCode,
            parentField: config.cascadingParentField,
            parentValue: parentFieldValue,
          });
          
          return applyStyles(
            <CascadingDropdownWrapper
              relationCode={config.cascadingRelationCode}
              parentFieldName={config.cascadingParentField}
              parentValue={parentFieldValue}
              value={currentValue}
              onChange={(value) => updateFormData(fieldName, value)}
              placeholder={finalPlaceholder}
              disabled={isReadonly}
              required={required}
            />,
          );
        }
        
        // 🔄 연쇄 드롭다운 처리 (방법 2: 직접 설정 방식 - 레거시)
        if (config?.cascading?.enabled) {
          const cascadingConfig = config.cascading;
          const parentValue = formData[cascadingConfig.parentField];
          
          return applyStyles(
            <CascadingDropdownWrapper
              config={cascadingConfig}
              parentValue={parentValue}
              value={currentValue}
              onChange={(value) => updateFormData(fieldName, value)}
              placeholder={finalPlaceholder}
              disabled={isReadonly}
              required={required}
            />,
          );
        }
        
        // 일반 Select
        const options = config?.options || [
          { label: "옵션 1", value: "option1" },
          { label: "옵션 2", value: "option2" },
          { label: "옵션 3", value: "option3" },
        ];

        return applyStyles(
          <Select
            value={currentValue || config?.defaultValue || ""}
            onValueChange={(value) => updateFormData(fieldName, value)}
            disabled={isReadonly}
            required={required}
          >
            <SelectTrigger className="h-full w-full">
              <SelectValue placeholder={finalPlaceholder} />
            </SelectTrigger>
            <SelectContent>
              {options.map((option, index) => (
                <SelectItem key={index} value={option.value} disabled={option.disabled}>
                  {option.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>,
        );
      }

      case "checkbox":
      case "boolean": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as CheckboxTypeConfig | undefined;

        console.log("☑️ InteractiveScreenViewer - Checkbox 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            defaultChecked: config?.defaultChecked,
            labelPosition: config?.labelPosition,
            checkboxText: config?.checkboxText,
            trueValue: config?.trueValue,
            falseValue: config?.falseValue,
          },
        });

        const isChecked = currentValue === true || currentValue === "true" || config?.defaultChecked;
        const checkboxText = config?.checkboxText || label || "확인";
        const labelPosition = config?.labelPosition || "right";

        return applyStyles(
          <div
            className={`flex h-full w-full items-center space-x-2 ${labelPosition === "left" ? "flex-row-reverse" : ""}`}
          >
            <Checkbox
              id={fieldName}
              checked={isChecked}
              onCheckedChange={(checked) => updateFormData(fieldName, checked)}
              disabled={isReadonly}
              required={required}
            />
            <label htmlFor={fieldName} className="text-sm">
              {checkboxText}
            </label>
          </div>,
        );
      }

      case "radio": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as RadioTypeConfig | undefined;

        console.log("🔘 InteractiveScreenViewer - Radio 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            options: config?.options,
            defaultValue: config?.defaultValue,
            layout: config?.layout,
            allowNone: config?.allowNone,
          },
        });

        const options = config?.options || [
          { label: "옵션 1", value: "option1" },
          { label: "옵션 2", value: "option2" },
          { label: "옵션 3", value: "option3" },
        ];

        const layout = config?.layout || "vertical";
        const selectedValue = currentValue || config?.defaultValue || "";

        return applyStyles(
          <div className={`h-full w-full ${layout === "horizontal" ? "flex flex-wrap gap-4" : "space-y-2"}`}>
            {config?.allowNone && (
              <div className="flex items-center space-x-2">
                <input
                  type="radio"
                  id={`${fieldName}_none`}
                  name={fieldName}
                  value=""
                  checked={selectedValue === ""}
                  onChange={(e) => updateFormData(fieldName, e.target.value)}
                  disabled={isReadonly}
                  required={required}
                  className="h-4 w-4"
                />
                <label htmlFor={`${fieldName}_none`} className="text-sm">
                  선택 안함
                </label>
              </div>
            )}
            {options.map((option, index) => (
              <div key={index} className="flex items-center space-x-2">
                <input
                  type="radio"
                  id={`${fieldName}_${index}`}
                  name={fieldName}
                  value={option.value}
                  checked={selectedValue === option.value}
                  onChange={(e) => updateFormData(fieldName, e.target.value)}
                  disabled={isReadonly || option.disabled}
                  required={required}
                  className="h-4 w-4"
                />
                <label htmlFor={`${fieldName}_${index}`} className="text-sm">
                  {option.label}
                </label>
              </div>
            ))}
          </div>,
        );
      }

      case "date": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as DateTypeConfig | undefined;

        console.log("📅 InteractiveScreenViewer - Date 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            format: config?.format,
            showTime: config?.showTime,
            defaultValue: config?.defaultValue,
            minDate: config?.minDate,
            maxDate: config?.maxDate,
          },
        });

        const shouldShowTime = config?.showTime || config?.format?.includes("HH:mm");
        const finalPlaceholder = config?.placeholder || placeholder || "날짜를 선택하세요";

        if (shouldShowTime) {
          // 시간 포함 날짜 입력
          return applyStyles(
            <Input
              type="datetime-local"
              placeholder={finalPlaceholder}
              value={currentValue || config?.defaultValue || ""}
              onChange={(e) => updateFormData(fieldName, e.target.value)}
              disabled={isReadonly}
              required={required}
              min={config?.minDate}
              max={config?.maxDate}
              className="w-full"
            style={{ height: "100%" }}
            />,
          );
        } else {
          // 날짜만 입력
          const dateValue = dateValues[fieldName];
          return applyStyles(
            <Popover>
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  className="h-full w-full justify-start text-left font-normal"
                  disabled={isReadonly}
                >
                  <CalendarIcon className="mr-2 h-4 w-4" />
                  {dateValue ? format(dateValue, "PPP", { locale: ko }) : config?.defaultValue || finalPlaceholder}
                </Button>
              </PopoverTrigger>
              <PopoverContent className="w-auto p-0">
                <Calendar
                  mode="single"
                  selected={dateValue}
                  onSelect={(date) => updateDateValue(fieldName, date)}
                  initialFocus
                />
              </PopoverContent>
            </Popover>,
          );
        }
      }

      case "datetime": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as DateTypeConfig | undefined;

        console.log("🕐 InteractiveScreenViewer - DateTime 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            format: config?.format,
            defaultValue: config?.defaultValue,
            minDate: config?.minDate,
            maxDate: config?.maxDate,
          },
        });

        const finalPlaceholder = config?.placeholder || placeholder || "날짜와 시간을 입력하세요...";

        return applyStyles(
          <Input
            type="datetime-local"
            placeholder={finalPlaceholder}
            value={currentValue || config?.defaultValue || ""}
            onChange={(e) => updateFormData(fieldName, e.target.value)}
            disabled={isReadonly}
            required={required}
            min={config?.minDate}
            max={config?.maxDate}
            className="w-full"
            style={{ height: "100%" }}
          />,
        );
      }

      case "file": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as FileTypeConfig | undefined;
        
        // 현재 파일 값 가져오기
        const getCurrentValue = () => {
          const fieldName = widget.columnName || widget.id;
          return (externalFormData?.[fieldName] || localFormData[fieldName]) as any;
        };
        
        const currentValue = getCurrentValue();

        // 화면 ID 추출 (URL에서)
        const screenId = typeof window !== 'undefined' && window.location.pathname.includes('/screens/') 
          ? parseInt(window.location.pathname.split('/screens/')[1]) 
          : null;

        console.log("📁 InteractiveScreenViewer - File 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          currentValue,
          screenId,
          appliedSettings: {
            accept: config?.accept,
            multiple: config?.multiple,
            maxSize: config?.maxSize,
            preview: config?.preview,
          },
        });

        const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
          // 프리뷰 모드에서는 파일 업로드 차단
          if (isPreviewMode) {
            e.target.value = ""; // 파일 선택 취소
            return;
          }
          
          const files = e.target.files;
          const fieldName = widget.columnName || widget.id;
          
          // 파일 선택을 취소한 경우 (files가 null이거나 길이가 0)
          if (!files || files.length === 0) {
            // console.log("📁 파일 선택 취소됨 - 기존 파일 유지");
            
            // 현재 저장된 파일이 있는지 확인
            const currentStoredValue = externalFormData?.[fieldName] || localFormData[fieldName];
            if (currentStoredValue) {
              // console.log("📁 기존 파일 있음 - 유지:", currentStoredValue);
              // 기존 파일이 있으면 그대로 유지 (아무것도 하지 않음)
              return;
            } else {
              // console.log("📁 기존 파일 없음 - 빈 상태 유지");
              // 기존 파일이 없으면 빈 상태 유지
              return;
            }
          }

          // 파일 크기 검증
          if (config?.maxSize) {
            for (let i = 0; i < files.length; i++) {
              const file = files[i];
              if (file.size > config.maxSize * 1024 * 1024) {
                alert(`파일 크기가 ${config.maxSize}MB를 초과합니다: ${file.name}`);
                e.target.value = "";
                return;
              }
            }
          }

          // 실제 서버로 파일 업로드
          try {
            toast.loading(`${files.length}개 파일 업로드 중...`);
            
            const uploadResult = await uploadFilesAndCreateData(files);
            
            if (uploadResult.success) {
              // console.log("📁 업로드 완료된 파일 데이터:", uploadResult.data);
              
              setLocalFormData(prev => ({ ...prev, [fieldName]: uploadResult.data }));
              
              // 외부 폼 데이터 변경 콜백 호출
              if (onFormDataChange) {
                onFormDataChange(fieldName, uploadResult.data);
              }
              
              toast.success(uploadResult.message);
            } else {
              throw new Error("파일 업로드에 실패했습니다.");
            }
          } catch (error) {
            // console.error("파일 업로드 오류:", error);
            showErrorToast("파일 업로드에 실패했습니다", error, { guidance: "파일 크기와 형식을 확인하고 다시 시도해 주세요." });
            
            // 파일 입력 초기화
            e.target.value = "";
            return;
          }
        };

        const clearFile = () => {
          const fieldName = widget.columnName || widget.id;
          setLocalFormData(prev => ({ ...prev, [fieldName]: null }));
          
          // 외부 폼 데이터 변경 콜백 호출
          if (onFormDataChange) {
            onFormDataChange(fieldName, null);
          }
          
          // 파일 input 초기화
          const fileInput = document.querySelector(`input[type="file"][data-field="${fieldName}"]`) as HTMLInputElement;
          if (fileInput) {
            fileInput.value = "";
          }
        };

        const renderFilePreview = () => {
          if (!currentValue || !config?.preview) return null;

          // 새로운 JSON 구조에서 파일 정보 추출
          const fileData = currentValue.files || [];
          if (fileData.length === 0) return null;
          
          return (
            <div className="mt-2 space-y-2">
              <div className="text-sm font-medium text-foreground">
                업로드된 파일 ({fileData.length}개)
              </div>
              {fileData.map((fileInfo: any, index: number) => {
                const isImage = fileInfo.type?.startsWith('image/');
                
                return (
                  <div key={index} className="flex items-center gap-2 rounded border bg-muted p-2">
                    <div className="flex h-16 w-16 items-center justify-center rounded bg-muted/50">
                      {isImage ? (
                        <div className="text-success text-xs font-medium">IMG</div>
                      ) : (
                        <File className="h-8 w-8 text-muted-foreground" />
                      )}
                    </div>
                    <div className="flex-1 min-w-0">
                      <p className="text-sm font-medium text-foreground truncate">{fileInfo.name}</p>
                      <p className="text-xs text-muted-foreground">
                        {(fileInfo.size / 1024 / 1024).toFixed(2)} MB
                      </p>
                      <p className="text-xs text-muted-foreground">{fileInfo.type || '알 수 없는 형식'}</p>
                      <p className="text-xs text-muted-foreground/70">업로드: {new Date(fileInfo.uploadedAt).toLocaleString('ko-KR')}</p>
                    </div>
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      onClick={clearFile}
                      className="h-8 w-8 p-0"
                    >
                      <X className="h-4 w-4" />
                    </Button>
                  </div>
                );
              })}
            </div>
          );
        };

        const fieldName = widget.columnName || widget.id;
        
        return applyStyles(
          <div className="w-full space-y-2">
            {/* 파일 선택 영역 */}
            <div className="relative">
              <input
                type="file"
                data-field={fieldName}
                onChange={handleFileChange}
                disabled={isReadonly}
                required={required}
                multiple={config?.multiple}
                accept={config?.accept}
                className="absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed"
                style={{ zIndex: 1 }}
              />
              <div className={cn(
                "flex items-center justify-center rounded-lg border-2 border-dashed p-4 text-center transition-colors",
                currentValue && currentValue.files && currentValue.files.length > 0 
                  ? 'border-success/30 bg-success/10' 
                  : 'border-input bg-muted hover:border-input/80 hover:bg-muted/80',
                readonly && 'cursor-not-allowed opacity-50',
                !readonly && 'cursor-pointer'
              )}>
                <div className="space-y-2">
                  {currentValue && currentValue.files && currentValue.files.length > 0 ? (
                    <>
                      <div className="flex items-center justify-center">
                        <div className="flex h-8 w-8 items-center justify-center rounded-full bg-success/20">
                          <svg className="h-5 w-5 text-success" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
                          </svg>
                        </div>
                      </div>
                      <p className="text-sm font-medium text-success">
                        {currentValue.totalCount === 1 
                          ? '파일 선택됨' 
                          : `${currentValue.totalCount}개 파일 선택됨`}
                      </p>
                      <p className="text-xs text-success/80">
                        총 {(currentValue.totalSize / 1024 / 1024).toFixed(2)}MB
                      </p>
                      <p className="text-xs text-success/80">클릭하여 다른 파일 선택</p>
                    </>
                  ) : (
                    <>
                      <Upload className="mx-auto h-8 w-8 text-muted-foreground" />
                      <p className="text-sm text-muted-foreground">
                        {config?.dragDrop ? '파일을 드래그하여 놓거나 클릭하여 선택' : '클릭하여 파일 선택'}
                      </p>
                      {(config?.accept || config?.maxSize) && (
                        <div className="text-xs text-muted-foreground space-y-1">
                          {config.accept && <div>허용 형식: {config.accept}</div>}
                          {config.maxSize && <div>최대 크기: {config.maxSize}MB</div>}
                          {config.multiple && <div>다중 선택 가능</div>}
                        </div>
                      )}
                    </>
                  )}
                </div>
              </div>
            </div>
            
            {/* 파일 미리보기 */}
            {renderFilePreview()}
          </div>
        );
      }

      case "code": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as CodeTypeConfig | undefined;

        console.log(`🔍 [InteractiveScreenViewer] Code 위젯 렌더링:`, {
          componentId: widget.id,
          columnName: widget.columnName,
          codeCategory: config?.codeCategory,
          menuObjid,
          hasMenuObjid: !!menuObjid,
        });

        // code 타입은 공통코드 선택박스로 처리
        // DynamicWebTypeRenderer를 사용하여 SelectBasicComponent 렌더링
        try {
          return applyStyles(
            <DynamicWebTypeRenderer
              webType="select"
              props={{
                component: widget,
                value: currentValue,
                onChange: (value: any) => updateFormData(fieldName, value),
                onFormDataChange: updateFormData,
                isInteractive: true,
                readonly: readonly,
                required: required,
                placeholder: config?.placeholder || "코드를 선택하세요...",
                className: "w-full h-full",
                menuObjid: menuObjid, // 🆕 메뉴 OBJID 전달
              }}
              config={{
                ...config,
                codeCategory: config?.codeCategory,
                isCodeType: true, // 코드 타입임을 명시
              }}
              onEvent={(event: string, data: any) => {
                // console.log(`Code widget event: ${event}`, data);
              }}
            />
          );
        } catch (error) {
          // console.error("DynamicWebTypeRenderer 로딩 실패, 기본 Select 사용:", error);
          
          // 폴백: 기본 Select 컴포넌트 사용
          return applyStyles(
            <Select
              value={currentValue || ""}
              onValueChange={(value) => updateFormData(fieldName, value)}
              disabled={isReadonly}
              required={required}
            >
              <SelectTrigger className="h-full w-full">
                <SelectValue placeholder={config?.placeholder || "코드를 선택하세요..."} />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="loading">로딩 중...</SelectItem>
              </SelectContent>
            </Select>
          );
        }
      }

      case "entity": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as EntityTypeConfig | undefined;

        console.log("🏢 InteractiveScreenViewer - Entity 위젯:", {
          componentId: widget.id,
          widgetType: widget.widgetType,
          config,
          appliedSettings: {
            entityName: config?.entityName,
            displayField: config?.displayField,
            valueField: config?.valueField,
            multiple: config?.multiple,
            defaultValue: config?.defaultValue,
          },
        });

        const finalPlaceholder = config?.placeholder || "엔티티를 선택하세요...";
        const defaultOptions = [
          { label: "사용자", value: "user" },
          { label: "제품", value: "product" },
          { label: "주문", value: "order" },
          { label: "카테고리", value: "category" },
        ];

        return (
          <Select
            value={currentValue || config?.defaultValue || ""}
            onValueChange={(value) => updateFormData(fieldName, value)}
            disabled={readonly}
            required={required}
          >
            <SelectTrigger 
              className="w-full"
              style={{
                ...comp.style,
                width: "100%",
                height: "100%",
              }}
            >
              <SelectValue placeholder={finalPlaceholder} />
            </SelectTrigger>
            <SelectContent>
              {defaultOptions.map((option) => (
                <SelectItem key={option.value} value={option.value}>
                  {config?.displayFormat
                    ? config.displayFormat.replace("{label}", option.label).replace("{value}", option.value)
                    : option.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        );
      }

      case "button": {
        const widget = comp as WidgetComponent;
        const config = widget.webTypeConfig as ButtonTypeConfig | undefined;

        const handleButtonClick = async () => {
          // 프리뷰 모드에서는 버튼 동작 차단
          if (isPreviewMode) {
            return;
          }
          
          const actionType = config?.actionType || "save";
          
          try {
            switch (actionType) {
              case "save":
                await handleSaveAction();
                break;
              case "delete":
                await handleDeleteAction();
                break;
              case "edit":
                handleEditAction();
                break;
              case "add":
                handleAddAction();
                break;
              case "search":
                handleSearchAction();
                break;
              case "reset":
                handleResetAction();
                break;
              case "submit":
                await handleSubmitAction();
                break;
              case "close":
                handleCloseAction();
                break;
              case "popup":
                handlePopupAction();
                break;
              case "navigate":
                handleNavigateAction();
                break;
              case "custom":
                await handleCustomAction();
                break;
              default:
                // console.log(`알 수 없는 액션 타입: ${actionType}`);
            }
          } catch (error) {
            // console.error(`버튼 액션 실행 오류 (${actionType}):`, error);
            alert(`작업 중 오류가 발생했습니다: ${error.message}`);
          }
        };

        // 저장 액션 (개선된 버전)
        const handleSaveAction = async () => {
          // console.log("💾 저장 시작");

          // ✅ 사용자 정보가 로드되지 않았으면 저장 불가
          if (!user?.userId) {
            alert("사용자 정보를 불러오는 중입니다. 잠시 후 다시 시도해주세요.");
            return;
          }

          // 개선된 검증 시스템이 활성화된 경우
          if (enhancedValidation) {
            // console.log("🔍 개선된 검증 시스템 사용");
            const success = await enhancedValidation.saveForm();
            if (success) {
              toast.success("데이터가 성공적으로 저장되었습니다!");
            }
            return;
          }

          // 기존 방식 (레거시 지원)
          const currentFormData = { ...localFormData, ...externalFormData };
          // console.log("💾 기존 방식으로 저장 - currentFormData:", currentFormData);
          
          // formData 유효성 체크를 완화 (빈 객체라도 위젯이 있으면 저장 진행)
          const hasWidgets = allComponents.some(comp => comp.type === 'widget');
          if (!hasWidgets) {
            alert("저장할 입력 컴포넌트가 없습니다.");
            return;
          }

          // 필수 항목 검증 (테이블 타입관리 NOT NULL 기반 + 기존 required 속성 폴백)
          const requiredFields = allComponents.filter(c => {
            const colName = c.columnName || c.id;
            return (c.required || isColumnRequired(colName)) && colName;
          });
          const missingFields = requiredFields.filter(field => {
            const fieldName = field.columnName || field.id;
            const value = currentFormData[fieldName];
            return !value || value.toString().trim() === "";
          });

          if (missingFields.length > 0) {
            const fieldNames = missingFields.map(f => f.label || f.columnName || f.id).join(", ");
            alert(`다음 필수 항목을 입력해주세요: ${fieldNames}`);
            return;
          }

          if (!screenInfo?.id) {
            alert("화면 정보가 없어 저장할 수 없습니다.");
            return;
          }

          try {
            // 컬럼명 기반으로 데이터 매핑
            const mappedData: Record<string, any> = {};
            
            // 입력 가능한 컴포넌트에서 데이터 수집
            allComponents.forEach(comp => {
              // 위젯 컴포넌트이고 입력 가능한 타입인 경우
              if (comp.type === 'widget') {
                const widget = comp as WidgetComponent;
                const fieldName = widget.columnName || widget.id;
                let value = currentFormData[fieldName];
                
                console.log(`🔍 컴포넌트 처리: ${fieldName}`, {
                  widgetType: widget.widgetType,
                  formDataValue: value,
                  hasWebTypeConfig: !!widget.webTypeConfig,
                  config: widget.webTypeConfig
                });
                
                // 자동입력 필드인 경우에만 값이 없을 때 생성
                if ((widget.widgetType === 'text' || widget.widgetType === 'email' || widget.widgetType === 'tel') && 
                    widget.webTypeConfig) {
                  const config = widget.webTypeConfig as TextTypeConfig;
                  const isAutoInput = config?.autoInput || false;
                  
                  console.log(`📋 ${fieldName} 자동입력 체크:`, {
                    isAutoInput,
                    autoValueType: config?.autoValueType,
                    hasValue: !!value,
                    value
                  });
                  
                  if (isAutoInput && config?.autoValueType && (!value || value === '')) {
                    // 자동입력이고 값이 없을 때만 생성
                    value = config.autoValueType === "custom" 
                      ? config.customValue || ""
                      : generateAutoValue(config.autoValueType);
                    
                    console.log("💾 자동입력 값 저장 (값이 없어서 생성):", {
                      fieldName,
                      autoValueType: config.autoValueType,
                      generatedValue: value
                    });
                  } else if (isAutoInput && value) {
                    console.log("💾 자동입력 필드지만 기존 값 유지:", {
                      fieldName,
                      existingValue: value
                    });
                  } else if (!isAutoInput) {
                    // console.log(`📝 일반 입력 필드: ${fieldName} = "${value}"`);
                  }
                }
                
                // 값이 있는 경우만 매핑 (빈 문자열도 포함하되, undefined는 제외)
                if (value !== undefined && value !== null && value !== "undefined") {
                  // columnName이 있으면 columnName을 키로, 없으면 컴포넌트 ID를 키로 사용
                  const saveKey = widget.columnName || `comp_${widget.id}`;
                  mappedData[saveKey] = value;
                } else if (widget.columnName) {
                  // 값이 없지만 columnName이 있는 경우, 빈 문자열로 저장
                  // console.log(`⚠️ ${widget.columnName} 필드에 값이 없어 빈 문자열로 저장`);
                  mappedData[widget.columnName] = "";
                }
              }
            });

            console.log("💾 저장할 데이터 매핑:", {
              원본데이터: currentFormData,
              매핑된데이터: mappedData,
              화면정보: screenInfo,
              전체컴포넌트수: allComponents.length,
              위젯컴포넌트수: allComponents.filter(c => c.type === 'widget').length,
            });

            // 각 컴포넌트의 상세 정보 로그
            // console.log("🔍 컴포넌트별 데이터 수집 상세:");
            allComponents.forEach(comp => {
              if (comp.type === 'widget') {
                const widget = comp as WidgetComponent;
                const fieldName = widget.columnName || widget.id;
                const value = currentFormData[fieldName];
                const hasValue = value !== undefined && value !== null && value !== '';
                // console.log(`  - ${fieldName} (${widget.widgetType}): "${value}" (값있음: ${hasValue}, 컬럼명: ${widget.columnName})`);
              }
            });
            
            // 매핑된 데이터가 비어있으면 경고
            if (Object.keys(mappedData).length === 0) {
              // console.warn("⚠️ 매핑된 데이터가 없습니다. 빈 데이터로 저장됩니다.");
            }

            // 테이블명 결정 (화면 정보에서 가져오거나 첫 번째 컴포넌트의 테이블명 사용)
            const tableName = screenInfo.tableName || 
                             allComponents.find(c => c.columnName)?.tableName ||
                             "dynamic_form_data"; // 기본값

            // 🆕 자동으로 작성자 정보 추가 (user.userId가 확실히 있음)
            const writerValue = user.userId;
            const companyCodeValue = user.companyCode || "";
            
            console.log("👤 현재 사용자 정보:", {
              userId: user.userId,
              userName: userName,
              companyCode: user.companyCode, // ✅ 회사 코드
              formDataWriter: mappedData.writer, // ✅ 폼에서 입력한 writer 값
              formDataCompanyCode: mappedData.company_code, // ✅ 폼에서 입력한 company_code 값
              defaultWriterValue: writerValue,
              companyCodeValue, // ✅ 최종 회사 코드 값
            });

            const dataWithUserInfo = {
              ...mappedData,
              writer: mappedData.writer || writerValue, // ✅ 입력값 우선, 없으면 userId
              created_by: writerValue, // created_by는 항상 로그인한 사람
              updated_by: writerValue, // updated_by는 항상 로그인한 사람
              company_code: mappedData.company_code || companyCodeValue, // ✅ 입력값 우선, 없으면 user.companyCode
            };

            // 🆕 리피터 데이터(배열)를 마스터 저장에서 제외 (V2Repeater가 별도로 저장)
            const masterDataWithUserInfo: Record<string, any> = {};
            Object.entries(dataWithUserInfo).forEach(([key, value]) => {
              if (!Array.isArray(value)) {
                masterDataWithUserInfo[key] = value;
              } else {
                console.log(`🔄 리피터 데이터 제외 (별도 저장): ${key}, ${value.length}개 항목`);
              }
            });

            const saveData: DynamicFormData = {
              screenId: screenInfo.id,
              tableName: tableName,
              data: masterDataWithUserInfo,
            };

            console.log("🚀 API 저장 요청:", saveData);

            const result = await dynamicFormApi.saveFormData(saveData);

            if (result.success) {
              const masterRecordId = result.data?.id || formData.id;
              
              // 🆕 리피터 데이터 저장 이벤트 발생 (V2Repeater 컴포넌트가 리스닝)
              window.dispatchEvent(
                new CustomEvent("repeaterSave", {
                  detail: { 
                    parentId: masterRecordId,
                    masterRecordId,
                    mainFormData: formData,
                    tableName: tableName,
                  },
                }),
              );
              console.log("📋 repeaterSave 이벤트 발생:", { masterRecordId, tableName });
              
              alert("저장되었습니다.");
              // console.log("✅ 저장 성공:", result.data);
              
              // 저장 후 데이터 초기화 (선택사항)
              if (onFormDataChange) {
                const resetData: Record<string, any> = {};
                Object.keys(formData).forEach(key => {
                  resetData[key] = "";
                });
                onFormDataChange(resetData);
              }
            } else {
              throw new Error(result.message || "저장에 실패했습니다.");
            }
          } catch (error: any) {
            // console.error("❌ 저장 실패:", error);
            alert(`저장 중 오류가 발생했습니다: ${error.message}`);
          }
        };


        // 삭제 액션
        const handleDeleteAction = async () => {
          const confirmMessage = config?.confirmMessage || "정말로 삭제하시겠습니까?";
          
          if (!confirm(confirmMessage)) {
            return;
          }

          // 삭제할 레코드 ID가 필요 (폼 데이터에서 id 필드 찾기)
          const recordId = formData["id"] || formData["ID"] || formData["objid"];
          
          if (!recordId) {
            alert("삭제할 데이터를 찾을 수 없습니다. (ID가 없음)");
            return;
          }

          // 테이블명 결정
          const tableName = screenInfo?.tableName || 
                           allComponents.find(c => c.columnName)?.tableName ||
                           "unknown_table";

          if (!tableName || tableName === "unknown_table") {
            alert("테이블 정보가 없어 삭제할 수 없습니다.");
            return;
          }

          try {
            // console.log("🗑️ 삭제 실행:", { recordId, tableName, formData });

            const result = await dynamicFormApi.deleteFormDataFromTable(recordId, tableName, screenInfo?.id);

            if (result.success) {
              alert("삭제되었습니다.");
              // console.log("✅ 삭제 성공");
              
              // 삭제 후 폼 초기화
              if (onFormDataChange) {
                const resetData: Record<string, any> = {};
                Object.keys(formData).forEach(key => {
                  resetData[key] = "";
                });
                onFormDataChange(resetData);
              }
            } else {
              throw new Error(result.message || "삭제에 실패했습니다.");
            }
          } catch (error: any) {
            // console.error("❌ 삭제 실패:", error);
            alert(`삭제 중 오류가 발생했습니다: ${error.message}`);
          }
        };

        // 편집 액션
        const handleEditAction = () => {
          console.log("✏️ 수정 액션 실행");
          
          // 버튼 컴포넌트의 수정 모달 설정 가져오기
          const editModalTitle = config?.editModalTitle || "";
          const editModalDescription = config?.editModalDescription || "";
          
          console.log("📝 버튼 수정 모달 설정:", { editModalTitle, editModalDescription });
          
          // EditModal 열기 이벤트 발생
          const event = new CustomEvent("openEditModal", {
            detail: {
              screenId: screenInfo?.id,
              modalSize: "lg",
              editData: formData,
              modalTitle: editModalTitle,
              modalDescription: editModalDescription,
              onSave: () => {
                console.log("✅ 수정 완료");
                // 필요시 폼 새로고침 또는 콜백 실행
              },
            },
          });
          window.dispatchEvent(event);
        };

        // 추가 액션
        const handleAddAction = () => {
          // console.log("➕ 새 항목 추가");
          // 새 항목 추가 로직
          alert("새 항목을 추가할 수 있습니다.");
        };

        // 검색 액션
        const handleSearchAction = () => {
          // console.log("🔍 검색 실행:", formData);
          // 검색 로직
          const searchTerms = Object.values(formData).filter(v => v && v.toString().trim());
          if (searchTerms.length === 0) {
            alert("검색할 내용을 입력해주세요.");
          } else {
            alert(`검색 실행: ${searchTerms.join(", ")}`);
          }
        };

        // 초기화 액션
        const handleResetAction = () => {
          if (confirm("모든 입력을 초기화하시겠습니까?")) {
            if (onFormDataChange) {
              const resetData: Record<string, any> = {};
              Object.keys(formData).forEach(key => {
                resetData[key] = "";
              });
              onFormDataChange(resetData);
            }
            // console.log("🔄 폼 초기화 완료");
            alert("입력이 초기화되었습니다.");
          }
        };

        // 제출 액션
        const handleSubmitAction = async () => {
          // console.log("📤 폼 제출:", formData);
          // 제출 로직
          alert("제출되었습니다.");
        };

        // 닫기 액션
        const handleCloseAction = () => {
          // console.log("❌ 닫기 액션 실행");
          
          // 모달 내부에서 실행되는지 확인
          const isInModal = document.querySelector('[role="dialog"]') !== null;
          const isInPopup = window.opener !== null;
          
          if (isInModal) {
            // 모달 내부인 경우: 모달의 닫기 버튼 클릭하거나 모달 닫기 이벤트 발생
            // console.log("🔄 모달 내부에서 닫기 - 모달 닫기 시도");
            
            // 모달의 닫기 버튼을 찾아서 클릭
            const modalCloseButton = document.querySelector('[role="dialog"] button[aria-label*="Close"], [role="dialog"] button[data-dismiss="modal"], [role="dialog"] .dialog-close');
            if (modalCloseButton) {
              (modalCloseButton as HTMLElement).click();
            } else {
              // ESC 키 이벤트 발생시키기
              const escEvent = new KeyboardEvent('keydown', { key: 'Escape', keyCode: 27, which: 27 });
              document.dispatchEvent(escEvent);
            }
          } else if (isInPopup) {
            // 팝업 창인 경우
            // console.log("🔄 팝업 창 닫기");
            window.close();
          } else {
            // 일반 페이지인 경우 - 이전 페이지로 이동하지 않고 아무것도 하지 않음
            // console.log("🔄 일반 페이지에서 닫기 - 아무 동작 하지 않음");
            alert("닫기 버튼이 클릭되었습니다.");
          }
        };

        // 팝업 액션
        const handlePopupAction = () => {
          // console.log("🎯 팝업 액션 실행:", { popupScreenId: config?.popupScreenId });
          
          if (config?.popupScreenId) {
            // 화면 모달 열기
            setPopupScreen({
              screenId: config.popupScreenId,
              title: config.popupTitle || "상세 정보",
              size: "lg",
            });
          } else if (config?.popupTitle && config?.popupContent) {
            // 텍스트 모달 표시
            alert(`${config.popupTitle}\n\n${config.popupContent}`);
          } else {
            alert("모달을 표시합니다.");
          }
        };

        // 네비게이션 액션
        const handleNavigateAction = () => {
          const navigateType = config?.navigateType || "url";
          
          if (navigateType === "screen" && config?.navigateScreenId) {
            // 화면으로 이동
            const screenPath = `/screens/${config.navigateScreenId}`;
            
            console.log("🎯 화면으로 이동:", {
              screenId: config.navigateScreenId,
              target: config.navigateTarget || "_self",
              path: screenPath
            });
            
            if (config.navigateTarget === "_blank") {
              window.open(screenPath, "_blank");
            } else {
              window.location.href = screenPath;
            }
          } else if (navigateType === "url" && config?.navigateUrl) {
            // URL로 이동
            console.log("🔗 URL로 이동:", {
              url: config.navigateUrl,
              target: config.navigateTarget || "_self"
            });
            
            if (config.navigateTarget === "_blank") {
              window.open(config.navigateUrl, "_blank");
            } else {
              window.location.href = config.navigateUrl;
            }
          } else {
            console.log("🔗 네비게이션 정보가 설정되지 않았습니다:", {
              navigateType,
              hasUrl: !!config?.navigateUrl,
              hasScreenId: !!config?.navigateScreenId
            });
          }
        };

        // 커스텀 액션
        const handleCustomAction = async () => {
          if (config?.customAction) {
            try {
              // 보안상 제한적인 eval 사용
              const result = eval(config.customAction);
              if (result instanceof Promise) {
                await result;
              }
              // console.log("⚡ 커스텀 액션 실행 완료");
            } catch (error) {
              throw new Error(`커스텀 액션 실행 실패: ${error.message}`);
            }
          } else {
            // console.log("⚡ 커스텀 액션이 설정되지 않았습니다.");
          }
        };

        // 커스텀 색상이 있으면 Tailwind 클래스 대신 직접 스타일 적용
        const hasCustomColors = config?.backgroundColor || config?.textColor;
        
        return applyStyles(
          <button
            onClick={handleButtonClick}
            disabled={isReadonly}
            className={`w-full rounded-md px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ${
              hasCustomColors
                ? ""
                : "bg-background border border-foreground text-foreground shadow-xs hover:bg-muted/50"
            }`}
            style={{
              height: "100%",
              backgroundColor: config?.backgroundColor,
              color: config?.textColor,
              borderColor: config?.borderColor,
            }}
          >
            <ButtonIconRenderer componentConfig={(component as any).componentConfig} fallbackLabel={label || "버튼"} />
          </button>
        );
      }

      default:
        return applyStyles(
          <Input
            type="text"
            placeholder={placeholder || "입력하세요..."}
            value={currentValue}
            onChange={(e) => updateFormData(fieldName, e.target.value)}
            disabled={isReadonly}
            required={required}
            className="w-full"
            style={{ height: "100%" }}
          />,
        );
    }
  };

  // 파일 첨부 컴포넌트 처리
  if (isFileComponent(component)) {
    const fileComponent = component as FileComponent;
    
    console.log("🎯 File 컴포넌트 렌더링:", {
      componentId: fileComponent.id,
      currentUploadedFiles: fileComponent.uploadedFiles?.length || 0,
      hasOnFormDataChange: !!onFormDataChange,
      userInfo: user ? { userId: user.userId, companyCode: user.companyCode } : "no user"
    });
    
    const handleFileUpdate = useCallback(async (updates: Partial<FileComponent>) => {
      // 실제 화면에서는 파일 업데이트를 처리
      console.log("📎 InteractiveScreenViewer - 파일 컴포넌트 업데이트:", {
        updates,
        hasUploadedFiles: !!updates.uploadedFiles,
        uploadedFilesCount: updates.uploadedFiles?.length || 0,
        hasOnFormDataChange: !!onFormDataChange
      });
      
      if (updates.uploadedFiles && onFormDataChange) {
        const fieldName = fileComponent.columnName || fileComponent.id;
        
        // attach_file_info 테이블 구조에 맞는 데이터 생성
        const fileInfoForDB = updates.uploadedFiles.map(file => ({
          objid: file.objid.replace('temp_', ''), // temp_ 제거
          target_objid: "",
          saved_file_name: file.savedFileName,
          real_file_name: file.realFileName,
          doc_type: file.docType,
          doc_type_name: file.docTypeName,
          file_size: file.fileSize,
          file_ext: file.fileExt,
          file_path: file.filePath,
          writer: file.writer,
          regdate: file.regdate,
          status: file.status,
          parent_target_objid: "",
          company_code: file.companyCode
        }));

        // console.log("💾 attach_file_info 형태로 변환된 데이터:", fileInfoForDB);

        // FormData에는 파일 연결 정보만 저장 (간단한 형태)
        const formDataValue = {
          fileCount: updates.uploadedFiles.length,
          docType: fileComponent.fileConfig.docType,
          files: updates.uploadedFiles.map(file => ({
            objid: file.objid,
            realFileName: file.realFileName,
            fileSize: file.fileSize,
            status: file.status
          }))
        };

        // console.log("📝 FormData 저장값:", { fieldName, formDataValue });
        onFormDataChange(fieldName, formDataValue);

        // TODO: 실제 API 연동 시 attach_file_info 테이블에 저장
        // await saveFilesToDatabase(fileInfoForDB);
        
      } else {
        console.warn("⚠️ 파일 업데이트 실패:", {
          hasUploadedFiles: !!updates.uploadedFiles,
          hasOnFormDataChange: !!onFormDataChange
        });
      }
    }, [fileComponent, onFormDataChange]);

    return (
      <div className="h-full w-full">
        <FileUpload
          component={fileComponent}
          onUpdateComponent={handleFileUpdate}
          userInfo={user} // 사용자 정보를 프롭으로 전달
        />
      </div>
    );
  }

  // 그룹 컴포넌트 처리
  if (component.type === "group") {
    const children = allComponents.filter((comp) => comp.parentId === component.id);

    return (
      <div className="relative h-full w-full">
        {/* 그룹 내의 자식 컴포넌트들 렌더링 */}
        {children.map((child) => (
          <div
            key={child.id}
            style={{
              position: "absolute",
              left: `${child.position.x - component.position.x}px`,
              top: `${child.position.y - component.position.y}px`,
              width: child.style?.width || `${child.size.width}px`,
              height: child.style?.height || `${child.size.height}px`,
              zIndex: child.position.z || 1,
            }}
          >
            <InteractiveScreenViewer
              component={child}
              allComponents={allComponents}
              formData={externalFormData}
              onFormDataChange={onFormDataChange}
            />
          </div>
        ))}
      </div>
    );
  }

  // 일반 위젯 컴포넌트
  // 템플릿 컴포넌트 목록 (자체적으로 제목을 가지므로 라벨 불필요)
  const templateTypes = ["datatable"];

  // 라벨 표시 여부 계산
  const shouldShowLabel =
    !hideLabel &&
    (component.style?.labelDisplay ?? true) !== false &&
    component.style?.labelDisplay !== "false" &&
    (component.label || component.style?.labelText) &&
    !templateTypes.includes(component.type);

  const labelText = component.style?.labelText || component.label || "";

  // 라벨 표시 여부 로그 (디버깅용)
  if (component.type === "widget") {
    console.log("🏷️ 라벨 표시 체크:", {
      componentId: component.id,
      hideLabel,
      shouldShowLabel,
      labelText,
    });
  }

  // 라벨 위치 및 스타일
  const labelPosition = component.style?.labelPosition || "top";
  const isHorizontalLabel = labelPosition === "left" || labelPosition === "right";
  const labelGap = component.style?.labelGap || "8px";

  const labelStyle: React.CSSProperties = {
    fontSize: component.style?.labelFontSize || "14px",
    color: component.style?.labelColor || "hsl(var(--foreground))",
    fontWeight: component.style?.labelFontWeight || "500",
    backgroundColor: component.style?.labelBackgroundColor || "transparent",
    padding: component.style?.labelPadding || "0",
    borderRadius: component.style?.labelBorderRadius || "0",
    ...(isHorizontalLabel
      ? { whiteSpace: "nowrap" as const, display: "flex", alignItems: "center" }
      : { marginBottom: component.style?.labelMarginBottom || "4px" }),
  };


  // 상위에서 라벨을 표시한 경우, 컴포넌트 내부에서는 라벨을 숨김
  const componentForRendering = shouldShowLabel
    ? {
        ...component,
        style: {
          ...component.style,
          labelDisplay: false,
          labelPosition: "top" as const,
          ...(isHorizontalLabel ? { width: "100%", height: "100%" } : {}),
        },
        ...(isHorizontalLabel ? {
          size: {
            ...component.size,
            width: undefined as unknown as number,
            height: undefined as unknown as number,
          },
        } : {}),
      }
    : component;

  // 모든 레이어의 컴포넌트 통합 (조건 평가용 - 트리거 컴포넌트 검색에 필요)
  const allLayerComponents = useMemo(() => {
    return layers.flatMap((layer) => layer.components);
  }, [layers]);

  // 🔧 활성 레이어 컴포넌트만 통합 (저장/데이터 수집용)
  // 기본 레이어(base) + 현재 활성화된 조건부 레이어만 포함
  // 비활성 레이어의 중복 columnName 컴포넌트가 저장 데이터를 오염시키는 문제 해결
  const visibleLayerComponents = useMemo(() => {
    return layers
      .filter((layer) => layer.type === "base" || activeLayerIds.includes(layer.id))
      .flatMap((layer) => layer.components);
  }, [layers, activeLayerIds]);

  // 🆕 레이어별 컴포넌트 렌더링 함수
  const renderLayerComponents = useCallback((layer: LayerDefinition) => {
    // 활성화되지 않은 레이어는 렌더링하지 않음
    if (!activeLayerIds.includes(layer.id)) return null;

    // 모달 레이어 처리
    if (layer.type === "modal") {
      const modalStyle: React.CSSProperties = {
        ...(layer.overlayConfig?.backgroundColor && { backgroundColor: layer.overlayConfig.backgroundColor }),
        ...(layer.overlayConfig?.backdropBlur && { backdropFilter: `blur(${layer.overlayConfig.backdropBlur}px)` }),
      };

      return (
        <Dialog key={layer.id} open={true} onOpenChange={() => handleLayerAction("hide", layer.id)}>
          <DialogContent 
            className="max-w-4xl max-h-[90vh] overflow-hidden" 
            style={modalStyle}
          >
            <DialogHeader>
              <DialogTitle>{layer.name}</DialogTitle>
            </DialogHeader>
            <div className="relative h-full w-full min-h-[300px]">
              {layer.components.map((comp) => (
                <div
                  key={comp.id}
                  className="absolute"
                  style={{
                    left: `${comp.position.x}px`,
                    top: `${comp.position.y}px`,
                    width: comp.style?.width || `${comp.size.width}px`,
                    height: comp.style?.height || `${comp.size.height}px`,
                    zIndex: comp.position.z || 1,
                  }}
                >
                  <InteractiveScreenViewer
                    component={comp}
                    allComponents={visibleLayerComponents}
                    formData={externalFormData}
                    onFormDataChange={onFormDataChange}
                    screenInfo={screenInfo}
                  />
                </div>
              ))}
            </div>
          </DialogContent>
        </Dialog>
      );
    }

    // 드로어 레이어 처리
    if (layer.type === "drawer") {
      const drawerPosition = layer.overlayConfig?.position || "right";
      const drawerWidth = layer.overlayConfig?.width || "400px";
      const drawerHeight = layer.overlayConfig?.height || "100%";

      const drawerPositionStyles: Record<string, React.CSSProperties> = {
        right: { right: 0, top: 0, width: drawerWidth, height: "100%" },
        left: { left: 0, top: 0, width: drawerWidth, height: "100%" },
        bottom: { bottom: 0, left: 0, width: "100%", height: drawerHeight },
        top: { top: 0, left: 0, width: "100%", height: drawerHeight },
      };

      return (
        <div
          key={layer.id}
          className="fixed inset-0 z-50"
          onClick={() => handleLayerAction("hide", layer.id)}
        >
          {/* 백드롭 */}
          <div 
            className="absolute inset-0 bg-black/50"
            style={{
              ...(layer.overlayConfig?.backdropBlur && { 
                backdropFilter: `blur(${layer.overlayConfig.backdropBlur}px)` 
              }),
            }}
          />
          {/* 드로어 패널 */}
          <div
            className="absolute bg-background shadow-lg"
            style={drawerPositionStyles[drawerPosition]}
            onClick={(e) => e.stopPropagation()}
          >
            <div className="flex items-center justify-between border-b p-4">
              <h3 className="text-lg font-semibold">{layer.name}</h3>
              <Button
                variant="ghost"
                size="icon"
                onClick={() => handleLayerAction("hide", layer.id)}
              >
                <X className="h-4 w-4" />
              </Button>
            </div>
            <div className="relative h-full overflow-auto p-4">
              {layer.components.map((comp) => (
                <div
                  key={comp.id}
                  className="absolute"
                  style={{
                    left: `${comp.position.x}px`,
                    top: `${comp.position.y}px`,
                    width: comp.style?.width || `${comp.size.width}px`,
                    height: comp.style?.height || `${comp.size.height}px`,
                    zIndex: comp.position.z || 1,
                  }}
                >
                  <InteractiveScreenViewer
                    component={comp}
                    allComponents={visibleLayerComponents}
                    formData={externalFormData}
                    onFormDataChange={onFormDataChange}
                    screenInfo={screenInfo}
                  />
                </div>
              ))}
            </div>
          </div>
        </div>
      );
    }

    // 조건부 레이어: Zone 기반 영역 내에 컴포넌트 렌더링
    if (layer.type === "conditional" && layer.displayRegion) {
      const region = layer.displayRegion;
      return (
        <div
          key={layer.id}
          className="pointer-events-none absolute"
          style={{
            left: `${region.x}px`,
            top: `${region.y}px`,
            width: `${region.width}px`,
            height: `${region.height}px`,
            zIndex: layer.zIndex,
            overflow: "hidden",
          }}
        >
          {layer.components.map((comp) => (
            <div
              key={comp.id}
              className="pointer-events-auto absolute"
              style={{
                left: `${comp.position.x}px`,
                top: `${comp.position.y}px`,
                width: comp.style?.width || `${comp.size.width}px`,
                height: comp.style?.height || `${comp.size.height}px`,
                zIndex: comp.position.z || 1,
              }}
            >
              <InteractiveScreenViewer
                component={comp}
                allComponents={visibleLayerComponents}
                formData={externalFormData}
                onFormDataChange={onFormDataChange}
                screenInfo={screenInfo}
              />
            </div>
          ))}
        </div>
      );
    }

    // 기본/기타 레이어 (base)
    return (
      <div
        key={layer.id}
        className="pointer-events-none absolute inset-0"
        style={{ zIndex: layer.zIndex }}
      >
        {layer.components.map((comp) => {
          const yOffset = layer.type === "base" ? calculateYOffset(comp.position.y) : 0;
          const adjustedY = comp.position.y - yOffset;

          return (
            <div
              key={comp.id}
              className="pointer-events-auto absolute"
              style={{
                left: `${comp.position.x}px`,
                top: `${adjustedY}px`,
                width: comp.style?.width || `${comp.size.width}px`,
                height: comp.style?.height || `${comp.size.height}px`,
                zIndex: comp.position.z || 1,
              }}
            >
              <InteractiveScreenViewer
                component={comp}
                allComponents={visibleLayerComponents}
                formData={externalFormData}
                onFormDataChange={onFormDataChange}
                screenInfo={screenInfo}
              />
            </div>
          );
        })}
      </div>
    );
  }, [activeLayerIds, handleLayerAction, externalFormData, onFormDataChange, screenInfo, calculateYOffset, visibleLayerComponents, layers]);

  return (
    <SplitPanelProvider>
      <ActiveTabProvider>
        <TableOptionsProvider>
        <div className="flex h-full flex-col">
          {/* 테이블 옵션 툴바 */}
          <TableOptionsToolbar />
          
          {/* 메인 컨텐츠 - 라벨 위치에 따라 flex 방향 변경 */}
          <div
            className="h-full flex-1"
            style={{
              width: '100%',
              ...(shouldShowLabel && isHorizontalLabel
                ? { display: 'flex', flexDirection: labelPosition === 'left' ? 'row' : 'row-reverse', alignItems: 'center', gap: labelGap }
                : {}),
            }}
          >
            {/* 라벨: top 또는 left일 때 위젯보다 먼저 렌더링 */}
            {shouldShowLabel && (labelPosition === "top" || labelPosition === "left") && (
              <label
                className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
                style={labelStyle}
              >
                {labelText}
                {(component.required || component.componentConfig?.required || isColumnRequired(component.columnName || component.style?.columnName || "")) && <span className="ml-1 text-destructive">*</span>}
              </label>
            )}

            {/* 실제 위젯 */}
            <div className="h-full" style={{ width: '100%', height: '100%', ...(isHorizontalLabel ? { flex: 1, minWidth: 0 } : {}) }}>
              {renderInteractiveWidget(componentForRendering)}
            </div>

            {/* 라벨: bottom 또는 right일 때 위젯 뒤에 렌더링 */}
            {shouldShowLabel && (labelPosition === "bottom" || labelPosition === "right") && (
              <label
                className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
                style={{
                  ...labelStyle,
                  ...(labelPosition === "bottom" ? { marginBottom: 0, marginTop: component.style?.labelMarginBottom || "4px" } : {}),
                }}
              >
                {labelText}
                {(component.required || component.componentConfig?.required || isColumnRequired(component.columnName || component.style?.columnName || "")) && <span className="ml-1 text-destructive">*</span>}
              </label>
            )}
          </div>
        </div>

        {/* 🆕 레이어 렌더링 */}
        {layers.length > 0 && layers.map(renderLayerComponents)}

        {/* 개선된 검증 패널 (선택적 표시) */}
        {showValidationPanel && enhancedValidation && (
          <div className="absolute bottom-4 right-4 z-50">
            <FormValidationIndicator
              validationState={enhancedValidation.validationState}
              saveState={enhancedValidation.saveState}
              onSave={async () => {
                const success = await enhancedValidation.saveForm();
                if (success) {
                  toast.success("데이터가 성공적으로 저장되었습니다!");
                }
              }}
              canSave={enhancedValidation.canSave}
              compact={true}
              showDetails={false}
            />
          </div>
        )}

        {/* 모달 화면 */}
        <Dialog open={!!popupScreen} onOpenChange={() => {
          setPopupScreen(null);
          setPopupFormData({}); // 팝업 닫을 때 formData도 초기화
        }}>
          <DialogContent 
            className="max-w-none w-auto max-h-[90vh] overflow-hidden p-0"
            style={popupScreenResolution ? { 
              width: `${Math.min(popupScreenResolution.width + 48, window.innerWidth * 0.98)}px`,
              maxWidth: "98vw",
            } : { maxWidth: "56rem" }}
          >
            <DialogHeader className="px-6 pt-4 pb-2">
              <DialogTitle>{popupScreen?.title || "상세 정보"}</DialogTitle>
            </DialogHeader>
            
            <div className="overflow-y-auto px-6 pb-6" style={{ maxHeight: "calc(90vh - 80px)" }}>
              {popupLoading ? (
                <div className="flex items-center justify-center py-8">
                  <div className="text-muted-foreground">화면을 불러오는 중...</div>
                </div>
              ) : popupLayout.length > 0 ? (
                <div className="relative bg-background border rounded" style={{ 
                  width: popupScreenResolution ? `${popupScreenResolution.width}px` : "100%", 
                  height: popupScreenResolution ? `${popupScreenResolution.height}px` : "400px",
                  minHeight: "400px",
                  position: "relative",
                  overflow: "hidden"
                }}>
                  {/* 팝업에서도 실제 위치와 크기로 렌더링 */}
                  {popupLayout.map((popupComponent) => (
                    <div
                      key={popupComponent.id}
                      className="absolute"
                      style={{
                        left: `${popupComponent.position.x}px`,
                        top: `${popupComponent.position.y}px`,
                        width: popupComponent.style?.width || `${popupComponent.size.width}px`,
                        height: popupComponent.style?.height || `${popupComponent.size.height}px`,
                        zIndex: Math.min(popupComponent.position.z || 1, 20), // 최대 z-index 20으로 제한
                      }}
                    >
                      {/* 🎯 핵심 수정: 팝업 전용 formData 사용 */}
                      <InteractiveScreenViewer
                        component={popupComponent}
                        allComponents={popupLayout}
                        hideLabel={false}
                        screenInfo={popupScreenInfo || undefined}
                        formData={popupFormData}
                        onFormDataChange={(fieldName, value) => {
                          console.log("💾 팝업 formData 업데이트:", {
                            fieldName,
                            value,
                            valueType: typeof value,
                            prevFormData: popupFormData
                          });
                          
                          setPopupFormData(prev => ({ 
                            ...prev, 
                            [fieldName]: value 
                          }));
                        }}
                      />
                    </div>
                  ))}
                </div>
              ) : (
                <div className="flex items-center justify-center py-8">
                  <div className="text-muted-foreground">화면 데이터가 없습니다.</div>
                </div>
              )}
            </div>
          </DialogContent>
        </Dialog>
        </TableOptionsProvider>
      </ActiveTabProvider>
    </SplitPanelProvider>
  );
};
