"use client";

import React, { useState, useEffect, useRef, useCallback, useMemo } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
import {
  AlertDialog,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogCancel,
  AlertDialogAction,
} from "@/components/ui/alert-dialog";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { InteractiveScreenViewerDynamic } from "@/components/screen/InteractiveScreenViewerDynamic";
import { screenApi } from "@/lib/api/screen";
import { ComponentData } from "@/types/screen";
import { toast } from "sonner";
import { showErrorToast } from "@/lib/utils/toastUtils";
import { useAuth } from "@/hooks/useAuth";
import { TableOptionsProvider } from "@/contexts/TableOptionsContext";
import { TableSearchWidgetHeightProvider } from "@/contexts/TableSearchWidgetHeightContext";
import { useSplitPanelContext } from "@/contexts/SplitPanelContext";
import { ActiveTabProvider } from "@/contexts/ActiveTabContext";
import { convertV2ToLegacy, isValidV2Layout } from "@/lib/utils/layoutV2Converter";
import { ConditionalZone, LayerDefinition } from "@/types/screen-management";
import { ScreenContextProvider } from "@/contexts/ScreenContext";
import { useTabStore } from "@/stores/tabStore";
import { useTabId } from "@/contexts/TabIdContext";

interface ScreenModalState {
  isOpen: boolean;
  screenId: number | null;
  title: string;
  description?: string;
  size: "sm" | "md" | "lg" | "xl";
}

interface ScreenModalProps {
  className?: string;
}

