"use client";

import React, { useState, useEffect, useMemo } from "react";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Loader2, Save, X, Layers, Table as TableIcon } from "lucide-react";
import {
  RepeatScreenModalProps,
  CardData,
  CardColumnConfig,
  GroupedCardData,
  CardRowData,
  AggregationConfig,
  TableColumnConfig,
  CardContentRowConfig,
  AggregationDisplayConfig,
} from "./types";
import { ComponentRendererProps } from "@/types/component";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";

export interface RepeatScreenModalComponentProps extends ComponentRendererProps {
  config?: RepeatScreenModalProps;
  groupedData?: Record<string, any>[]; // EditModal에서 전달하는 그룹 데이터
}

export function RepeatScreenModalComponent({
  component,
  isDesignMode = false,
  formData,
  onFormDataChange,
  config,
  className,
  groupedData: propsGroupedData, // EditModal에서 전달받는 그룹 데이터
  ...props
}: RepeatScreenModalComponentProps) {
  // props에서도 groupedData를 추출 (DynamicWebTypeRenderer에서 전달될 수 있음)
  const groupedData = propsGroupedData || (props as any).groupedData;
  const componentConfig = {
    ...config,
    ...component?.config,
  };

  // 설정 값 추출
  const dataSource = componentConfig?.dataSource;
  const saveMode = componentConfig?.saveMode || "all";
  const cardSpacing = componentConfig?.cardSpacing || "24px";
  const showCardBorder = componentConfig?.showCardBorder ?? true;
  const showCardTitle = componentConfig?.showCardTitle ?? true;
  const cardTitle = componentConfig?.cardTitle || "카드 {index}";
  const grouping = componentConfig?.grouping;
  
  // 🆕 v3: 자유 레이아웃
  const contentRows = componentConfig?.contentRows || [];
  
  // (레거시 호환)
  const cardLayout = componentConfig?.cardLayout || [];
  const cardMode = componentConfig?.cardMode || "simple";
  const tableLayout = componentConfig?.tableLayout;

  // 상태
  const [rawData, setRawData] = useState<any[]>([]); // 원본 데이터
  const [cardsData, setCardsData] = useState<CardData[]>([]); // simple 모드용
  const [groupedCardsData, setGroupedCardsData] = useState<GroupedCardData[]>([]); // withTable 모드용
  const [isLoading, setIsLoading] = useState(false);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [isSaving, setIsSaving] = useState(false);

  // 초기 데이터 로드
  useEffect(() => {
    const loadInitialData = async () => {
      console.log("[RepeatScreenModal] 데이터 로드 시작");
      console.log("[RepeatScreenModal] groupedData (from EditModal):", groupedData);
      console.log("[RepeatScreenModal] formData:", formData);
      console.log("[RepeatScreenModal] dataSource:", dataSource);

      setIsLoading(true);
      setLoadError(null);

      try {
        let loadedData: any[] = [];

        // 🆕 우선순위 1: EditModal에서 전달받은 groupedData 사용
        if (groupedData && groupedData.length > 0) {
          console.log("[RepeatScreenModal] groupedData 사용:", groupedData.length, "건");
          loadedData = groupedData;
        }
        // 우선순위 2: API 호출
        else if (dataSource && dataSource.sourceTable) {
          // 필터 조건 생성
          const filters: Record<string, any> = {};

          // formData에서 선택된 행 ID 가져오기
          let selectedIds: any[] = [];
          
          if (formData) {
            // 1. 명시적으로 설정된 filterField 확인
            if (dataSource.filterField) {
              const filterValue = formData[dataSource.filterField];
              if (filterValue) {
                selectedIds = Array.isArray(filterValue) ? filterValue : [filterValue];
              }
            }
            
            // 2. 일반적인 선택 필드 확인 (fallback)
            if (selectedIds.length === 0) {
              const commonFields = ['selectedRows', 'selectedIds', 'checkedRows', 'checkedIds', 'ids'];
              for (const field of commonFields) {
                if (formData[field]) {
                  const value = formData[field];
                  selectedIds = Array.isArray(value) ? value : [value];
                  console.log(`[RepeatScreenModal] ${field}에서 선택된 ID 발견:`, selectedIds);
                  break;
                }
              }
            }
            
            // 3. formData에 id가 있으면 단일 행
            if (selectedIds.length === 0 && formData.id) {
              selectedIds = [formData.id];
              console.log("[RepeatScreenModal] formData.id 사용:", selectedIds);
            }
          }

          console.log("[RepeatScreenModal] 최종 선택된 ID:", selectedIds);

          // 선택된 ID가 있으면 필터 적용
          if (selectedIds.length > 0) {
            filters.id = selectedIds;
          } else {
            console.warn("[RepeatScreenModal] 선택된 데이터가 없습니다.");
            setRawData([]);
            setCardsData([]);
            setGroupedCardsData([]);
            setIsLoading(false);
            return;
          }

          console.log("[RepeatScreenModal] API 필터:", filters);

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

          if (response.data.success && response.data.data?.data) {
            loadedData = response.data.data.data;
          }
        } else {
          console.log("[RepeatScreenModal] 데이터 소스 없음");
          setRawData([]);
          setCardsData([]);
          setGroupedCardsData([]);
          setIsLoading(false);
          return;
        }

        console.log("[RepeatScreenModal] 로드된 데이터:", loadedData.length, "건");

        if (loadedData.length === 0) {
          setRawData([]);
          setCardsData([]);
          setGroupedCardsData([]);
          setIsLoading(false);
          return;
        }

        setRawData(loadedData);

        // 🆕 v3: contentRows가 있으면 새로운 방식 사용
        const useNewLayout = contentRows && contentRows.length > 0;
        
        // 그룹핑 모드 확인 (groupByField가 없어도 enabled면 그룹핑 모드로 처리)
        const useGrouping = grouping?.enabled;
        
        if (useGrouping) {
          // 그룹핑 모드
          const grouped = processGroupedData(loadedData, grouping);
          setGroupedCardsData(grouped);
        } else {
          // 단순 모드: 각 행이 하나의 카드
          const initialCards: CardData[] = await Promise.all(
            loadedData.map(async (row: any, index: number) => ({
              _cardId: `card-${index}-${Date.now()}`,
              _originalData: { ...row },
              _isDirty: false,
              ...(await loadCardData(row)),
            }))
          );
          setCardsData(initialCards);
        }
      } catch (error: any) {
        console.error("데이터 로드 실패:", error);
        setLoadError(error.message || "데이터 로드 중 오류가 발생했습니다.");
      } finally {
        setIsLoading(false);
      }
    };

    loadInitialData();
  }, [dataSource, formData, groupedData, contentRows, grouping?.enabled, grouping?.groupByField]);

  // 그룹화된 데이터 처리
  const processGroupedData = (data: any[], groupingConfig: typeof grouping): GroupedCardData[] => {
    if (!groupingConfig?.enabled) {
      return [];
    }

    const groupByField = groupingConfig.groupByField;
    const groupMap = new Map<string, any[]>();

    // groupByField가 없으면 각 행을 개별 그룹으로 처리
    if (!groupByField) {
      // 각 행이 하나의 카드 (그룹)
      data.forEach((row, index) => {
        const groupKey = `row-${index}`;
        groupMap.set(groupKey, [row]);
      });
    } else {
      // 그룹별로 데이터 분류
      data.forEach((row) => {
        const groupKey = String(row[groupByField] || "");
        if (!groupMap.has(groupKey)) {
          groupMap.set(groupKey, []);
        }
        groupMap.get(groupKey)!.push(row);
      });
    }

    // GroupedCardData 생성
    const result: GroupedCardData[] = [];
    let cardIndex = 0;

    groupMap.forEach((rows, groupKey) => {
      // 집계 계산
      const aggregations: Record<string, number> = {};
      if (groupingConfig.aggregations) {
        groupingConfig.aggregations.forEach((agg) => {
          aggregations[agg.resultField] = calculateAggregation(rows, agg);
        });
      }

      // 행 데이터 생성
      const cardRows: CardRowData[] = rows.map((row, idx) => ({
        _rowId: `row-${cardIndex}-${idx}-${Date.now()}`,
        _originalData: { ...row },
        _isDirty: false,
        ...row,
      }));

      result.push({
        _cardId: `grouped-card-${cardIndex}-${Date.now()}`,
        _groupKey: groupKey,
        _groupField: groupByField || "",
        _aggregations: aggregations,
        _rows: cardRows,
        _representativeData: rows[0] || {},
      });

      cardIndex++;
    });

    return result;
  };

  // 집계 계산
  const calculateAggregation = (rows: any[], agg: AggregationConfig): number => {
    const values = rows.map((row) => Number(row[agg.sourceField]) || 0);

    switch (agg.type) {
      case "sum":
        return values.reduce((a, b) => a + b, 0);
      case "count":
        return values.length;
      case "avg":
        return values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;
      case "min":
        return values.length > 0 ? Math.min(...values) : 0;
      case "max":
        return values.length > 0 ? Math.max(...values) : 0;
      default:
        return 0;
    }
  };

  // 카드 데이터 로드 (소스 설정에 따라)
  const loadCardData = async (originalData: any): Promise<Record<string, any>> => {
    const cardData: Record<string, any> = {};

    // 🆕 v3: contentRows 사용
    if (contentRows && contentRows.length > 0) {
      for (const contentRow of contentRows) {
        // 헤더/필드 타입의 컬럼 처리
        if ((contentRow.type === "header" || contentRow.type === "fields") && contentRow.columns) {
          for (const col of contentRow.columns) {
            if (col.sourceConfig) {
              if (col.sourceConfig.type === "direct") {
                cardData[col.field] = originalData[col.sourceConfig.sourceColumn || col.field];
              } else if (col.sourceConfig.type === "join" && col.sourceConfig.joinTable) {
                cardData[col.field] = null; // 조인은 나중에 일괄 처리
              } else if (col.sourceConfig.type === "manual") {
                cardData[col.field] = null;
              }
            } else {
              // sourceConfig가 없으면 원본 데이터에서 직접 가져옴
              cardData[col.field] = originalData[col.field];
            }
          }
        }
        
        // 테이블 타입의 컬럼 처리
        if (contentRow.type === "table" && contentRow.tableColumns) {
          for (const col of contentRow.tableColumns) {
            cardData[col.field] = originalData[col.field];
          }
        }
      }
    } else {
      // 레거시: cardLayout 사용
      for (const row of cardLayout) {
        for (const col of row.columns) {
          if (col.sourceConfig) {
            if (col.sourceConfig.type === "direct") {
              cardData[col.field] = originalData[col.sourceConfig.sourceColumn || col.field];
            } else if (col.sourceConfig.type === "join" && col.sourceConfig.joinTable) {
              cardData[col.field] = null; // 조인은 나중에 일괄 처리
            } else if (col.sourceConfig.type === "manual") {
              cardData[col.field] = null;
            }
          } else {
            cardData[col.field] = originalData[col.field];
          }
        }
      }
    }

    return cardData;
  };

  // Simple 모드: 카드 데이터 변경
  const handleCardDataChange = (cardId: string, field: string, value: any) => {
    setCardsData((prev) =>
      prev.map((card) => (card._cardId === cardId ? { ...card, [field]: value, _isDirty: true } : card))
    );
  };

  // WithTable 모드: 행 데이터 변경
  const handleRowDataChange = (cardId: string, rowId: string, field: string, value: any) => {
    setGroupedCardsData((prev) =>
      prev.map((card) => {
        if (card._cardId !== cardId) return card;

        const updatedRows = card._rows.map((row) =>
          row._rowId === rowId ? { ...row, [field]: value, _isDirty: true } : row
        );

        // 집계값 재계산
        const newAggregations: Record<string, number> = {};
        if (grouping?.aggregations) {
          grouping.aggregations.forEach((agg) => {
            newAggregations[agg.resultField] = calculateAggregation(updatedRows, agg);
          });
        }

        return {
          ...card,
          _rows: updatedRows,
          _aggregations: newAggregations,
        };
      })
    );
  };

  // 카드 제목 생성
  const getCardTitle = (data: Record<string, any>, index: number): string => {
    let title = cardTitle;
    title = title.replace("{index}", String(index + 1));

    const matches = title.match(/\{(\w+)\}/g);
    if (matches) {
      matches.forEach((match) => {
        const field = match.slice(1, -1);
        const value = data[field] || "";
        title = title.replace(match, String(value));
      });
    }

    return title;
  };

  // 전체 저장
  const handleSaveAll = async () => {
    setIsSaving(true);

    try {
      if (cardMode === "withTable") {
        await saveGroupedData();
      } else {
        await saveSimpleData();
      }

      alert("저장되었습니다.");
    } catch (error: any) {
      console.error("저장 실패:", error);
      alert(`저장 중 오류가 발생했습니다: ${error.message}`);
    } finally {
      setIsSaving(false);
    }
  };

  // Simple 모드 저장
  const saveSimpleData = async () => {
    const dirtyCards = cardsData.filter((card) => card._isDirty);

    if (dirtyCards.length === 0) {
      alert("변경된 데이터가 없습니다.");
      return;
    }

    const groupedData: Record<string, any[]> = {};

    for (const card of dirtyCards) {
      for (const row of cardLayout) {
        for (const col of row.columns) {
          if (col.targetConfig && col.targetConfig.saveEnabled !== false) {
            const targetTable = col.targetConfig.targetTable;
            const targetColumn = col.targetConfig.targetColumn;
            const value = card[col.field];

            if (!groupedData[targetTable]) {
              groupedData[targetTable] = [];
            }

            let existingRow = groupedData[targetTable].find((r) => r._cardId === card._cardId);

            if (!existingRow) {
              existingRow = {
                _cardId: card._cardId,
                _originalData: card._originalData,
              };
              groupedData[targetTable].push(existingRow);
            }

            existingRow[targetColumn] = value;
          }
        }
      }
    }

    await saveToTables(groupedData);

    setCardsData((prev) => prev.map((card) => ({ ...card, _isDirty: false })));
  };

  // WithTable 모드 저장
  const saveGroupedData = async () => {
    const dirtyCards = groupedCardsData.filter((card) => card._rows.some((row) => row._isDirty));

    if (dirtyCards.length === 0) {
      alert("변경된 데이터가 없습니다.");
      return;
    }

    const groupedData: Record<string, any[]> = {};

    for (const card of dirtyCards) {
      const dirtyRows = card._rows.filter((row) => row._isDirty);

      for (const row of dirtyRows) {
        // 테이블 컬럼에서 저장 대상 추출
        if (tableLayout?.tableColumns) {
          for (const col of tableLayout.tableColumns) {
            if (col.editable && col.targetConfig && col.targetConfig.saveEnabled !== false) {
              const targetTable = col.targetConfig.targetTable;
              const targetColumn = col.targetConfig.targetColumn;
              const value = row[col.field];

              if (!groupedData[targetTable]) {
                groupedData[targetTable] = [];
              }

              let existingRow = groupedData[targetTable].find((r) => r._rowId === row._rowId);

              if (!existingRow) {
                existingRow = {
                  _rowId: row._rowId,
                  _originalData: row._originalData,
                };
                groupedData[targetTable].push(existingRow);
              }

              existingRow[targetColumn] = value;
            }
          }
        }
      }
    }

    await saveToTables(groupedData);

    setGroupedCardsData((prev) =>
      prev.map((card) => ({
        ...card,
        _rows: card._rows.map((row) => ({ ...row, _isDirty: false })),
      }))
    );
  };

  // 테이블별 저장
  const saveToTables = async (groupedData: Record<string, any[]>) => {
    const savePromises = Object.entries(groupedData).map(async ([tableName, rows]) => {
      return Promise.all(
        rows.map(async (row) => {
          const { _cardId, _rowId, _originalData, ...dataToSave } = row;
          const id = _originalData?.id;

          if (id) {
            await apiClient.put(`/table-management/tables/${tableName}/data/${id}`, dataToSave);
          } else {
            await apiClient.post(`/table-management/tables/${tableName}/data`, dataToSave);
          }
        })
      );
    });

    await Promise.all(savePromises);
  };

  // 수정 여부 확인
  const hasDirtyData = useMemo(() => {
    if (cardMode === "withTable") {
      return groupedCardsData.some((card) => card._rows.some((row) => row._isDirty));
    }
    return cardsData.some((c) => c._isDirty);
  }, [cardMode, cardsData, groupedCardsData]);

  // 디자인 모드 렌더링
  if (isDesignMode) {
    // 행 타입별 개수 계산
    const rowTypeCounts = {
      header: contentRows.filter((r) => r.type === "header").length,
      aggregation: contentRows.filter((r) => r.type === "aggregation").length,
      table: contentRows.filter((r) => r.type === "table").length,
      fields: contentRows.filter((r) => r.type === "fields").length,
    };

    return (
      <div
        className={cn(
          "w-full h-full min-h-[400px] border-2 border-dashed border-primary/50 rounded-lg p-8 bg-gradient-to-br from-primary/5 to-primary/10",
          className
        )}
      >
        <div className="flex flex-col items-center justify-center h-full space-y-6">
          {/* 아이콘 */}
          <div className="w-20 h-20 rounded-full bg-primary/10 flex items-center justify-center">
            <Layers className="w-10 h-10 text-primary" />
          </div>

          {/* 제목 */}
          <div className="text-center space-y-2">
            <div className="text-xl font-bold text-primary">Repeat Screen Modal</div>
            <div className="text-base font-semibold text-foreground">반복 화면 모달</div>
            <Badge variant="secondary">v3 자유 레이아웃</Badge>
          </div>

          {/* 행 구성 정보 */}
          <div className="flex flex-wrap gap-2 justify-center">
            {contentRows.length > 0 ? (
              <>
                {rowTypeCounts.header > 0 && (
                  <Badge className="bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-300">
                    헤더 {rowTypeCounts.header}개
                  </Badge>
                )}
                {rowTypeCounts.aggregation > 0 && (
                  <Badge className="bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-300">
                    집계 {rowTypeCounts.aggregation}개
                  </Badge>
                )}
                {rowTypeCounts.table > 0 && (
                  <Badge className="bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300">
                    테이블 {rowTypeCounts.table}개
                  </Badge>
                )}
                {rowTypeCounts.fields > 0 && (
                  <Badge className="bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300">
                    필드 {rowTypeCounts.fields}개
                  </Badge>
                )}
              </>
            ) : (
              <Badge variant="outline">행 없음</Badge>
            )}
          </div>

          {/* 통계 정보 */}
          <div className="flex gap-6 text-center">
            <div className="space-y-1">
              <div className="text-2xl font-bold text-primary">{contentRows.length}</div>
              <div className="text-xs text-muted-foreground">행 (Rows)</div>
            </div>
            <div className="w-px bg-border" />
            <div className="space-y-1">
              <div className="text-2xl font-bold text-primary">{grouping?.aggregations?.length || 0}</div>
              <div className="text-xs text-muted-foreground">집계 설정</div>
            </div>
            <div className="w-px bg-border" />
            <div className="space-y-1">
              <div className="text-2xl font-bold text-primary">{dataSource?.sourceTable ? 1 : 0}</div>
              <div className="text-xs text-muted-foreground">데이터 소스</div>
            </div>
          </div>

          {/* 데이터 소스 정보 */}
          {dataSource?.sourceTable && (
            <div className="text-xs bg-green-100 dark:bg-green-900 px-3 py-2 rounded-md">
              소스 테이블: <strong>{dataSource.sourceTable}</strong>
              {dataSource.filterField && <span className="ml-2">(필터: {dataSource.filterField})</span>}
            </div>
          )}

          {/* 그룹핑 정보 */}
          {grouping?.enabled && (
            <div className="text-xs bg-purple-100 dark:bg-purple-900 px-3 py-2 rounded-md">
              그룹핑: <strong>{grouping.groupByField}</strong>
            </div>
          )}

          {/* 카드 제목 정보 */}
          {showCardTitle && cardTitle && (
            <div className="text-xs bg-muted px-3 py-2 rounded-md">
              카드 제목: <strong>{cardTitle}</strong>
            </div>
          )}

          {/* 설정 안내 */}
          <div className="text-xs text-muted-foreground bg-muted/50 px-4 py-2 rounded-md border">
            오른쪽 패널에서 행을 추가하고 타입(헤더/집계/테이블/필드)을 선택하세요
          </div>
        </div>
      </div>
    );
  }

  // 로딩 상태
  if (isLoading) {
    return (
      <div className="flex items-center justify-center p-12">
        <Loader2 className="h-8 w-8 animate-spin text-primary" />
        <span className="ml-3 text-sm text-muted-foreground">데이터를 불러오는 중...</span>
      </div>
    );
  }

  // 오류 상태
  if (loadError) {
    return (
      <div className="p-6 border border-destructive/50 rounded-lg bg-destructive/5">
        <div className="flex items-center gap-2 text-destructive mb-2">
          <X className="h-5 w-5" />
          <span className="font-semibold">데이터 로드 실패</span>
        </div>
        <p className="text-sm text-muted-foreground">{loadError}</p>
      </div>
    );
  }

  // 🆕 v3: 자유 레이아웃 렌더링 (contentRows 사용)
  const useNewLayout = contentRows && contentRows.length > 0;
  const useGrouping = grouping?.enabled;

  // 그룹핑 모드 렌더링
  if (useGrouping) {
    return (
      <div className={cn("space-y-6 overflow-x-auto", className)}>
        <div className="space-y-4 min-w-[800px]" style={{ gap: cardSpacing }}>
          {groupedCardsData.map((card, cardIndex) => (
            <Card
              key={card._cardId}
              className={cn(
                "transition-shadow",
                showCardBorder && "border-2",
                card._rows.some((r) => r._isDirty) && "border-primary shadow-lg"
              )}
            >
              {/* 카드 제목 (선택사항) */}
              {showCardTitle && (
                <CardHeader className="pb-3">
                  <CardTitle className="text-lg flex items-center justify-between">
                    <span>{getCardTitle(card._representativeData, cardIndex)}</span>
                    {card._rows.some((r) => r._isDirty) && (
                      <Badge variant="outline" className="text-xs text-primary">
                        수정됨
                      </Badge>
                    )}
                  </CardTitle>
                </CardHeader>
              )}
              <CardContent className="space-y-4">
                {/* 🆕 v3: contentRows 기반 렌더링 */}
                {useNewLayout ? (
                  contentRows.map((contentRow, rowIndex) => (
                    <div key={contentRow.id || `crow-${rowIndex}`}>
                      {renderContentRow(contentRow, card, grouping?.aggregations || [], handleRowDataChange)}
                    </div>
                  ))
                ) : (
                  // 레거시: tableLayout 사용
                  <>
                    {tableLayout?.headerRows && tableLayout.headerRows.length > 0 && (
                      <div className="space-y-3 p-4 bg-muted/30 rounded-lg">
                        {tableLayout.headerRows.map((row, rowIndex) => (
                          <div
                            key={row.id || `hrow-${rowIndex}`}
                            className={cn(
                              "grid gap-4",
                              row.layout === "vertical" ? "grid-cols-1" : "grid-flow-col auto-cols-fr",
                              row.backgroundColor && getBackgroundClass(row.backgroundColor),
                              row.rounded && "rounded-lg",
                              row.padding && `p-${row.padding}`
                            )}
                            style={{ gap: row.gap || "16px" }}
                          >
                            {row.columns.map((col, colIndex) => (
                              <div key={col.id || `hcol-${colIndex}`} style={{ width: col.width }}>
                                {renderHeaderColumn(col, card, grouping?.aggregations || [])}
                              </div>
                            ))}
                          </div>
                        ))}
                      </div>
                    )}

                    {tableLayout?.tableColumns && tableLayout.tableColumns.length > 0 && (
                      <div className="border rounded-lg overflow-hidden">
                        <Table>
                          <TableHeader>
                            <TableRow className="bg-muted/50">
                              {tableLayout.tableColumns.map((col) => (
                                <TableHead
                                  key={col.id}
                                  style={{ width: col.width }}
                                  className={cn("text-xs", col.align && `text-${col.align}`)}
                                >
                                  {col.label}
                                </TableHead>
                              ))}
                            </TableRow>
                          </TableHeader>
                          <TableBody>
                            {card._rows.map((row) => (
                              <TableRow key={row._rowId} className={cn(row._isDirty && "bg-primary/5")}>
                                {tableLayout.tableColumns.map((col) => (
                                  <TableCell
                                    key={`${row._rowId}-${col.id}`}
                                    className={cn("text-sm", col.align && `text-${col.align}`)}
                                  >
                                    {renderTableCell(col, row, (value) =>
                                      handleRowDataChange(card._cardId, row._rowId, col.field, value)
                                    )}
                                  </TableCell>
                                ))}
                              </TableRow>
                            ))}
                          </TableBody>
                        </Table>
                      </div>
                    )}
                  </>
                )}
              </CardContent>
            </Card>
          ))}
        </div>

        {/* 저장 버튼 */}
        {groupedCardsData.length > 0 && (
          <div className="flex justify-end gap-2">
            <Button onClick={handleSaveAll} disabled={isSaving || !hasDirtyData} className="gap-2">
              {isSaving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
              전체 저장
            </Button>
          </div>
        )}

        {/* 데이터 없음 */}
        {groupedCardsData.length === 0 && !isLoading && (
          <div className="text-center py-12 text-muted-foreground">표시할 데이터가 없습니다.</div>
        )}
      </div>
    );
  }

  // 단순 모드 렌더링 (그룹핑 없음)
  return (
    <div className={cn("space-y-6 overflow-x-auto", className)}>
      <div className="space-y-4 min-w-[600px]" style={{ gap: cardSpacing }}>
        {cardsData.map((card, cardIndex) => (
          <Card
            key={card._cardId}
            className={cn("transition-shadow", showCardBorder && "border-2", card._isDirty && "border-primary shadow-lg")}
          >
            {/* 카드 제목 (선택사항) */}
            {showCardTitle && (
              <CardHeader className="pb-3">
                <CardTitle className="text-lg flex items-center justify-between">
                  <span>{getCardTitle(card, cardIndex)}</span>
                  {card._isDirty && <span className="text-xs text-primary font-normal">(수정됨)</span>}
                </CardTitle>
              </CardHeader>
            )}
            <CardContent className="space-y-4">
              {/* 🆕 v3: contentRows 기반 렌더링 */}
              {useNewLayout ? (
                contentRows.map((contentRow, rowIndex) => (
                  <div key={contentRow.id || `crow-${rowIndex}`}>
                    {renderSimpleContentRow(contentRow, card, (value, field) =>
                      handleCardDataChange(card._cardId, field, value)
                    )}
                  </div>
                ))
              ) : (
                // 레거시: cardLayout 사용
                cardLayout.map((row, rowIndex) => (
                  <div
                    key={row.id || `row-${rowIndex}`}
                    className={cn(
                      "grid gap-4",
                      row.layout === "vertical" ? "grid-cols-1" : "grid-flow-col auto-cols-fr"
                    )}
                    style={{ gap: row.gap || "16px" }}
                  >
                    {row.columns.map((col, colIndex) => (
                      <div key={col.id || `col-${colIndex}`} style={{ width: col.width }}>
                        {renderColumn(col, card, (value) => handleCardDataChange(card._cardId, col.field, value))}
                      </div>
                    ))}
                  </div>
                ))
              )}
            </CardContent>
          </Card>
        ))}
      </div>

      {/* 저장 버튼 */}
      {cardsData.length > 0 && (
        <div className="flex justify-end gap-2">
          <Button onClick={handleSaveAll} disabled={isSaving || !hasDirtyData} className="gap-2">
            {isSaving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
            {saveMode === "all" ? "전체 저장" : "저장"}
          </Button>
        </div>
      )}

      {/* 데이터 없음 */}
      {cardsData.length === 0 && !isLoading && (
        <div className="text-center py-12 text-muted-foreground">표시할 데이터가 없습니다.</div>
      )}
    </div>
  );
}

// 🆕 v3: contentRow 렌더링 (그룹핑 모드)
function renderContentRow(
  contentRow: CardContentRowConfig,
  card: GroupedCardData,
  aggregations: AggregationConfig[],
  onRowDataChange: (cardId: string, rowId: string, field: string, value: any) => void
) {
  switch (contentRow.type) {
    case "header":
    case "fields":
      // contentRow에서 직접 columns 가져오기 (v3 구조)
      const headerColumns = contentRow.columns || [];
      
      if (headerColumns.length === 0) {
        return (
          <div className="p-4 bg-muted/30 rounded-lg text-sm text-muted-foreground">
            헤더 컬럼이 설정되지 않았습니다.
          </div>
        );
      }
      
      return (
        <div
          className={cn(
            "grid gap-4",
            contentRow.layout === "vertical" ? "grid-cols-1" : "grid-flow-col auto-cols-fr",
            contentRow.backgroundColor && getBackgroundClass(contentRow.backgroundColor),
            contentRow.padding && `p-${contentRow.padding}`,
            "rounded-lg"
          )}
          style={{ gap: contentRow.gap || "16px" }}
        >
          {headerColumns.map((col, colIndex) => (
            <div key={col.id || `col-${colIndex}`} style={{ width: col.width }}>
              {renderHeaderColumn(col, card, aggregations)}
            </div>
          ))}
        </div>
      );

    case "aggregation":
      // contentRow에서 직접 aggregationFields 가져오기 (v3 구조)
      const aggFields = contentRow.aggregationFields || [];
      
      if (aggFields.length === 0) {
        return (
          <div className="p-4 bg-orange-50 dark:bg-orange-950 rounded-lg text-sm text-orange-600 dark:text-orange-400">
            집계 필드가 설정되지 않았습니다. (레이아웃 탭에서 집계 필드를 추가하세요)
          </div>
        );
      }
      
      return (
        <div
          className={cn(
            contentRow.aggregationLayout === "vertical"
              ? "flex flex-col gap-3"
              : "flex flex-wrap gap-4"
          )}
        >
          {aggFields.map((aggField, fieldIndex) => {
            // 집계 결과에서 값 가져오기 (aggregationResultField 사용)
            const value = card._aggregations?.[aggField.aggregationResultField] || 0;
            return (
              <div
                key={fieldIndex}
                className={cn(
                  "p-3 rounded-lg flex-1 min-w-[120px]",
                  aggField.backgroundColor ? getBackgroundClass(aggField.backgroundColor) : "bg-muted/50"
                )}
              >
                <div className="text-xs text-muted-foreground">{aggField.label || aggField.aggregationResultField}</div>
                <div
                  className={cn(
                    "font-bold",
                    aggField.fontSize ? `text-${aggField.fontSize}` : "text-lg",
                    aggField.textColor && `text-${aggField.textColor}`
                  )}
                >
                  {typeof value === "number" ? value.toLocaleString() : value || "-"}
                </div>
              </div>
            );
          })}
        </div>
      );

    case "table":
      // contentRow에서 직접 tableColumns 가져오기 (v3 구조)
      const tableColumns = contentRow.tableColumns || [];
      
      if (tableColumns.length === 0) {
        return (
          <div className="p-4 bg-blue-50 dark:bg-blue-950 rounded-lg text-sm text-blue-600 dark:text-blue-400">
            테이블 컬럼이 설정되지 않았습니다. (레이아웃 탭에서 테이블 컬럼을 추가하세요)
          </div>
        );
      }
      
      return (
        <div className="border rounded-lg overflow-hidden">
          {contentRow.tableTitle && (
            <div className="px-4 py-2 bg-muted/30 border-b text-sm font-medium">
              {contentRow.tableTitle}
            </div>
          )}
          <Table>
            {contentRow.showTableHeader !== false && (
              <TableHeader>
                <TableRow className="bg-muted/50">
                  {tableColumns.map((col) => (
                    <TableHead
                      key={col.id}
                      style={{ width: col.width }}
                      className={cn("text-xs", col.align && `text-${col.align}`)}
                    >
                      {col.label}
                    </TableHead>
                  ))}
                </TableRow>
              </TableHeader>
            )}
            <TableBody>
              {card._rows.map((row) => (
                <TableRow key={row._rowId} className={cn(row._isDirty && "bg-primary/5")}>
                  {tableColumns.map((col) => (
                    <TableCell
                      key={`${row._rowId}-${col.id}`}
                      className={cn("text-sm", col.align && `text-${col.align}`)}
                    >
                      {renderTableCell(col, row, (value) =>
                        onRowDataChange(card._cardId, row._rowId, col.field, value)
                      )}
                    </TableCell>
                  ))}
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </div>
      );

    default:
      return null;
  }
}

// 🆕 v3: contentRow 렌더링 (단순 모드)
function renderSimpleContentRow(
  contentRow: CardContentRowConfig,
  card: CardData,
  onChange: (value: any, field: string) => void
) {
  switch (contentRow.type) {
    case "header":
    case "fields":
      return (
        <div
          className={cn(
            "grid gap-4",
            contentRow.layout === "vertical" ? "grid-cols-1" : "grid-flow-col auto-cols-fr",
            contentRow.backgroundColor && getBackgroundClass(contentRow.backgroundColor),
            contentRow.padding && `p-${contentRow.padding}`,
            "rounded-lg"
          )}
          style={{ gap: contentRow.gap || "16px" }}
        >
          {(contentRow.columns || []).map((col, colIndex) => (
            <div key={col.id || `col-${colIndex}`} style={{ width: col.width }}>
              {renderColumn(col, card, (value) => onChange(value, col.field))}
            </div>
          ))}
        </div>
      );

    case "aggregation":
      // 단순 모드에서도 집계 표시 (단일 카드 기준)
      // contentRow에서 직접 aggregationFields 가져오기 (v3 구조)
      const aggFields = contentRow.aggregationFields || [];
      
      if (aggFields.length === 0) {
        return (
          <div className="p-4 bg-orange-50 dark:bg-orange-950 rounded-lg text-sm text-orange-600 dark:text-orange-400">
            집계 필드가 설정되지 않았습니다.
          </div>
        );
      }
      
      return (
        <div
          className={cn(
            contentRow.aggregationLayout === "vertical"
              ? "flex flex-col gap-3"
              : "flex flex-wrap gap-4"
          )}
        >
          {aggFields.map((aggField, fieldIndex) => {
            // 단순 모드에서는 카드 데이터에서 직접 값을 가져옴 (aggregationResultField 사용)
            const value = card[aggField.aggregationResultField] || card._originalData?.[aggField.aggregationResultField];
            return (
              <div
                key={fieldIndex}
                className={cn(
                  "p-3 rounded-lg flex-1 min-w-[120px]",
                  aggField.backgroundColor ? getBackgroundClass(aggField.backgroundColor) : "bg-muted/50"
                )}
              >
                <div className="text-xs text-muted-foreground">{aggField.label || aggField.aggregationResultField}</div>
                <div
                  className={cn(
                    "font-bold",
                    aggField.fontSize ? `text-${aggField.fontSize}` : "text-lg",
                    aggField.textColor && `text-${aggField.textColor}`
                  )}
                >
                  {typeof value === "number" ? value.toLocaleString() : value || "-"}
                </div>
              </div>
            );
          })}
        </div>
      );

    case "table":
      // 단순 모드에서도 테이블 표시 (단일 행)
      // contentRow에서 직접 tableColumns 가져오기 (v3 구조)
      const tableColumns = contentRow.tableColumns || [];
      
      if (tableColumns.length === 0) {
        return (
          <div className="p-4 bg-blue-50 dark:bg-blue-950 rounded-lg text-sm text-blue-600 dark:text-blue-400">
            테이블 컬럼이 설정되지 않았습니다.
          </div>
        );
      }
      
      return (
        <div className="border rounded-lg overflow-hidden">
          {contentRow.tableTitle && (
            <div className="px-4 py-2 bg-muted/30 border-b text-sm font-medium">
              {contentRow.tableTitle}
            </div>
          )}
          <Table>
            {contentRow.showTableHeader !== false && (
              <TableHeader>
                <TableRow className="bg-muted/50">
                  {tableColumns.map((col) => (
                    <TableHead
                      key={col.id}
                      style={{ width: col.width }}
                      className={cn("text-xs", col.align && `text-${col.align}`)}
                    >
                      {col.label}
                    </TableHead>
                  ))}
                </TableRow>
              </TableHeader>
            )}
            <TableBody>
              {/* 단순 모드: 카드 자체가 하나의 행 */}
              <TableRow className={cn(card._isDirty && "bg-primary/5")}>
                {tableColumns.map((col) => (
                  <TableCell
                    key={`${card._cardId}-${col.id}`}
                    className={cn("text-sm", col.align && `text-${col.align}`)}
                  >
                    {renderSimpleTableCell(col, card, (value) => onChange(value, col.field))}
                  </TableCell>
                ))}
              </TableRow>
            </TableBody>
          </Table>
        </div>
      );

    default:
      return null;
  }
}

// 단순 모드 테이블 셀 렌더링
function renderSimpleTableCell(
  col: TableColumnConfig,
  card: CardData,
  onChange: (value: any) => void
) {
  const value = card[col.field] || card._originalData?.[col.field];

  if (!col.editable) {
    // 읽기 전용
    if (col.type === "number") {
      return typeof value === "number" ? value.toLocaleString() : value || "-";
    }
    return value || "-";
  }

  // 편집 가능
  switch (col.type) {
    case "number":
      return (
        <Input
          type="number"
          value={value || ""}
          onChange={(e) => onChange(parseFloat(e.target.value) || 0)}
          className="h-8 text-sm"
        />
      );
    case "date":
      return (
        <Input
          type="date"
          value={value || ""}
          onChange={(e) => onChange(e.target.value)}
          className="h-8 text-sm"
        />
      );
    case "select":
      return (
        <Select value={value || ""} onValueChange={onChange}>
          <SelectTrigger className="h-8 text-sm">
            <SelectValue placeholder="선택" />
          </SelectTrigger>
          <SelectContent>
            {(col.selectOptions || []).map((opt) => (
              <SelectItem key={opt.value} value={opt.value}>
                {opt.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      );
    default:
      return (
        <Input
          type="text"
          value={value || ""}
          onChange={(e) => onChange(e.target.value)}
          className="h-8 text-sm"
        />
      );
  }
}

// 배경색 클래스 변환
function getBackgroundClass(color: string): string {
  const colorMap: Record<string, string> = {
    blue: "bg-blue-50 dark:bg-blue-950",
    green: "bg-green-50 dark:bg-green-950",
    purple: "bg-purple-50 dark:bg-purple-950",
    orange: "bg-orange-50 dark:bg-orange-950",
  };
  return colorMap[color] || "";
}

// 헤더 컬럼 렌더링 (집계값 포함)
function renderHeaderColumn(
  col: CardColumnConfig,
  card: GroupedCardData,
  aggregations: AggregationConfig[]
) {
  let value: any;

  // 집계값 타입이면 집계 결과에서 가져옴
  if (col.type === "aggregation" && col.aggregationField) {
    value = card._aggregations[col.aggregationField];
    const aggConfig = aggregations.find((a) => a.resultField === col.aggregationField);

    return (
      <div className="space-y-1">
        <Label className="text-xs font-medium text-muted-foreground">{col.label}</Label>
        <div
          className={cn(
            "text-lg font-bold",
            col.textColor && `text-${col.textColor}`,
            col.fontSize && `text-${col.fontSize}`
          )}
        >
          {typeof value === "number" ? value.toLocaleString() : value || "-"}
          {aggConfig && <span className="text-xs font-normal text-muted-foreground ml-1">({aggConfig.type})</span>}
        </div>
      </div>
    );
  }

  // 일반 필드는 대표 데이터에서 가져옴
  value = card._representativeData[col.field];

  return (
    <div className="space-y-1">
      <Label className="text-xs font-medium text-muted-foreground">{col.label}</Label>
      <div
        className={cn(
          "text-sm",
          col.fontWeight && `font-${col.fontWeight}`,
          col.fontSize && `text-${col.fontSize}`
        )}
      >
        {value || "-"}
      </div>
    </div>
  );
}

// 테이블 셀 렌더링
function renderTableCell(col: TableColumnConfig, row: CardRowData, onChange: (value: any) => void) {
  const value = row[col.field];

  // Badge 타입
  if (col.type === "badge") {
    const badgeColor = col.badgeColorMap?.[value] || col.badgeVariant || "default";
    return <Badge variant={badgeColor as any}>{value || "-"}</Badge>;
  }

  // 읽기 전용
  if (!col.editable) {
    if (col.type === "number") {
      return <span>{typeof value === "number" ? value.toLocaleString() : value || "-"}</span>;
    }
    return <span>{value || "-"}</span>;
  }

  // 편집 가능
  switch (col.type) {
    case "text":
      return (
        <Input
          value={value || ""}
          onChange={(e) => onChange(e.target.value)}
          className="h-8 text-sm"
        />
      );
    case "number":
      return (
        <Input
          type="number"
          value={value || ""}
          onChange={(e) => onChange(Number(e.target.value) || 0)}
          className="h-8 text-sm text-right"
        />
      );
    case "date":
      return (
        <Input
          type="date"
          value={value || ""}
          onChange={(e) => onChange(e.target.value)}
          className="h-8 text-sm"
        />
      );
    default:
      return <span>{value || "-"}</span>;
  }
}

// 컬럼 렌더링 함수 (Simple 모드)
function renderColumn(col: CardColumnConfig, card: CardData, onChange: (value: any) => void) {
  const value = card[col.field];
  const isReadOnly = !col.editable;

  return (
    <div className="space-y-1.5">
      <Label className="text-xs font-medium">
        {col.label}
        {col.required && <span className="text-destructive ml-1">*</span>}
      </Label>

      {isReadOnly && (
        <div className="text-sm text-muted-foreground bg-muted px-3 py-2 rounded-md min-h-[40px] flex items-center">
          {value || "-"}
        </div>
      )}

      {!isReadOnly && (
        <>
          {col.type === "text" && (
            <Input
              value={value || ""}
              onChange={(e) => onChange(e.target.value)}
              placeholder={col.placeholder}
              className="h-10 text-sm"
            />
          )}

          {col.type === "number" && (
            <Input
              type="number"
              value={value || ""}
              onChange={(e) => onChange(e.target.value)}
              placeholder={col.placeholder}
              className="h-10 text-sm"
            />
          )}

          {col.type === "date" && (
            <Input
              type="date"
              value={value || ""}
              onChange={(e) => onChange(e.target.value)}
              className="h-10 text-sm"
            />
          )}

          {col.type === "select" && (
            <Select value={value || ""} onValueChange={onChange}>
              <SelectTrigger className="h-10 text-sm">
                <SelectValue placeholder={col.placeholder || "선택하세요"} />
              </SelectTrigger>
              <SelectContent>
                {col.selectOptions?.map((option) => (
                  <SelectItem key={option.value} value={option.value}>
                    {option.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          )}

          {col.type === "textarea" && (
            <Textarea
              value={value || ""}
              onChange={(e) => onChange(e.target.value)}
              placeholder={col.placeholder}
              className="text-sm min-h-[80px]"
            />
          )}

          {col.type === "component" && col.componentType && (
            <div className="text-xs text-muted-foreground p-2 border rounded">
              컴포넌트: {col.componentType} (개발 중)
            </div>
          )}
        </>
      )}
    </div>
  );
}