export const ScreenModal: React.FC<ScreenModalProps> = ({ className }) => {
  const { userId, userName, user } = useAuth();
  const splitPanelContext = useSplitPanelContext();
  const tabId = useTabId();
  const activeTabId = useTabStore((s) => s[s.mode].activeTabId);

  const [modalState, setModalState] = useState<ScreenModalState>({
    isOpen: false,
    screenId: null,
    title: "",
    description: "",
    size: "md",
  });

  const [screenData, setScreenData] = useState<{
    components: ComponentData[];
    screenInfo: any;
  } | null>(null);

  const [loading, setLoading] = useState(false);
  const [screenDimensions, setScreenDimensions] = useState<{
    width: number;
    height: number;
    offsetX?: number;
    offsetY?: number;
  } | null>(null);

  // 폼 데이터 상태 추가
  const [formData, setFormData] = useState<Record<string, any>>({});

  // 🆕 원본 데이터 상태 (수정 모드에서 UPDATE 판단용)
  const [originalData, setOriginalData] = useState<Record<string, any> | null>(null);

  // 🆕 선택된 데이터 상태 (RepeatScreenModal 등에서 사용)
  const [selectedData, setSelectedData] = useState<Record<string, any>[]>([]);

  // 🆕 조건부 레이어 상태 (Zone 기반)
  const [conditionalLayers, setConditionalLayers] = useState<(LayerDefinition & { components: ComponentData[]; zone?: ConditionalZone })[]>([]);

  // 연속 등록 모드 상태 (state로 변경 - 체크박스 UI 업데이트를 위해)
  const [continuousMode, setContinuousMode] = useState(false);

  // 화면 리셋 키 (컴포넌트 강제 리마운트용)
  const [resetKey, setResetKey] = useState(0);

  // 모달 닫기 확인 다이얼로그 표시 상태
  const [showCloseConfirm, setShowCloseConfirm] = useState(false);

  // 사용자가 폼 데이터를 실제로 변경했는지 추적 (변경 없으면 경고 없이 바로 닫기)
  const formDataChangedRef = useRef(false);

  // localStorage에서 연속 모드 상태 복원
  useEffect(() => {
    const savedMode = localStorage.getItem("screenModal_continuousMode");
    if (savedMode === "true") {
      setContinuousMode(true);
      // console.log("🔄 연속 모드 복원: true");
    }
  }, []);

  // 화면의 실제 크기 계산 함수
  const calculateScreenDimensions = (components: ComponentData[]) => {
    if (components.length === 0) {
      return {
        width: 400,
        height: 300,
        offsetX: 0,
        offsetY: 0,
      };
    }

    // 모든 컴포넌트의 경계 찾기
    let minX = Infinity;
    let minY = Infinity;
    let maxX = -Infinity;
    let maxY = -Infinity;

    components.forEach((component) => {
      const x = parseFloat(component.position?.x?.toString() || "0");
      const y = parseFloat(component.position?.y?.toString() || "0");
      const width = parseFloat(component.size?.width?.toString() || "100");
      const height = parseFloat(component.size?.height?.toString() || "40");

      minX = Math.min(minX, x);
      minY = Math.min(minY, y);
      maxX = Math.max(maxX, x + width);
      maxY = Math.max(maxY, y + height);
    });

    // 실제 컨텐츠 크기 계산
    const contentWidth = maxX - minX;
    const contentHeight = maxY - minY;

    // 여백 없이 컨텐츠 크기 그대로 사용
    const paddingX = 0;
    const paddingY = 0;

    const finalWidth = Math.max(contentWidth + paddingX, 400);
    const finalHeight = Math.max(contentHeight + paddingY, 300);

    return {
      width: Math.min(finalWidth, window.innerWidth * 0.95),
      height: Math.min(finalHeight, window.innerHeight * 0.9),
      offsetX: Math.max(0, minX), // 여백 없이 컨텐츠 시작점 기준
      offsetY: Math.max(0, minY), // 여백 없이 컨텐츠 시작점 기준
    };
  };

  // 모달이 열린 시간 추적 (저장 성공 이벤트 무시용)
  const modalOpenedAtRef = React.useRef<number>(0);

  // 🆕 채번 필드 수동 입력 값 변경 이벤트 리스너
  useEffect(() => {
    const handleNumberingValueChanged = (event: CustomEvent) => {
      const { columnName, value } = event.detail;
      if (columnName && modalState.isOpen) {
        setFormData((prev) => ({
          ...prev,
          [columnName]: value,
        }));
      }
    };

    window.addEventListener("numberingValueChanged", handleNumberingValueChanged as EventListener);
    return () => {
      window.removeEventListener("numberingValueChanged", handleNumberingValueChanged as EventListener);
    };
  }, [modalState.isOpen]);

  // 전역 모달 이벤트 리스너
  useEffect(() => {
    const handleOpenModal = (event: CustomEvent) => {
      // 활성 탭에서만 이벤트 처리 (다른 탭의 ScreenModal 인스턴스는 무시)
      const storeState = useTabStore.getState();
      const currentActiveTabId = storeState[storeState.mode].activeTabId;
      if (tabId && tabId !== currentActiveTabId) return;

      const {
        screenId,
        title,
        description,
        size,
        urlParams,
        editData,
        splitPanelParentData,
        selectedData: eventSelectedData,
        selectedIds,
        isCreateMode,
        fieldMappings,
      } = event.detail;

      console.log("🟣 [ScreenModal] openScreenModal 이벤트 수신:", {
        screenId,
        splitPanelParentData: JSON.stringify(splitPanelParentData),
        editData: !!editData,
        isCreateMode,
      });

      // 모달 열린 시간 기록
      modalOpenedAtRef.current = Date.now();

      // 폼 변경 추적 초기화
      formDataChangedRef.current = false;

      // 🆕 선택된 데이터 저장 (RepeatScreenModal 등에서 사용)
      if (eventSelectedData && Array.isArray(eventSelectedData)) {
        setSelectedData(eventSelectedData);
      } else {
        setSelectedData([]);
      }

      // 🆕 URL 파라미터가 있으면 현재 URL에 추가
      if (urlParams && typeof window !== "undefined") {
        const currentUrl = new URL(window.location.href);
        Object.entries(urlParams).forEach(([key, value]) => {
          currentUrl.searchParams.set(key, String(value));
        });
        // pushState로 URL 변경 (페이지 새로고침 없이)
        window.history.pushState({}, "", currentUrl.toString());
      }

      // 🆕 editData가 있으면 formData와 originalData로 설정 (수정 모드)
      // 🔧 단, isCreateMode가 true이면 (복사 모드) originalData를 설정하지 않음 → 채번 생성 가능
      if (editData && !isCreateMode) {
        // 🆕 배열인 경우 두 가지 데이터를 설정:
        // 1. formData: 첫 번째 요소(객체) - 일반 입력 필드용 (TextInput 등)
        // 2. selectedData: 전체 배열 - 다중 항목 컴포넌트용 (SelectedItemsDetailInput 등)
        if (Array.isArray(editData)) {
          const firstRecord = editData[0] || {};
          setFormData(firstRecord); // 🔧 일반 입력 필드용 (객체)
          setSelectedData(editData); // 🔧 다중 항목 컴포넌트용 (배열) - groupedData로 전달됨
          setOriginalData(firstRecord); // 첫 번째 레코드를 원본으로 저장
        } else {
          setFormData(editData);
          setSelectedData([editData]); // 🔧 단일 객체도 배열로 변환하여 저장
          setOriginalData(editData); // 🆕 원본 데이터 저장 (UPDATE 판단용)
        }
      } else if (editData && isCreateMode) {
        // 🆕 복사 모드: formData만 설정하고 originalData는 null로 유지 (채번 생성 가능)
        if (Array.isArray(editData)) {
          const firstRecord = editData[0] || {};
          setFormData(firstRecord);
          setSelectedData(editData);
        } else {
          setFormData(editData);
          setSelectedData([editData]);
        }
        setOriginalData(null); // 🔧 복사 모드에서는 originalData를 null로 설정
      } else {
        // 🆕 신규 등록 모드: 분할 패널 부모 데이터가 있으면 미리 설정
        // 🔧 중요: 신규 등록 시에는 연결 필드(equipment_code 등)만 전달해야 함
        // 모든 필드를 전달하면 동일한 컬럼명이 있을 때 부모 값이 들어가는 문제 발생
        // 예: 설비의 manufacturer가 소모품의 manufacturer로 들어감

        // parentDataMapping에서 명시된 필드만 추출
        const parentDataMapping = splitPanelContext?.parentDataMapping || [];

        // 부모 데이터 소스
        // 🔧 수정: 여러 소스를 병합 (우선순위: splitPanelParentData > selectedLeftData > 기존 formData의 링크 필드)
        // 예: screen 150→226→227 전환 시:
        //   - splitPanelParentData: item_info 데이터 (screen 226에서 전달)
        //   - selectedLeftData: customer_mng 데이터 (SplitPanel 좌측 선택)
        //   - 기존 formData: 이전 모달에서 설정된 link 필드 (customer_code 등)
        const contextData = splitPanelContext?.selectedLeftData || {};
        const eventData = splitPanelParentData && Object.keys(splitPanelParentData).length > 0
          ? splitPanelParentData
          : {};
        
        // 🆕 기존 formData에서 link 필드(_code, _id)를 가져와 base로 사용
        // 모달 체인(226→227)에서 이전 모달의 연결 필드가 유지됨
        const previousLinkFields: Record<string, any> = {};
        if (formData && typeof formData === "object" && !Array.isArray(formData)) {
          const linkFieldPatterns = ["_code", "_id"];
          const excludeFields = ["id", "created_date", "updated_date", "created_at", "updated_at", "writer"];
          for (const [key, value] of Object.entries(formData)) {
            if (excludeFields.includes(key)) continue;
            if (value === undefined || value === null) continue;
            const isLinkField = linkFieldPatterns.some((pattern) => key.endsWith(pattern));
            if (isLinkField) {
              previousLinkFields[key] = value;
            }
          }
        }
        
        const rawParentData = { ...previousLinkFields, ...contextData, ...eventData };

        // 🔧 신규 등록 모드에서는 연결에 필요한 필드만 전달
        const parentData: Record<string, any> = {};

        // 필수 연결 필드: company_code (멀티테넌시)
        if (rawParentData.company_code) {
          parentData.company_code = rawParentData.company_code;
        }

        // 🆕 명시적 필드 매핑이 있으면 매핑된 타겟 필드를 모두 보존
        // (버튼 설정에서 fieldMappings로 지정한 필드는 link 필드가 아니어도 전달)
        const mappedTargetFields = new Set<string>();
        if (fieldMappings && Array.isArray(fieldMappings)) {
          for (const mapping of fieldMappings) {
            if (mapping.targetField) {
              mappedTargetFields.add(mapping.targetField);
            }
          }
        }

        // parentDataMapping에 정의된 필드만 전달
        for (const mapping of parentDataMapping) {
          const sourceValue = rawParentData[mapping.sourceColumn];
          if (sourceValue !== undefined && sourceValue !== null) {
            parentData[mapping.targetColumn] = sourceValue;
          }
        }

        // 🆕 명시적 필드 매핑이 있으면 해당 필드를 모두 전달
        if (mappedTargetFields.size > 0) {
          for (const [key, value] of Object.entries(rawParentData)) {
            if (mappedTargetFields.has(key) && value !== undefined && value !== null) {
              parentData[key] = value;
            }
          }
        }

        // parentDataMapping이 비어있고 명시적 필드 매핑도 없으면 연결 필드 자동 감지
        if (parentDataMapping.length === 0 && mappedTargetFields.size === 0) {
          const linkFieldPatterns = ["_code", "_id"];
          const excludeFields = [
            "id",
            "company_code",
            "created_date",
            "updated_date",
            "created_at",
            "updated_at",
            "writer",
          ];

          for (const [key, value] of Object.entries(rawParentData)) {
            if (excludeFields.includes(key)) continue;
            if (value === undefined || value === null) continue;

            // 연결 필드 패턴 확인
            const isLinkField = linkFieldPatterns.some((pattern) => key.endsWith(pattern));
            if (isLinkField) {
              parentData[key] = value;
            }
          }
        } else if (parentDataMapping.length === 0 && mappedTargetFields.size > 0) {
          // 🆕 명시적 매핑이 있어도 연결 필드(_code, _id)는 추가로 전달
          const linkFieldPatterns = ["_code", "_id"];
          const excludeFields = [
            "id",
            "company_code",
            "created_date",
            "updated_date",
            "created_at",
            "updated_at",
            "writer",
          ];

          for (const [key, value] of Object.entries(rawParentData)) {
            if (excludeFields.includes(key)) continue;
            if (parentData[key] !== undefined) continue; // 이미 매핑된 필드는 스킵
            if (value === undefined || value === null) continue;

            const isLinkField = linkFieldPatterns.some((pattern) => key.endsWith(pattern));
            if (isLinkField) {
              parentData[key] = value;
            }
          }
        }

        if (Object.keys(parentData).length > 0) {
          console.log("🔵 [ScreenModal] ADD모드 formData 설정:", JSON.stringify(parentData));
          setFormData(parentData);
        } else {
          console.log("🔵 [ScreenModal] ADD모드 formData 비어있음");
          setFormData({});
        }
        setOriginalData(null); // 신규 등록 모드
      }

      setModalState({
        isOpen: true,
        screenId,
        title,
        description: description || "",
        size,
      });
    };

    const handleCloseModal = () => {
      // 🆕 URL 파라미터 제거
      if (typeof window !== "undefined") {
        const currentUrl = new URL(window.location.href);
        // dataSourceId 파라미터 제거
        currentUrl.searchParams.delete("dataSourceId");
        window.history.pushState({}, "", currentUrl.toString());
      }

      setModalState({
        isOpen: false,
        screenId: null,
        title: "",
        description: "",
        size: "md",
      });
      setScreenData(null);
      setFormData({});
      setOriginalData(null); // 🆕 원본 데이터 초기화
      setSelectedData([]); // 🆕 선택된 데이터 초기화
      setContinuousMode(false);
      localStorage.setItem("screenModal_continuousMode", "false");
    };

    // 저장 성공 이벤트 처리 (연속 등록 모드 지원)
    const handleSaveSuccess = () => {
      // 🆕 모달이 열린 후 500ms 이내의 저장 성공 이벤트는 무시 (이전 이벤트 방지)
      const timeSinceOpen = Date.now() - modalOpenedAtRef.current;
      if (timeSinceOpen < 500) {
        return;
      }

      const isContinuousMode = continuousMode;

      if (isContinuousMode) {
        // 연속 모드: 폼만 초기화하고 모달은 유지
        formDataChangedRef.current = false;
        setFormData({});
        setResetKey((prev) => prev + 1);

        // 화면 데이터 다시 로드 (채번 규칙 새로 생성)
        if (modalState.screenId) {
          loadScreenData(modalState.screenId);
        }

        toast.success("저장되었습니다. 계속 입력하세요.");
      } else {
        // 일반 모드: 모달 닫기
        handleCloseModal();
      }
    };

    window.addEventListener("openScreenModal", handleOpenModal as EventListener);
    window.addEventListener("closeSaveModal", handleCloseModal);
    window.addEventListener("saveSuccessInModal", handleSaveSuccess);

    return () => {
      window.removeEventListener("openScreenModal", handleOpenModal as EventListener);
      window.removeEventListener("closeSaveModal", handleCloseModal);
      window.removeEventListener("saveSuccessInModal", handleSaveSuccess);
    };
  }, [tabId, continuousMode]);

  // 화면 데이터 로딩
  useEffect(() => {
    if (modalState.isOpen && modalState.screenId) {
      loadScreenData(modalState.screenId);
    }
  }, [modalState.isOpen, modalState.screenId]);

  const loadScreenData = async (screenId: number) => {
    try {
      setLoading(true);

      // 화면 정보와 레이아웃 데이터 로딩 (V2 API 사용으로 기본값 병합)
      const [screenInfo, v2LayoutData] = await Promise.all([
        screenApi.getScreen(screenId),
        screenApi.getLayoutV2(screenId),
      ]);

      // V2 → Legacy 변환 (기본값 병합 포함)
      let layoutData: any = null;
      if (v2LayoutData && isValidV2Layout(v2LayoutData)) {
        layoutData = convertV2ToLegacy(v2LayoutData);
        if (layoutData) {
          // screenResolution은 V2 레이아웃에서 직접 가져오기
          layoutData.screenResolution = v2LayoutData.screenResolution || layoutData.screenResolution;
        }
      }
      
      // V2 레이아웃이 없으면 기존 API로 fallback
      if (!layoutData) {
        layoutData = await screenApi.getLayout(screenId);
      }

      // 🆕 URL 파라미터 확인 (수정 모드)
      if (typeof window !== "undefined") {
        const urlParams = new URLSearchParams(window.location.search);
        const mode = urlParams.get("mode");
        const editId = urlParams.get("editId");
        const tableName = urlParams.get("tableName") || screenInfo.tableName;
        const groupByColumnsParam = urlParams.get("groupByColumns");
        const primaryKeyColumn = urlParams.get("primaryKeyColumn"); // 🆕 Primary Key 컬럼명

        // 수정 모드이고 editId가 있으면 해당 레코드 조회
        if (mode === "edit" && editId && tableName) {
          try {
            // groupByColumns 파싱
            let groupByColumns: string[] = [];
            if (groupByColumnsParam) {
              try {
                groupByColumns = JSON.parse(groupByColumnsParam);
              } catch {
                // groupByColumns 파싱 실패 시 무시
              }
            }

            // 🆕 apiClient를 named import로 가져오기
            const { apiClient } = await import("@/lib/api/client");
            const params: any = {
              enableEntityJoin: true, // 엔티티 조인 활성화 (모든 엔티티 컬럼 자동 포함)
            };
            if (groupByColumns.length > 0) {
              params.groupByColumns = JSON.stringify(groupByColumns);
            }
            // 🆕 Primary Key 컬럼명 전달 (백엔드 자동 감지 실패 시 사용)
            if (primaryKeyColumn) {
              params.primaryKeyColumn = primaryKeyColumn;
            }

            const apiResponse = await apiClient.get(`/data/${tableName}/${editId}`, { params });
            const response = apiResponse.data;

            if (response.success && response.data) {
              // 🔧 날짜 필드 정규화 (타임존 제거)
              const normalizeDates = (data: any): any => {
                if (Array.isArray(data)) {
                  return data.map(normalizeDates);
                }

                if (typeof data !== "object" || data === null) {
                  return data;
                }

                const normalized: any = {};
                for (const [key, value] of Object.entries(data)) {
                  if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
                    // ISO 날짜 형식 감지: YYYY-MM-DD만 추출
                    normalized[key] = value.split("T")[0];
                  } else {
                    normalized[key] = value;
                  }
                }
                return normalized;
              };

              const normalizedData = normalizeDates(response.data);

              // 🔧 배열 데이터는 formData로 설정하지 않음 (SelectedItemsDetailInput만 사용)
              if (Array.isArray(normalizedData)) {
                setFormData(normalizedData); // SelectedItemsDetailInput이 직접 사용
                setOriginalData(normalizedData[0] || null); // 🆕 첫 번째 레코드를 원본으로 저장
              } else {
                setFormData(normalizedData);
                setOriginalData(normalizedData); // 🆕 원본 데이터 저장 (UPDATE 판단용)
              }
            } else {
              toast.error("수정할 데이터를 불러올 수 없습니다.", {
                description: "해당 항목이 삭제되었거나 접근 권한이 없을 수 있습니다.",
              });
            }
          } catch (error) {
            console.error("수정 데이터 조회 오류:", error);
            showErrorToast("수정 데이터 조회에 실패했습니다", error, {
              guidance: "네트워크 연결을 확인하고 다시 시도해 주세요.",
            });
          }
        }
      }

      // screenApi는 직접 데이터를 반환하므로 .success 체크 불필요
      if (screenInfo && layoutData) {
        const components = layoutData.components || [];

        // 화면 관리에서 설정한 해상도 사용 (우선순위)
        const screenResolution = (layoutData as any).screenResolution || (screenInfo as any).screenResolution;

        console.log("🔍 [ScreenModal] 해상도 디버그:", {
          screenId,
          v2ScreenResolution: v2LayoutData?.screenResolution,
          layoutScreenResolution: (layoutData as any).screenResolution,
          screenInfoResolution: (screenInfo as any).screenResolution,
          finalScreenResolution: screenResolution,
          hasWidth: screenResolution?.width,
          hasHeight: screenResolution?.height,
        });

        let dimensions;
        if (screenResolution && screenResolution.width && screenResolution.height) {
          // 화면 관리에서 설정한 해상도 사용
          dimensions = {
            width: screenResolution.width,
            height: screenResolution.height,
            offsetX: 0,
            offsetY: 0,
          };
          console.log("✅ [ScreenModal] 화면관리 해상도 적용:", dimensions);
        } else {
          // 해상도 정보가 없으면 자동 계산
          dimensions = calculateScreenDimensions(components);
          console.log("⚠️ [ScreenModal] 해상도 없음 - 자동 계산:", dimensions);
        }

        setScreenDimensions(dimensions);

        setScreenData({
          components,
          screenInfo: screenInfo,
        });

        // 🆕 조건부 레이어/존 로드
        loadConditionalLayersAndZones(screenId);
      } else {
        throw new Error("화면 데이터가 없습니다");
      }
    } catch (error) {
      console.error("화면 데이터 로딩 오류:", error);
      showErrorToast("화면 데이터를 불러오는 데 실패했습니다", error, {
        guidance: "화면 설정을 확인하거나 잠시 후 다시 시도해 주세요.",
      });
      handleClose();
    } finally {
      setLoading(false);
    }
  };

  // 🆕 조건부 레이어 & 존 로드 함수
  const loadConditionalLayersAndZones = async (screenId: number) => {
    try {
      const [layersRes, zonesRes] = await Promise.all([
        screenApi.getScreenLayers(screenId),
        screenApi.getScreenZones(screenId),
      ]);

      const loadedLayers = layersRes || [];
      const loadedZones: ConditionalZone[] = zonesRes || [];

      // 기본 레이어(layer_id=1) 제외
      const nonBaseLayers = loadedLayers.filter((l: any) => l.layer_id !== 1);

      if (nonBaseLayers.length === 0) {
        setConditionalLayers([]);
        return;
      }

      const layerDefs: (LayerDefinition & { components: ComponentData[] })[] = [];

      for (const layer of nonBaseLayers) {
        try {
          const layerLayout = await screenApi.getLayerLayout(screenId, layer.layer_id);

          let layerComponents: ComponentData[] = [];
          if (layerLayout && isValidV2Layout(layerLayout)) {
            const legacyLayout = convertV2ToLegacy(layerLayout);
            layerComponents = (legacyLayout?.components || []) as unknown as ComponentData[];
          } else if (layerLayout?.components) {
            layerComponents = layerLayout.components;
          }

          // condition_config에서 zone_id, condition_value 추출
          const cc = layer.condition_config || {};
          const zone = loadedZones.find((z) => z.zone_id === cc.zone_id);

          layerDefs.push({
            id: `layer-${layer.layer_id}`,
            name: layer.layer_name || `레이어 ${layer.layer_id}`,
            type: "conditional",
            zIndex: layer.layer_id,
            isVisible: false,
            isLocked: false,
            zoneId: cc.zone_id,
            conditionValue: cc.condition_value,
            condition: zone
              ? {
                  targetComponentId: zone.trigger_component_id || "",
                  operator: (zone.trigger_operator || "eq") as any,
                  value: cc.condition_value || "",
                }
              : undefined,
            components: layerComponents,
            zone: zone || undefined, // 🆕 Zone 위치 정보 포함 (오프셋 계산용)
          } as any);
        } catch (err) {
          console.warn(`[ScreenModal] 레이어 ${layer.layer_id} 로드 실패:`, err);
        }
      }

      console.log("[ScreenModal] 조건부 레이어 로드 완료:", layerDefs.length, "개",
        layerDefs.map((l) => ({
          id: l.id, name: l.name, conditionValue: l.conditionValue,
          componentCount: l.components.length,
          condition: l.condition,
        }))
      );

      setConditionalLayers(layerDefs);
    } catch (error) {
      console.error("[ScreenModal] 조건부 레이어 로드 실패:", error);
    }
  };

  // 🆕 조건부 레이어 활성화 평가 (formData 변경 시)
  const activeConditionalComponents = useMemo(() => {
    if (conditionalLayers.length === 0) return [];

    const allComponents = screenData?.components || [];
    const activeComps: ComponentData[] = [];

    conditionalLayers.forEach((layer) => {
      if (!layer.condition) return;
      const { targetComponentId, operator, value } = layer.condition;
      if (!targetComponentId) return;

      // V2 레이아웃: overrides.columnName 우선
      const comp = allComponents.find((c: any) => c.id === targetComponentId);
      const fieldKey =
        (comp as any)?.overrides?.columnName ||
        (comp as any)?.columnName ||
        (comp as any)?.componentConfig?.columnName ||
        targetComponentId;

      const targetValue = formData[fieldKey];

      let isMatch = false;
      switch (operator) {
        case "eq":
          isMatch = String(targetValue ?? "") === String(value ?? "");
          break;
        case "neq":
          isMatch = String(targetValue ?? "") !== String(value ?? "");
          break;
        case "in":
          if (Array.isArray(value)) {
            isMatch = value.some((v) => String(v) === String(targetValue ?? ""));
          } else if (typeof value === "string" && value.includes(",")) {
            isMatch = value.split(",").map((v) => v.trim()).includes(String(targetValue ?? ""));
          }
          break;
      }

      console.log("[ScreenModal] 레이어 조건 평가:", {
        layerName: layer.name, fieldKey,
        targetValue: String(targetValue ?? "(없음)"),
        conditionValue: String(value), operator, isMatch,
      });

      if (isMatch) {
        // Zone 오프셋 적용 (레이어 2 컴포넌트는 Zone 상대 좌표로 저장됨)
        const zoneX = layer.zone?.x || 0;
        const zoneY = layer.zone?.y || 0;

        const offsetComponents = layer.components.map((c: any) => ({
          ...c,
          position: {
            ...c.position,
            x: parseFloat(c.position?.x?.toString() || "0") + zoneX,
            y: parseFloat(c.position?.y?.toString() || "0") + zoneY,
          },
        }));

        activeComps.push(...offsetComponents);
      }
    });

    return activeComps;
  }, [formData, conditionalLayers, screenData?.components]);

  // 🆕 이전 활성 레이어 ID 추적 (레이어 전환 감지용)
  const prevActiveLayerIdsRef = useRef<string[]>([]);

  // 🆕 레이어 전환 시 비활성화된 레이어의 필드값을 formData에서 제거
  // (품목우선 → 공급업체우선 전환 시, 품목우선 레이어의 데이터가 남지 않도록)
  useEffect(() => {
    if (conditionalLayers.length === 0) return;

    // 현재 활성 레이어 ID 목록
    const currentActiveLayerIds = conditionalLayers
      .filter((layer) => {
        if (!layer.condition) return false;
        const { targetComponentId, operator, value } = layer.condition;
        if (!targetComponentId) return false;

        const allComponents = screenData?.components || [];
        const comp = allComponents.find((c: any) => c.id === targetComponentId);
        const fieldKey =
          (comp as any)?.overrides?.columnName ||
          (comp as any)?.columnName ||
          (comp as any)?.componentConfig?.columnName ||
          targetComponentId;

        const targetValue = formData[fieldKey];
        switch (operator) {
          case "eq":
            return String(targetValue ?? "") === String(value ?? "");
          case "neq":
            return String(targetValue ?? "") !== String(value ?? "");
          case "in":
            if (Array.isArray(value)) {
              return value.some((v) => String(v) === String(targetValue ?? ""));
            } else if (typeof value === "string" && value.includes(",")) {
              return value.split(",").map((v) => v.trim()).includes(String(targetValue ?? ""));
            }
            return false;
          default:
            return false;
        }
      })
      .map((l) => l.id);

    const prevIds = prevActiveLayerIdsRef.current;

    // 이전에 활성이었는데 이번에 비활성이 된 레이어 찾기
    const deactivatedLayerIds = prevIds.filter((id) => !currentActiveLayerIds.includes(id));

    if (deactivatedLayerIds.length > 0) {
      // 비활성화된 레이어의 컴포넌트 필드명 수집
      const fieldsToRemove: string[] = [];
      deactivatedLayerIds.forEach((layerId) => {
        const layer = conditionalLayers.find((l) => l.id === layerId);
        if (!layer) return;

        layer.components.forEach((comp: any) => {
          const fieldName =
            comp?.overrides?.columnName ||
            comp?.columnName ||
            comp?.componentConfig?.columnName;
          if (fieldName) {
            fieldsToRemove.push(fieldName);
          }
        });
      });

      if (fieldsToRemove.length > 0) {
        console.log("[ScreenModal] 레이어 전환 감지 - 비활성 레이어 필드 제거:", {
          deactivatedLayerIds,
          fieldsToRemove,
        });

        setFormData((prev) => {
          const cleaned = { ...prev };
          fieldsToRemove.forEach((field) => {
            delete cleaned[field];
          });
          return cleaned;
        });
      }
    }

    // 현재 상태 저장
    prevActiveLayerIdsRef.current = currentActiveLayerIds;
  }, [formData, conditionalLayers, screenData?.components]);

  // 사용자가 바깥 클릭/ESC/X 버튼으로 닫으려 할 때
  // 폼 데이터 변경이 있으면 확인 다이얼로그, 없으면 바로 닫기
  const handleCloseAttempt = useCallback(() => {
    if (formDataChangedRef.current) {
      setShowCloseConfirm(true);
    } else {
      handleCloseInternal();
    }
  }, [tabId]);

  // 확인 후 실제로 모달을 닫는 함수
  const handleConfirmClose = useCallback(() => {
    setShowCloseConfirm(false);
    handleCloseInternal();
  }, []);

  // 닫기 취소 (계속 작업)
  const handleCancelClose = useCallback(() => {
    setShowCloseConfirm(false);
  }, []);

  const handleCloseInternal = () => {
    // 🔧 URL 파라미터 제거 (mode, editId, tableName, groupByColumns, dataSourceId 등)
    if (typeof window !== "undefined") {
      const currentUrl = new URL(window.location.href);
      currentUrl.searchParams.delete("mode");
      currentUrl.searchParams.delete("editId");
      currentUrl.searchParams.delete("tableName");
      currentUrl.searchParams.delete("groupByColumns");
      currentUrl.searchParams.delete("dataSourceId");
      window.history.pushState({}, "", currentUrl.toString());
    }

    setModalState({
      isOpen: false,
      screenId: null,
      title: "",
      size: "md",
    });
    setScreenData(null);
    setFormData({}); // 폼 데이터 초기화
    setOriginalData(null); // 원본 데이터 초기화
    setSelectedData([]); // 선택된 데이터 초기화
    setConditionalLayers([]); // 🆕 조건부 레이어 초기화
    setContinuousMode(false);
    localStorage.setItem("screenModal_continuousMode", "false");
  };

  // 기존 handleClose를 유지 (이벤트 핸들러 등에서 사용)
  const handleClose = handleCloseInternal;

  // 모달 크기 설정 - 화면관리 설정 크기 + 헤더/푸터
  const getModalStyle = () => {
    if (!screenDimensions) {
      console.log("⚠️ [ScreenModal] getModalStyle: screenDimensions가 null - 기본 스타일 사용");
      return {
        className: "w-fit min-w-[400px] max-w-4xl overflow-hidden",
        style: { padding: 0, gap: 0, maxHeight: "calc(100dvh - 8px)" },
      };
    }

    const finalWidth = Math.min(screenDimensions.width, window.innerWidth * 0.98);
    console.log("✅ [ScreenModal] getModalStyle: 해상도 적용됨", {
      screenDimensions,
      finalWidth: `${finalWidth}px`,
      viewportWidth: window.innerWidth,
    });

    return {
      className: "overflow-hidden",
      style: {
        width: `${finalWidth}px`,
        // CSS가 알아서 처리: 뷰포트 안에 들어가면 auto-height, 넘치면 max-height로 제한
        maxHeight: "calc(100dvh - 8px)",
        maxWidth: "98vw",
        padding: 0,
        gap: 0,
      },
    };
  };

  const modalStyle = getModalStyle();

  // 안정적인 modalId를 상태로 저장 (모달이 닫혀도 유지)
  const [persistedModalId, setPersistedModalId] = useState<string | undefined>(undefined);

  // modalId 생성 및 업데이트
  useEffect(() => {
    // 모달이 열려있고 screenId가 있을 때만 업데이트
    if (!modalState.isOpen) return;

    let newModalId: string | undefined;

    // 1순위: screenId (가장 안정적)
    if (modalState.screenId) {
      newModalId = `screen-modal-${modalState.screenId}`;
      // console.log("🔑 ScreenModal modalId 생성:", {
      //   method: "screenId",
      //   screenId: modalState.screenId,
      //   result: newModalId,
      // });
    }
    // 2순위: 테이블명
    else if (screenData?.screenInfo?.tableName) {
      newModalId = `screen-modal-table-${screenData.screenInfo.tableName}`;
      // console.log("🔑 ScreenModal modalId 생성:", {
      //   method: "tableName",
      //   tableName: screenData.screenInfo.tableName,
      //   result: newModalId,
      // });
    }
    // 3순위: 화면명
    else if (screenData?.screenInfo?.screenName) {
      newModalId = `screen-modal-name-${screenData.screenInfo.screenName}`;
      // console.log("🔑 ScreenModal modalId 생성:", {
      //   method: "screenName",
      //   screenName: screenData.screenInfo.screenName,
      //   result: newModalId,
      // });
    }
    // 4순위: 제목
    else if (modalState.title) {
      const titleId = modalState.title.replace(/\s+/g, "-");
      newModalId = `screen-modal-title-${titleId}`;
      // console.log("🔑 ScreenModal modalId 생성:", {
      //   method: "title",
      //   title: modalState.title,
      //   result: newModalId,
      // });
    }

    if (newModalId) {
      setPersistedModalId(newModalId);
    }
  }, [
    modalState.isOpen,
    modalState.screenId,
    modalState.title,
    screenData?.screenInfo?.tableName,
    screenData?.screenInfo?.screenName,
  ]);

  return (
    <Dialog
      open={modalState.isOpen}
      onOpenChange={(open) => {
        if (!open) {
          handleCloseAttempt();
        }
      }}
    >
      <DialogContent
        className={`${modalStyle.className} ${className || ""} max-w-none flex flex-col`}
        style={modalStyle.style}
        // 바깥 클릭 시 바로 닫히지 않도록 방지
        onInteractOutside={(e) => {
          e.preventDefault();
          handleCloseAttempt();
        }}
        // ESC 키 누를 때도 바로 닫히지 않도록 방지
        onEscapeKeyDown={(e) => {
          e.preventDefault();
          handleCloseAttempt();
        }}
      >
        <DialogHeader className="shrink-0 border-b px-4 py-3">
          <div className="flex items-center gap-2">
            <DialogTitle className="text-base">{modalState.title}</DialogTitle>
            {modalState.description && !loading && (
              <DialogDescription className="text-muted-foreground text-xs">{modalState.description}</DialogDescription>
            )}
            {loading && (
              <DialogDescription className="text-xs">{loading ? "화면을 불러오는 중입니다..." : ""}</DialogDescription>
            )}
          </div>
        </DialogHeader>

        <div 
          className="flex-1 min-h-0 flex items-start justify-center overflow-auto"
        >
          {loading ? (
            <div className="flex h-full items-center justify-center">
              <div className="text-center">
                <div className="mx-auto mb-4 h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600"></div>
                <p className="text-muted-foreground">화면을 불러오는 중...</p>
              </div>
            </div>
          ) : screenData ? (
            <ScreenContextProvider
              screenId={modalState.screenId || undefined}
              tableName={screenData.screenInfo?.tableName}
            >
            <ActiveTabProvider>
              <TableOptionsProvider>
                <div
                  data-screen-runtime="true"
                  className="relative bg-white"
                  style={{
                    width: `${screenDimensions?.width || 800}px`,
                    // 🆕 조건부 레이어 활성화 시 높이 자동 확장
                    minHeight: `${screenDimensions?.height || 600}px`,
                    height: (() => {
                      const baseHeight = screenDimensions?.height || 600;
                      if (activeConditionalComponents.length > 0) {
                        const offsetY = screenDimensions?.offsetY || 0;
                        let maxBottom = 0;
                        activeConditionalComponents.forEach((comp: any) => {
                          const y = parseFloat(comp.position?.y?.toString() || "0") - offsetY;
                          const h = parseFloat(comp.size?.height?.toString() || "40");
                          maxBottom = Math.max(maxBottom, y + h);
                        });
                        return `${Math.max(baseHeight, maxBottom + 20)}px`;
                      }
                      return `${baseHeight}px`;
                    })(),
                    overflow: "visible",
                  }}
                >
                  {(() => {
                    // 🆕 동적 y 좌표 조정을 위해 먼저 숨겨지는 컴포넌트들 파악
                    const isComponentHidden = (comp: any) => {
                      const cc = comp.componentConfig?.conditionalConfig || comp.conditionalConfig;
                      if (!cc?.enabled || !formData) return false;
                      
                      const { field, operator, value, action } = cc;
                      const fieldValue = formData[field];
                      
                      let conditionMet = false;
                      switch (operator) {
                        case "=":
                        case "==":
                        case "===":
                          conditionMet = fieldValue === value;
                          break;
                        case "!=":
                        case "!==":
                          conditionMet = fieldValue !== value;
                          break;
                        default:
                          conditionMet = fieldValue === value;
                      }
                      
                      return (action === "show" && !conditionMet) || (action === "hide" && conditionMet);
                    };
                    
                    // 표시되는 컴포넌트들의 y 범위 수집
                    const visibleRanges: { y: number; bottom: number }[] = [];
                    screenData.components.forEach((comp: any) => {
                      if (!isComponentHidden(comp)) {
                        const y = parseFloat(comp.position?.y?.toString() || "0");
                        const height = parseFloat(comp.size?.height?.toString() || "0");
                        visibleRanges.push({ y, bottom: y + height });
                      }
                    });
                    
                    // 숨겨지는 컴포넌트의 "실제 빈 공간" 계산 (표시되는 컴포넌트와 겹치지 않는 영역)
                    const getActualGap = (hiddenY: number, hiddenBottom: number): number => {
                      // 숨겨지는 영역 중 표시되는 컴포넌트와 겹치는 부분을 제외
                      let gapStart = hiddenY;
                      let gapEnd = hiddenBottom;
                      
                      for (const visible of visibleRanges) {
                        // 겹치는 영역 확인
                        if (visible.y < gapEnd && visible.bottom > gapStart) {
                          // 겹치는 부분을 제외
                          if (visible.y <= gapStart && visible.bottom >= gapEnd) {
                            // 완전히 덮힘 - 빈 공간 없음
                            return 0;
                          } else if (visible.y <= gapStart) {
                            // 위쪽이 덮힘
                            gapStart = visible.bottom;
                          } else if (visible.bottom >= gapEnd) {
                            // 아래쪽이 덮힘
                            gapEnd = visible.y;
                          }
                        }
                      }
                      
                      return Math.max(0, gapEnd - gapStart);
                    };
                    
                    // 숨겨지는 컴포넌트들의 실제 빈 공간 수집
                    const hiddenGaps: { bottom: number; gap: number }[] = [];
                    screenData.components.forEach((comp: any) => {
                      if (isComponentHidden(comp)) {
                        const y = parseFloat(comp.position?.y?.toString() || "0");
                        const height = parseFloat(comp.size?.height?.toString() || "0");
                        const bottom = y + height;
                        const gap = getActualGap(y, bottom);
                        if (gap > 0) {
                          hiddenGaps.push({ bottom, gap });
                        }
                      }
                    });
                    
                    // bottom 기준으로 정렬 및 중복 제거 (같은 bottom은 가장 큰 gap만 유지)
                    const mergedGaps = new Map<number, number>();
                    hiddenGaps.forEach(({ bottom, gap }) => {
                      const existing = mergedGaps.get(bottom) || 0;
                      mergedGaps.set(bottom, Math.max(existing, gap));
                    });
                    
                    const sortedGaps = Array.from(mergedGaps.entries())
                      .map(([bottom, gap]) => ({ bottom, gap }))
                      .sort((a, b) => a.bottom - b.bottom);
                    
                    // 각 컴포넌트의 y 조정값 계산 함수
                    const getYOffset = (compY: number, compId?: string) => {
                      let offset = 0;
                      for (const { bottom, gap } of sortedGaps) {
                        // 컴포넌트가 숨겨진 영역 아래에 있으면 그 빈 공간만큼 위로 이동
                        if (compY > bottom) {
                          offset += gap;
                        }
                      }
                      return offset;
                    };
                    
                    return screenData.components.map((component: any) => {
                      // 숨겨지는 컴포넌트는 렌더링 안함
                      if (isComponentHidden(component)) {
                        return null;
                      }
                    
                    // 화면 관리 해상도를 사용하는 경우 offset 조정 불필요
                    const offsetX = screenDimensions?.offsetX || 0;
                    const offsetY = screenDimensions?.offsetY || 0;
                    
                    // 🆕 동적 y 좌표 조정 (숨겨진 컴포넌트 높이만큼 위로 이동)
                    const compY = parseFloat(component.position?.y?.toString() || "0");
                    const yAdjustment = getYOffset(compY, component.id);

                    // offset이 0이면 원본 위치 사용 (화면 관리 해상도 사용 시)
                    const adjustedComponent = {
                      ...component,
                      position: {
                        ...component.position,
                        x: parseFloat(component.position?.x?.toString() || "0") - offsetX,
                        y: compY - offsetY - yAdjustment, // 🆕 동적 조정 적용
                      },
                    };

                    return (
                      <InteractiveScreenViewerDynamic
                        key={`${component.id}-${resetKey}`}
                        component={adjustedComponent}
                        allComponents={screenData.components}
                        formData={formData}
                        originalData={originalData} // 🆕 원본 데이터 전달 (UPDATE 판단용)
                        onFormDataChange={(fieldName, value) => {
                          formDataChangedRef.current = true;
                          setFormData((prev) => {
                            const newFormData = {
                              ...prev,
                              [fieldName]: value,
                            };
                            console.log("🟡 [ScreenModal] onFormDataChange:", fieldName, "→", value, "| formData keys:", Object.keys(newFormData), "| process_code:", newFormData.process_code);
                            return newFormData;
                          });
                        }}
                        onRefresh={() => {
                          // 부모 화면의 테이블 새로고침 이벤트 발송
                          window.dispatchEvent(new CustomEvent("refreshTable"));
                        }}
                        screenInfo={{
                          id: modalState.screenId!,
                          tableName: screenData.screenInfo?.tableName,
                        }}
                        groupedData={selectedData}
                        userId={userId}
                        userName={userName}
                        companyCode={user?.companyCode}
                        isInModal={true}
                      />
                    );
                  });
                  })()}

                  {/* 🆕 조건부 레이어 컴포넌트 렌더링 */}
                  {activeConditionalComponents.map((component: any) => {
                    const offsetX = screenDimensions?.offsetX || 0;
                    const offsetY = screenDimensions?.offsetY || 0;

                    const adjustedComponent = {
                      ...component,
                      position: {
                        ...component.position,
                        x: parseFloat(component.position?.x?.toString() || "0") - offsetX,
                        y: parseFloat(component.position?.y?.toString() || "0") - offsetY,
                      },
                    };

                    return (
                      <InteractiveScreenViewerDynamic
                        key={`conditional-${component.id}-${resetKey}`}
                        component={adjustedComponent}
                        allComponents={[...(screenData?.components || []), ...activeConditionalComponents]}
                        formData={formData}
                        originalData={originalData}
                        onFormDataChange={(fieldName, value) => {
                          formDataChangedRef.current = true;
                          setFormData((prev) => ({
                            ...prev,
                            [fieldName]: value,
                          }));
                        }}
                        onRefresh={() => {
                          window.dispatchEvent(new CustomEvent("refreshTable"));
                        }}
                        screenInfo={{
                          id: modalState.screenId!,
                          tableName: screenData?.screenInfo?.tableName,
                        }}
                        userId={userId}
                        userName={userName}
                        companyCode={user?.companyCode}
                        isInModal={true}
                      />
                    );
                  })}
                </div>
              </TableOptionsProvider>
            </ActiveTabProvider>
            </ScreenContextProvider>
          ) : (
            <div className="flex h-full items-center justify-center">
              <p className="text-muted-foreground">화면 데이터가 없습니다.</p>
            </div>
          )}
        </div>

        {/* 연속 등록 모드 체크박스 */}
        <div className="border-t px-4 py-3">
          <div className="flex items-center gap-2">
            <Checkbox
              id="continuous-mode"
              checked={continuousMode}
              onCheckedChange={(checked) => {
                const isChecked = checked === true;
                setContinuousMode(isChecked);
                localStorage.setItem("screenModal_continuousMode", String(isChecked));
              }}
            />
            <Label htmlFor="continuous-mode" className="cursor-pointer text-sm font-normal select-none">
              저장 후 계속 입력 (연속 등록 모드)
            </Label>
          </div>
        </div>
      </DialogContent>

      {/* 모달 닫기 확인 다이얼로그 */}
      <AlertDialog open={showCloseConfirm} onOpenChange={setShowCloseConfirm}>
        <AlertDialogContent className="max-w-[95vw] sm:max-w-[400px]">
          <AlertDialogHeader>
            <AlertDialogTitle className="text-base sm:text-lg">
              화면을 닫으시겠습니까?
            </AlertDialogTitle>
            <AlertDialogDescription className="text-xs sm:text-sm">
              지금 나가시면 진행 중인 데이터가 저장되지 않습니다.
              <br />
              계속 작업하시려면 &apos;계속 작업&apos; 버튼을 눌러주세요.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter className="gap-2 sm:gap-0">
            <AlertDialogCancel
              onClick={handleCancelClose}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              계속 작업
            </AlertDialogCancel>
            <AlertDialogAction
              onClick={handleConfirmClose}
              className="h-8 flex-1 text-xs bg-destructive text-destructive-foreground hover:bg-destructive/90 sm:h-10 sm:flex-none sm:text-sm"
            >
              나가기
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </Dialog>
  );
};

export default ScreenModal;
