"use client";

/**
 * pop-field 설정 패널
 *
 * 구조:
 * - [레이아웃 탭] 섹션 목록 (추가/삭제/이동) + 필드 편집
 * - [저장 탭] 저장 테이블 / 필드-컬럼 매핑 / 읽기 데이터 소스
 */

import { useState, useEffect, useCallback, useMemo } from "react";
import {
  ChevronDown,
  ChevronRight,
  Plus,
  Trash2,
  GripVertical,
  Check,
  ChevronsUpDown,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
import type {
  PopFieldConfig,
  PopFieldSection,
  PopFieldItem,
  FieldInputType,
  FieldSectionStyle,
  FieldSectionAppearance,
  FieldSelectSource,
  AutoNumberConfig,
  FieldValueSource,
  PopFieldSaveMapping,
  PopFieldSaveConfig,
  PopFieldReadMapping,
  PopFieldHiddenMapping,
  PopFieldAutoGenMapping,
  HiddenValueSource,
} from "./types";
import {
  DEFAULT_FIELD_CONFIG,
  DEFAULT_SECTION_APPEARANCES,
  FIELD_INPUT_TYPE_LABELS,
  FIELD_SECTION_STYLE_LABELS,
} from "./types";
import {
  fetchTableList,
  fetchTableColumns,
  type TableInfo,
  type ColumnInfo,
} from "../pop-dashboard/utils/dataFetcher";
import { dataApi } from "@/lib/api/data";
import { getAvailableNumberingRulesForScreen } from "@/lib/api/numberingRule";

// ========================================
// Props
// ========================================

interface PopFieldConfigPanelProps {
  config: PopFieldConfig | undefined;
  onUpdate: (config: PopFieldConfig) => void;
}

// ========================================
// 메인 설정 패널
// ========================================

export function PopFieldConfigPanel({
  config,
  onUpdate: onConfigChange,
}: PopFieldConfigPanelProps) {
  const cfg: PopFieldConfig = {
    ...DEFAULT_FIELD_CONFIG,
    ...config,
    sections: config?.sections?.length ? config.sections : DEFAULT_FIELD_CONFIG.sections,
  };
  const [tables, setTables] = useState<TableInfo[]>([]);
  const [saveTableOpen, setSaveTableOpen] = useState(false);
  const [readTableOpen, setReadTableOpen] = useState(false);

  const saveTableName = cfg.saveConfig?.tableName ?? cfg.targetTable ?? "";

  useEffect(() => {
    fetchTableList().then(setTables);
  }, []);

  const updateConfig = useCallback(
    (partial: Partial<PopFieldConfig>) => {
      onConfigChange({ ...cfg, ...partial });
    },
    [cfg, onConfigChange]
  );

  const updateSection = useCallback(
    (sectionId: string, partial: Partial<PopFieldSection>) => {
      const sections = cfg.sections.map((s) =>
        s.id === sectionId ? { ...s, ...partial } : s
      );
      updateConfig({ sections });
    },
    [cfg.sections, updateConfig]
  );

  const addSection = useCallback(() => {
    const newId = `section_${Date.now()}`;
    const newSection: PopFieldSection = {
      id: newId,
      style: "input",
      columns: "auto",
      showLabels: true,
      fields: [],
    };
    updateConfig({ sections: [...cfg.sections, newSection] });
  }, [cfg.sections, updateConfig]);

  const removeSection = useCallback(
    (sectionId: string) => {
      if (cfg.sections.length <= 1) return;
      updateConfig({ sections: cfg.sections.filter((s) => s.id !== sectionId) });
    },
    [cfg.sections, updateConfig]
  );

  const moveSectionUp = useCallback(
    (index: number) => {
      if (index <= 0) return;
      const sections = [...cfg.sections];
      [sections[index - 1], sections[index]] = [
        sections[index],
        sections[index - 1],
      ];
      updateConfig({ sections });
    },
    [cfg.sections, updateConfig]
  );

  const handleSaveTableChange = useCallback(
    (tableName: string) => {
      const next = tableName === saveTableName ? "" : tableName;
      const saveConfig: PopFieldSaveConfig = {
        ...cfg.saveConfig,
        tableName: next,
        fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
      };
      updateConfig({ saveConfig, targetTable: next });
    },
    [cfg.saveConfig, saveTableName, updateConfig]
  );

  const allFields = useMemo(() => {
    return cfg.sections.flatMap((s) =>
      (s.fields ?? []).map((f) => ({ field: f, section: s }))
    );
  }, [cfg.sections]);

  const displayFields = useMemo(() => {
    return cfg.sections
      .filter((s) => migrateStyle(s.style) === "display")
      .flatMap((s) => (s.fields ?? []).map((f) => ({ field: f, section: s })));
  }, [cfg.sections]);

  const inputFields = useMemo(() => {
    return cfg.sections
      .filter((s) => migrateStyle(s.style) === "input")
      .flatMap((s) => (s.fields ?? []).map((f) => ({ field: f, section: s })));
  }, [cfg.sections]);

  const hasDisplayFields = displayFields.length > 0;
  const hasInputFields = inputFields.length > 0;

  return (
    <Tabs defaultValue="layout" className="w-full">
      <TabsList className="h-8 w-full">
        <TabsTrigger value="layout" className="flex-1 text-xs">
          레이아웃
        </TabsTrigger>
        <TabsTrigger value="save" className="flex-1 text-xs">
          저장
        </TabsTrigger>
      </TabsList>

      <TabsContent value="layout" className="mt-3 space-y-4">
        {cfg.sections.map((section, idx) => (
          <SectionEditor
            key={section.id}
            section={section}
            index={idx}
            canDelete={cfg.sections.length > 1}
            onUpdate={(partial) => updateSection(section.id, partial)}
            onRemove={() => removeSection(section.id)}
            onMoveUp={() => moveSectionUp(idx)}
          />
        ))}
        <Button
          variant="outline"
          size="sm"
          className="w-full text-xs"
          onClick={addSection}
        >
          <Plus className="mr-1 h-3 w-3" />
          섹션 추가
        </Button>
      </TabsContent>

      <TabsContent value="save" className="mt-3 space-y-4">
        <SaveTabContent
          cfg={cfg}
          tables={tables}
          saveTableName={saveTableName}
          saveTableOpen={saveTableOpen}
          setSaveTableOpen={setSaveTableOpen}
          readTableOpen={readTableOpen}
          setReadTableOpen={setReadTableOpen}
          allFields={allFields}
          displayFields={displayFields}
          inputFields={inputFields}
          hasDisplayFields={hasDisplayFields}
          hasInputFields={hasInputFields}
          onSaveTableChange={handleSaveTableChange}
          onUpdateConfig={updateConfig}
        />
      </TabsContent>
    </Tabs>
  );
}

// ========================================
// SaveTabContent: 저장 탭 (필드 중심 순차 설정)
// 1. 테이블 설정 (읽기/저장 테이블 + PK)
// 2. 읽기 필드 매핑 (display 섹션)
// 3. 입력 필드 매핑 (input 섹션)
// ========================================

interface SaveTabContentProps {
  cfg: PopFieldConfig;
  tables: TableInfo[];
  saveTableName: string;
  saveTableOpen: boolean;
  setSaveTableOpen: (v: boolean) => void;
  readTableOpen: boolean;
  setReadTableOpen: (v: boolean) => void;
  allFields: { field: PopFieldItem; section: PopFieldSection }[];
  displayFields: { field: PopFieldItem; section: PopFieldSection }[];
  inputFields: { field: PopFieldItem; section: PopFieldSection }[];
  hasDisplayFields: boolean;
  hasInputFields: boolean;
  onSaveTableChange: (tableName: string) => void;
  onUpdateConfig: (partial: Partial<PopFieldConfig>) => void;
}

function SaveTabContent({
  cfg,
  tables,
  saveTableName,
  saveTableOpen,
  setSaveTableOpen,
  readTableOpen,
  setReadTableOpen,
  allFields,
  displayFields,
  inputFields,
  hasDisplayFields,
  hasInputFields,
  onSaveTableChange,
  onUpdateConfig,
}: SaveTabContentProps) {
  const [saveColumns, setSaveColumns] = useState<ColumnInfo[]>([]);
  const [readColumns, setReadColumns] = useState<ColumnInfo[]>([]);
  const [jsonKeysMap, setJsonKeysMap] = useState<Record<string, string[]>>({});

  useEffect(() => {
    if (saveTableName) {
      fetchTableColumns(saveTableName).then(setSaveColumns);
    } else {
      setSaveColumns([]);
    }
  }, [saveTableName]);

  const readTableName = cfg.readSource?.tableName ?? "";
  const readSameAsSave = readTableName === saveTableName && !!saveTableName;
  const readTableForFetch = readSameAsSave ? saveTableName : readTableName;

  useEffect(() => {
    if (readTableForFetch) {
      fetchTableColumns(readTableForFetch).then(setReadColumns);
    } else {
      setReadColumns([]);
    }
  }, [readTableForFetch]);

  const fetchJsonKeysForColumn = useCallback(
    async (tableName: string, columnName: string) => {
      const cacheKey = `${tableName}__${columnName}`;
      if (jsonKeysMap[cacheKey]) return;
      try {
        const result = await dataApi.getTableData(tableName, { page: 1, size: 1 });
        const row = result.data?.[0];
        if (!row || !row[columnName]) return;
        const raw = row[columnName];
        const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
        if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
          setJsonKeysMap((prev) => ({ ...prev, [cacheKey]: Object.keys(parsed).sort() }));
        }
      } catch {
        // JSON 파싱 실패 시 무시
      }
    },
    [jsonKeysMap]
  );

  const getJsonKeys = useCallback(
    (tableName: string, columnName: string): string[] => {
      return jsonKeysMap[`${tableName}__${columnName}`] ?? [];
    },
    [jsonKeysMap]
  );

  // --- 저장 매핑 로직 ---
  const saveMappings = cfg.saveConfig?.fieldMappings ?? [];

  const getSaveMappingForField = (fieldId: string): PopFieldSaveMapping => {
    return (
      saveMappings.find((x) => x.fieldId === fieldId) ?? {
        fieldId,
        valueSource: "direct",
        targetColumn: "",
      }
    );
  };

  const syncAndUpdateSaveMappings = useCallback(
    (updater?: (prev: PopFieldSaveMapping[]) => PopFieldSaveMapping[]) => {
      const fieldIds = new Set(allFields.map(({ field }) => field.id));
      const prev = saveMappings.filter((m) => fieldIds.has(m.fieldId));
      const next = updater ? updater(prev) : prev;
      const added = allFields.filter(
        ({ field }) => !next.some((m) => m.fieldId === field.id)
      );
      const merged: PopFieldSaveMapping[] = [
        ...next,
        ...added.map(({ field }) => ({
          fieldId: field.id,
          valueSource: "direct" as FieldValueSource,
          targetColumn: "",
        })),
      ];
      const structureChanged =
        merged.length !== saveMappings.length ||
        merged.some((m, i) => m.fieldId !== saveMappings[i]?.fieldId);
      if (updater || structureChanged) {
        onUpdateConfig({
          saveConfig: {
            ...cfg.saveConfig,
            tableName: saveTableName,
            fieldMappings: merged,
          },
        });
      }
    },
    [allFields, saveMappings, cfg.saveConfig, saveTableName, onUpdateConfig]
  );

  const fieldIdsKey = allFields.map(({ field }) => field.id).join(",");
  useEffect(() => {
    syncAndUpdateSaveMappings();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fieldIdsKey]);

  const updateSaveMapping = useCallback(
    (fieldId: string, partial: Partial<PopFieldSaveMapping>) => {
      syncAndUpdateSaveMappings((prev) =>
        prev.map((m) => (m.fieldId === fieldId ? { ...m, ...partial } : m))
      );
    },
    [syncAndUpdateSaveMappings]
  );

  // --- 숨은 필드 매핑 로직 ---
  const hiddenMappings = cfg.saveConfig?.hiddenMappings ?? [];

  const addHiddenMapping = useCallback(() => {
    const newMapping: PopFieldHiddenMapping = {
      id: `hidden_${Date.now()}`,
      valueSource: "db_column",
      targetColumn: "",
      label: "",
    };
    onUpdateConfig({
      saveConfig: {
        ...cfg.saveConfig,
        tableName: saveTableName,
        fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
        hiddenMappings: [...hiddenMappings, newMapping],
      },
    });
  }, [cfg.saveConfig, saveTableName, hiddenMappings, onUpdateConfig]);

  const updateHiddenMapping = useCallback(
    (id: string, partial: Partial<PopFieldHiddenMapping>) => {
      onUpdateConfig({
        saveConfig: {
          ...cfg.saveConfig,
          tableName: saveTableName,
          fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
          hiddenMappings: hiddenMappings.map((m) =>
            m.id === id ? { ...m, ...partial } : m
          ),
        },
      });
    },
    [cfg.saveConfig, saveTableName, hiddenMappings, onUpdateConfig]
  );

  const removeHiddenMapping = useCallback(
    (id: string) => {
      onUpdateConfig({
        saveConfig: {
          ...cfg.saveConfig,
          tableName: saveTableName,
          fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
          hiddenMappings: hiddenMappings.filter((m) => m.id !== id),
        },
      });
    },
    [cfg.saveConfig, saveTableName, hiddenMappings, onUpdateConfig]
  );

  // --- 레이아웃 auto 필드 감지 (입력 섹션에서 inputType=auto인 필드) ---
  const autoInputFields = useMemo(
    () => inputFields.filter(({ field }) => field.inputType === "auto"),
    [inputFields]
  );
  const regularInputFields = useMemo(
    () => inputFields.filter(({ field }) => field.inputType !== "auto"),
    [inputFields]
  );

  // --- 자동생성 필드 로직 ---
  const autoGenMappings = cfg.saveConfig?.autoGenMappings ?? [];
  const [numberingRules, setNumberingRules] = useState<{ ruleId: string; ruleName: string }[]>([]);

  // 레이아웃 auto 필드 → autoGenMappings 자동 동기화
  const autoFieldIdsKey = autoInputFields.map(({ field }) => field.id).join(",");
  useEffect(() => {
    if (autoInputFields.length === 0) return;
    const current = cfg.saveConfig?.autoGenMappings ?? [];
    const linkedIds = new Set(current.filter((m) => m.linkedFieldId).map((m) => m.linkedFieldId));
    const toAdd: PopFieldAutoGenMapping[] = [];
    for (const { field } of autoInputFields) {
      if (!linkedIds.has(field.id)) {
        toAdd.push({
          id: `autogen_linked_${field.id}`,
          linkedFieldId: field.id,
          label: field.labelText || "",
          targetColumn: "",
          numberingRuleId: field.autoNumber?.numberingRuleId ?? "",
          showInForm: true,
          showResultModal: true,
        });
      }
    }
    if (toAdd.length > 0) {
      onUpdateConfig({
        saveConfig: {
          ...cfg.saveConfig,
          tableName: saveTableName,
          fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
          autoGenMappings: [...current, ...toAdd],
        },
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoFieldIdsKey]);

  useEffect(() => {
    if (saveTableName) {
      getAvailableNumberingRulesForScreen(saveTableName)
        .then((res) => {
          if (res.success && Array.isArray(res.data)) {
            setNumberingRules(
              res.data.map((r: any) => ({
                ruleId: String(r.ruleId ?? r.rule_id ?? ""),
                ruleName: String(r.ruleName ?? r.rule_name ?? ""),
              }))
            );
          }
        })
        .catch(() => setNumberingRules([]));
    }
  }, [saveTableName]);

  const addAutoGenMapping = useCallback(() => {
    const newMapping: PopFieldAutoGenMapping = {
      id: `autogen_${Date.now()}`,
      label: "",
      targetColumn: "",
      numberingRuleId: "",
      showInForm: false,
      showResultModal: true,
    };
    onUpdateConfig({
      saveConfig: {
        ...cfg.saveConfig,
        tableName: saveTableName,
        fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
        autoGenMappings: [...autoGenMappings, newMapping],
      },
    });
  }, [cfg.saveConfig, saveTableName, autoGenMappings, onUpdateConfig]);

  const updateAutoGenMapping = useCallback(
    (id: string, partial: Partial<PopFieldAutoGenMapping>) => {
      onUpdateConfig({
        saveConfig: {
          ...cfg.saveConfig,
          tableName: saveTableName,
          fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
          autoGenMappings: autoGenMappings.map((m) =>
            m.id === id ? { ...m, ...partial } : m
          ),
        },
      });
    },
    [cfg.saveConfig, saveTableName, autoGenMappings, onUpdateConfig]
  );

  const removeAutoGenMapping = useCallback(
    (id: string) => {
      onUpdateConfig({
        saveConfig: {
          ...cfg.saveConfig,
          tableName: saveTableName,
          fieldMappings: cfg.saveConfig?.fieldMappings ?? [],
          autoGenMappings: autoGenMappings.filter((m) => m.id !== id),
        },
      });
    },
    [cfg.saveConfig, saveTableName, autoGenMappings, onUpdateConfig]
  );

  // --- 읽기 매핑 로직 ---
  const getReadMappingForField = (fieldId: string): PopFieldReadMapping => {
    return (
      cfg.readSource?.fieldMappings?.find((x) => x.fieldId === fieldId) ?? {
        fieldId,
        valueSource: "db_column",
        columnName: "",
      }
    );
  };

  const updateReadMapping = useCallback(
    (fieldId: string, partial: Partial<PopFieldReadMapping>) => {
      const prev = cfg.readSource?.fieldMappings ?? [];
      const next = prev.map((m) =>
        m.fieldId === fieldId ? { ...m, ...partial } : m
      );
      if (!next.some((m) => m.fieldId === fieldId)) {
        next.push({ fieldId, valueSource: "db_column", columnName: "", ...partial });
      }
      onUpdateConfig({
        readSource: {
          ...cfg.readSource,
          tableName: readTableName || saveTableName,
          pkColumn: cfg.readSource?.pkColumn ?? "",
          fieldMappings: next,
        },
      });
    },
    [cfg.readSource, readTableName, saveTableName, onUpdateConfig]
  );

  // --- 읽기 테이블 변경 ---
  const handleReadSameAsSaveChange = useCallback(
    (checked: boolean) => {
      onUpdateConfig({
        readSource: {
          tableName: checked ? saveTableName : "",
          pkColumn: checked ? (cfg.readSource?.pkColumn ?? "") : "",
          fieldMappings: cfg.readSource?.fieldMappings ?? [],
        },
      });
    },
    [saveTableName, cfg.readSource, onUpdateConfig]
  );

  const handleReadTableChange = useCallback(
    (tableName: string) => {
      onUpdateConfig({
        readSource: {
          ...cfg.readSource,
          tableName,
          pkColumn: cfg.readSource?.pkColumn ?? "",
          fieldMappings: cfg.readSource?.fieldMappings ?? [],
        },
      });
    },
    [cfg.readSource, onUpdateConfig]
  );

  const colName = (c: ColumnInfo) => c.name;

  const noFields = allFields.length === 0;

  const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});
  const toggleSection = useCallback((key: string) => {
    setCollapsed((prev) => ({ ...prev, [key]: !prev[key] }));
  }, []);

  return (
    <div className="space-y-4">
      {noFields && (
        <p className="rounded-md border bg-muted/30 px-3 py-4 text-center text-xs text-muted-foreground">
          레이아웃 탭에서 섹션과 필드를 먼저 추가해주세요.
        </p>
      )}

      {/* ── 1. 테이블 설정 ── */}
      {!noFields && (
        <div className="rounded-md border bg-card">
          <div
            className="flex cursor-pointer items-center gap-1.5 px-3 py-2"
            onClick={() => toggleSection("table")}
          >
            {collapsed["table"] ? (
              <ChevronRight className="h-3 w-3 text-muted-foreground" />
            ) : (
              <ChevronDown className="h-3 w-3 text-muted-foreground" />
            )}
            <span className="text-xs font-medium">테이블 설정</span>
          </div>
          {!collapsed["table"] && <div className="space-y-3 border-t p-3">
            {/* 읽기 테이블 (display 섹션이 있을 때만) */}
            {hasDisplayFields && (
              <>
                <div>
                  <Label className="text-[10px]">읽기 테이블</Label>
                  <div className="mt-1 flex items-center gap-2">
                    <div className="flex items-center gap-1.5">
                      <Switch
                        checked={readSameAsSave}
                        onCheckedChange={handleReadSameAsSaveChange}
                      />
                      <span className="text-[10px] text-muted-foreground">
                        저장과 동일
                      </span>
                    </div>
                  </div>
                  {!readSameAsSave && (
                    <Popover open={readTableOpen} onOpenChange={setReadTableOpen}>
                      <PopoverTrigger asChild>
                        <Button
                          variant="outline"
                          role="combobox"
                          className="mt-1 h-7 w-full justify-between text-xs"
                        >
                          {readTableName || "테이블 선택"}
                          <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                        </Button>
                      </PopoverTrigger>
                      <PopoverContent
                        className="p-0"
                        style={{ width: "var(--radix-popover-trigger-width)" }}
                        align="start"
                      >
                        <Command>
                          <CommandInput placeholder="테이블 검색..." className="text-xs" />
                          <CommandList>
                            <CommandEmpty className="text-xs">
                              테이블을 찾을 수 없습니다.
                            </CommandEmpty>
                            <CommandGroup>
                              {tables.map((t) => (
                                <CommandItem
                                  key={t.tableName}
                                  value={t.tableName}
                                  onSelect={(v) => {
                                    handleReadTableChange(v);
                                    setReadTableOpen(false);
                                  }}
                                  className="text-xs"
                                >
                                  <Check
                                    className={cn(
                                      "mr-2 h-3 w-3",
                                      readTableName === t.tableName ? "opacity-100" : "opacity-0"
                                    )}
                                  />
                                  {t.tableName}
                                </CommandItem>
                              ))}
                            </CommandGroup>
                          </CommandList>
                        </Command>
                      </PopoverContent>
                    </Popover>
                  )}
                </div>
                <div>
                  <Label className="text-[10px]">PK 컬럼</Label>
                  <Select
                    value={cfg.readSource?.pkColumn ?? ""}
                    onValueChange={(v) =>
                      onUpdateConfig({
                        readSource: {
                          ...cfg.readSource,
                          tableName: readTableName || saveTableName,
                          pkColumn: v,
                          fieldMappings: cfg.readSource?.fieldMappings ?? [],
                        },
                      })
                    }
                  >
                    <SelectTrigger className="mt-1 h-7 text-xs">
                      <SelectValue placeholder="PK 선택" />
                    </SelectTrigger>
                    <SelectContent>
                      {readColumns.map((c) => (
                        <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                          {colName(c)}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
              </>
            )}

            {/* 저장 테이블 */}
            {hasInputFields && (
              <div>
                <Label className="text-[10px]">저장 테이블</Label>
                <Popover open={saveTableOpen} onOpenChange={setSaveTableOpen}>
                  <PopoverTrigger asChild>
                    <Button
                      variant="outline"
                      role="combobox"
                      className="mt-1 h-7 w-full justify-between text-xs"
                    >
                      {saveTableName || "테이블 선택"}
                      <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
                    </Button>
                  </PopoverTrigger>
                  <PopoverContent
                    className="p-0"
                    style={{ width: "var(--radix-popover-trigger-width)" }}
                    align="start"
                  >
                    <Command>
                      <CommandInput placeholder="테이블 검색..." className="text-xs" />
                      <CommandList>
                        <CommandEmpty className="text-xs">
                          테이블을 찾을 수 없습니다.
                        </CommandEmpty>
                        <CommandGroup>
                          {tables.map((t) => (
                            <CommandItem
                              key={t.tableName}
                              value={t.tableName}
                              onSelect={(v) => {
                                onSaveTableChange(v === saveTableName ? "" : v);
                                setSaveTableOpen(false);
                              }}
                              className="text-xs"
                            >
                              <Check
                                className={cn(
                                  "mr-2 h-3 w-3",
                                  saveTableName === t.tableName ? "opacity-100" : "opacity-0"
                                )}
                              />
                              {t.tableName}
                              {t.displayName && t.displayName !== t.tableName && (
                                <span className="ml-1 text-muted-foreground">
                                  ({t.displayName})
                                </span>
                              )}
                            </CommandItem>
                          ))}
                        </CommandGroup>
                      </CommandList>
                    </Command>
                  </PopoverContent>
                </Popover>
              </div>
            )}
          </div>}
        </div>
      )}

      {/* ── 2. 읽기 필드 매핑 (display) ── */}
      {hasDisplayFields && (readTableForFetch || readSameAsSave) && (
        <div className="rounded-md border bg-card">
          <div
            className="flex cursor-pointer items-center gap-1.5 px-3 py-2"
            onClick={() => toggleSection("read")}
          >
            {collapsed["read"] ? (
              <ChevronRight className="h-3 w-3 text-muted-foreground" />
            ) : (
              <ChevronDown className="h-3 w-3 text-muted-foreground" />
            )}
            <span className="text-xs font-medium">읽기 필드</span>
            <span className="text-[10px] text-muted-foreground">
              (읽기 폼)
            </span>
          </div>
          {!collapsed["read"] && <div className="space-y-2 border-t p-3">
            {readColumns.length === 0 ? (
              <p className="py-2 text-xs text-muted-foreground">
                읽기 테이블의 컬럼을 불러오는 중...
              </p>
            ) : (
              displayFields.map(({ field }) => {
                const m = getReadMappingForField(field.id);
                const sm = getSaveMappingForField(field.id);
                const isJson = m.valueSource === "json_extract";
                return (
                  <div key={field.id} className="space-y-1">
                    <div className="flex items-center gap-2">
                      <span className="w-20 shrink-0 truncate text-xs font-medium">
                        {field.labelText || "(미설정)"}
                      </span>
                      <Select
                        value={m.valueSource === "direct" ? "db_column" : m.valueSource}
                        onValueChange={(v) =>
                          updateReadMapping(field.id, {
                            valueSource: v as FieldValueSource,
                            columnName: "",
                            jsonKey: undefined,
                          })
                        }
                      >
                        <SelectTrigger className="h-7 w-24 text-xs">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="db_column" className="text-xs">
                            DB 컬럼
                          </SelectItem>
                          <SelectItem value="json_extract" className="text-xs">
                            JSON
                          </SelectItem>
                        </SelectContent>
                      </Select>
                      {!isJson && (
                        <>
                          <span className="text-muted-foreground">←</span>
                          <Select
                            value={m.columnName || ""}
                            onValueChange={(v) =>
                              updateReadMapping(field.id, { columnName: v })
                            }
                          >
                            <SelectTrigger className="h-7 flex-1 text-xs">
                              <SelectValue placeholder="컬럼 선택" />
                            </SelectTrigger>
                            <SelectContent>
                              {readColumns.map((c) => (
                                <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                                  {colName(c)}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </>
                      )}
                    </div>
                    {isJson && (
                      <div className="ml-[88px] flex items-center gap-1">
                        <span className="text-muted-foreground">←</span>
                        <Select
                          value={m.columnName || ""}
                          onValueChange={(v) => {
                            updateReadMapping(field.id, { columnName: v, jsonKey: undefined });
                            if (readTableForFetch && v) {
                              fetchJsonKeysForColumn(readTableForFetch, v);
                            }
                          }}
                        >
                          <SelectTrigger className="h-7 flex-1 text-xs">
                            <SelectValue placeholder="JSON 컬럼" />
                          </SelectTrigger>
                          <SelectContent>
                            {readColumns.map((c) => (
                              <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                                {colName(c)}
                              </SelectItem>
                            ))}
                          </SelectContent>
                        </Select>
                        <span className="text-[10px] text-muted-foreground">.</span>
                        <JsonKeySelect
                          value={m.jsonKey ?? ""}
                          keys={readTableForFetch && m.columnName ? getJsonKeys(readTableForFetch, m.columnName) : []}
                          onValueChange={(v) => updateReadMapping(field.id, { jsonKey: v })}
                          onOpen={() => {
                            if (readTableForFetch && m.columnName) {
                              fetchJsonKeysForColumn(readTableForFetch, m.columnName);
                            }
                          }}
                        />
                      </div>
                    )}
                    {saveTableName && saveColumns.length > 0 && (
                      <div className="ml-[88px] flex items-center gap-1">
                        <span className="text-muted-foreground">→</span>
                        <Select
                          value={sm.targetColumn || "__none__"}
                          onValueChange={(v) =>
                            updateSaveMapping(field.id, {
                              targetColumn: v === "__none__" ? "" : v,
                            })
                          }
                        >
                          <SelectTrigger className="h-7 flex-1 text-xs">
                            <SelectValue placeholder="저장 컬럼" />
                          </SelectTrigger>
                          <SelectContent>
                            <SelectItem value="__none__" className="text-xs">
                              저장 안함
                            </SelectItem>
                            {saveColumns.map((c) => (
                              <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                                {colName(c)}
                              </SelectItem>
                            ))}
                          </SelectContent>
                        </Select>
                      </div>
                    )}
                  </div>
                );
              })
            )}
          </div>}
        </div>
      )}

      {/* ── 3. 입력 필드 매핑 (input, auto 타입 제외) ── */}
      {regularInputFields.length > 0 && saveTableName && (
        <div className="rounded-md border bg-card">
          <div
            className="flex cursor-pointer items-center gap-1.5 px-3 py-2"
            onClick={() => toggleSection("input")}
          >
            {collapsed["input"] ? (
              <ChevronRight className="h-3 w-3 text-muted-foreground" />
            ) : (
              <ChevronDown className="h-3 w-3 text-muted-foreground" />
            )}
            <span className="text-xs font-medium">입력 필드</span>
            <span className="text-[10px] text-muted-foreground">
              (입력 폼 → 저장)
            </span>
          </div>
          {!collapsed["input"] && <div className="space-y-2 border-t p-3">
            {saveColumns.length === 0 ? (
              <p className="py-2 text-xs text-muted-foreground">
                저장 테이블의 컬럼을 불러오는 중...
              </p>
            ) : (
              regularInputFields.map(({ field }) => {
                const m = getSaveMappingForField(field.id);
                return (
                  <div key={field.id} className="flex items-center gap-2">
                    <span className="w-20 shrink-0 truncate text-xs font-medium">
                      {field.labelText || "(미설정)"}
                    </span>
                    <span className="text-muted-foreground">→</span>
                    <Select
                      value={m.targetColumn || "__none__"}
                      onValueChange={(v) =>
                        updateSaveMapping(field.id, {
                          targetColumn: v === "__none__" ? "" : v,
                          valueSource: "direct",
                        })
                      }
                    >
                      <SelectTrigger className="h-7 flex-1 text-xs">
                        <SelectValue placeholder="저장 컬럼" />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="__none__" className="text-xs">
                          매핑 안함
                        </SelectItem>
                        {saveColumns.map((c) => (
                          <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                            {colName(c)}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                );
              })
            )}
          </div>}
        </div>
      )}

      {/* ── 4. 숨은 필드 매핑 (읽기 필드와 동일한 소스 구조) ── */}
      {saveTableName && (
        <div className="rounded-md border bg-card">
          <div
            className="flex cursor-pointer items-center gap-1.5 px-3 py-2"
            onClick={() => toggleSection("hidden")}
          >
            {collapsed["hidden"] ? (
              <ChevronRight className="h-3 w-3 text-muted-foreground" />
            ) : (
              <ChevronDown className="h-3 w-3 text-muted-foreground" />
            )}
            <span className="text-xs font-medium">숨은 필드</span>
            <span className="text-[10px] text-muted-foreground">
              (UI 미표시, 전달 데이터에서 추출하여 저장)
            </span>
          </div>
          {!collapsed["hidden"] && <div className="space-y-3 border-t p-3">
            {hiddenMappings.map((m) => {
              const isJson = m.valueSource === "json_extract";
              return (
                <div key={m.id} className="space-y-1.5 rounded border bg-background p-2">
                  <div className="flex items-center gap-2">
                    <Input
                      value={m.label || ""}
                      onChange={(e) => updateHiddenMapping(m.id, { label: e.target.value })}
                      placeholder="라벨 (관리용)"
                      className="h-7 flex-1 text-xs"
                    />
                    <Button
                      variant="ghost"
                      size="icon"
                      className="h-6 w-6 shrink-0 text-destructive"
                      onClick={() => removeHiddenMapping(m.id)}
                    >
                      <Trash2 className="h-3 w-3" />
                    </Button>
                  </div>
                  <div className="flex items-center gap-2">
                    <Select
                      value={m.valueSource || "db_column"}
                      onValueChange={(v) =>
                        updateHiddenMapping(m.id, {
                          valueSource: v as HiddenValueSource,
                          sourceDbColumn: undefined,
                          sourceJsonColumn: undefined,
                          sourceJsonKey: undefined,
                        })
                      }
                    >
                      <SelectTrigger className="h-7 w-24 text-xs">
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="db_column" className="text-xs">DB 컬럼</SelectItem>
                        <SelectItem value="json_extract" className="text-xs">JSON</SelectItem>
                      </SelectContent>
                    </Select>
                    {!isJson && (
                      <>
                        <Select
                          value={m.sourceDbColumn || "__none__"}
                          onValueChange={(v) =>
                            updateHiddenMapping(m.id, { sourceDbColumn: v === "__none__" ? "" : v })
                          }
                        >
                          <SelectTrigger className="h-7 flex-1 text-xs">
                            <SelectValue placeholder="소스 컬럼" />
                          </SelectTrigger>
                          <SelectContent>
                            <SelectItem value="__none__" className="text-xs">선택</SelectItem>
                            {readColumns.map((c) => (
                              <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                                {colName(c)}
                              </SelectItem>
                            ))}
                          </SelectContent>
                        </Select>
                      </>
                    )}
                  </div>
                  {isJson && (
                    <div className="flex items-center gap-1">
                      <Select
                        value={m.sourceJsonColumn || "__none__"}
                        onValueChange={(v) => {
                          const col = v === "__none__" ? "" : v;
                          updateHiddenMapping(m.id, { sourceJsonColumn: col, sourceJsonKey: "" });
                          if (readTableForFetch && col) {
                            fetchJsonKeysForColumn(readTableForFetch, col);
                          }
                        }}
                      >
                        <SelectTrigger className="h-7 flex-1 text-xs">
                          <SelectValue placeholder="JSON 컬럼" />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="__none__" className="text-xs">선택</SelectItem>
                          {readColumns.map((c) => (
                            <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                              {colName(c)}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                      <span className="text-[10px] text-muted-foreground">.</span>
                      <JsonKeySelect
                        value={m.sourceJsonKey ?? ""}
                        keys={readTableForFetch && m.sourceJsonColumn ? getJsonKeys(readTableForFetch, m.sourceJsonColumn) : []}
                        onValueChange={(v) => updateHiddenMapping(m.id, { sourceJsonKey: v })}
                        onOpen={() => {
                          if (readTableForFetch && m.sourceJsonColumn) {
                            fetchJsonKeysForColumn(readTableForFetch, m.sourceJsonColumn);
                          }
                        }}
                      />
                    </div>
                  )}
                  <div className="flex items-center gap-2">
                    <span className="text-muted-foreground">→</span>
                    <Select
                      value={m.targetColumn || "__none__"}
                      onValueChange={(v) =>
                        updateHiddenMapping(m.id, { targetColumn: v === "__none__" ? "" : v })
                      }
                    >
                      <SelectTrigger className="h-7 flex-1 text-xs">
                        <SelectValue placeholder="저장 컬럼" />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="__none__" className="text-xs">선택</SelectItem>
                        {saveColumns.map((c) => (
                          <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                            {colName(c)}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                </div>
              );
            })}
            <Button
              variant="outline"
              size="sm"
              className="w-full text-xs"
              onClick={addHiddenMapping}
            >
              <Plus className="mr-1 h-3 w-3" />
              숨은 필드 추가
            </Button>
          </div>}
        </div>
      )}

      {/* ── 5. 자동생성 필드 ── */}
      {saveTableName && (
        <div className="rounded-md border bg-card">
          <div
            className="flex cursor-pointer items-center gap-1.5 px-3 py-2"
            onClick={() => toggleSection("autogen")}
          >
            {collapsed["autogen"] ? (
              <ChevronRight className="h-3 w-3 text-muted-foreground" />
            ) : (
              <ChevronDown className="h-3 w-3 text-muted-foreground" />
            )}
            <span className="text-xs font-medium">자동생성 필드</span>
            <span className="text-[10px] text-muted-foreground">
              (저장 시 서버에서 채번)
            </span>
          </div>
          {!collapsed["autogen"] && <div className="space-y-3 border-t p-3">
            {autoGenMappings.map((m) => {
              const isLinked = !!m.linkedFieldId;
              return (
                <div key={m.id} className="space-y-2 rounded border bg-background p-2">
                  <div className="flex items-center gap-2">
                    {isLinked && (
                      <span className="shrink-0 rounded bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium text-primary">
                        레이아웃
                      </span>
                    )}
                    <Input
                      value={m.label}
                      onChange={(e) => updateAutoGenMapping(m.id, { label: e.target.value })}
                      placeholder="라벨 (예: 입고번호)"
                      className="h-7 flex-1 text-xs"
                      readOnly={isLinked}
                    />
                    {!isLinked && (
                      <Button
                        variant="ghost"
                        size="icon"
                        className="h-6 w-6 shrink-0 text-destructive"
                        onClick={() => removeAutoGenMapping(m.id)}
                      >
                        <Trash2 className="h-3 w-3" />
                      </Button>
                    )}
                  </div>
                  <div className="flex items-center gap-2">
                    <span className="text-muted-foreground">→</span>
                    <Select
                      value={m.targetColumn || "__none__"}
                      onValueChange={(v) =>
                        updateAutoGenMapping(m.id, { targetColumn: v === "__none__" ? "" : v })
                      }
                    >
                      <SelectTrigger className="h-7 flex-1 text-xs">
                        <SelectValue placeholder="저장 컬럼" />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="__none__" className="text-xs">
                          선택
                        </SelectItem>
                        {saveColumns.map((c) => (
                          <SelectItem key={colName(c)} value={colName(c)} className="text-xs">
                            {colName(c)}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                  <div>
                    <Label className="text-[10px]">채번 규칙</Label>
                    <Select
                      value={m.numberingRuleId || "__none__"}
                      onValueChange={(v) =>
                        updateAutoGenMapping(m.id, { numberingRuleId: v === "__none__" ? "" : v })
                      }
                    >
                      <SelectTrigger className="mt-0.5 h-7 text-xs">
                        <SelectValue placeholder="채번 규칙 선택" />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="__none__" className="text-xs">
                          선택
                        </SelectItem>
                        {numberingRules.map((r) => (
                          <SelectItem key={r.ruleId} value={r.ruleId} className="text-xs">
                            {r.ruleName || r.ruleId}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                  <div className="flex items-center gap-4">
                    {!isLinked && (
                      <div className="flex items-center gap-1.5">
                        <Switch
                          checked={m.showInForm}
                          onCheckedChange={(v) => updateAutoGenMapping(m.id, { showInForm: v })}
                        />
                        <Label className="text-[10px]">필드 표시</Label>
                      </div>
                    )}
                    <div className="flex items-center gap-1.5">
                      <Switch
                        checked={m.showResultModal}
                        onCheckedChange={(v) => updateAutoGenMapping(m.id, { showResultModal: v })}
                      />
                      <Label className="text-[10px]">결과 모달</Label>
                    </div>
                  </div>
                </div>
              );
            })}
            <Button
              variant="outline"
              size="sm"
              className="w-full text-xs"
              onClick={addAutoGenMapping}
            >
              <Plus className="mr-1 h-3 w-3" />
              자동생성 필드 추가
            </Button>
          </div>}
        </div>
      )}

      {/* 저장 테이블 미선택 안내 */}
      {(regularInputFields.length > 0 || autoInputFields.length > 0) && !saveTableName && !noFields && (
        <p className="rounded-md border bg-muted/30 px-3 py-3 text-center text-xs text-muted-foreground">
          저장 테이블을 선택하면 입력 필드 매핑이 표시됩니다.
        </p>
      )}
    </div>
  );
}

// ========================================
// SectionEditor: 섹션 단위 편집
// ========================================

interface SectionEditorProps {
  section: PopFieldSection;
  index: number;
  canDelete: boolean;
  onUpdate: (partial: Partial<PopFieldSection>) => void;
  onRemove: () => void;
  onMoveUp: () => void;
}

function migrateStyle(style: string): FieldSectionStyle {
  if (style === "display" || style === "input") return style;
  if (style === "summary") return "display";
  if (style === "form") return "input";
  return "input";
}

function SectionEditor({
  section,
  index,
  canDelete,
  onUpdate,
  onRemove,
  onMoveUp,
}: SectionEditorProps) {
  const [collapsed, setCollapsed] = useState(false);
  const resolvedStyle = migrateStyle(section.style);

  const sectionFields = section.fields || [];

  const updateField = useCallback(
    (fieldId: string, partial: Partial<PopFieldItem>) => {
      const fields = sectionFields.map((f) =>
        f.id === fieldId ? { ...f, ...partial } : f
      );
      onUpdate({ fields });
    },
    [sectionFields, onUpdate]
  );

  const addField = useCallback(() => {
    const fieldId = `field_${Date.now()}`;
    const newField: PopFieldItem = {
      id: fieldId,
      inputType: "text",
      fieldName: fieldId,
      labelText: "",
      readOnly: false,
    };
    onUpdate({ fields: [...sectionFields, newField] });
  }, [sectionFields, onUpdate]);

  const removeField = useCallback(
    (fieldId: string) => {
      onUpdate({ fields: sectionFields.filter((f) => f.id !== fieldId) });
    },
    [sectionFields, onUpdate]
  );

  return (
    <div className="rounded-md border bg-card">
      {/* 섹션 헤더 */}
      <div
        className="flex cursor-pointer items-center gap-2 px-3 py-2"
        onClick={() => setCollapsed(!collapsed)}
      >
        {collapsed ? (
          <ChevronRight className="h-3 w-3 text-muted-foreground" />
        ) : (
          <ChevronDown className="h-3 w-3 text-muted-foreground" />
        )}
        <span className="flex-1 text-xs font-medium">
          섹션 {index + 1}
          {section.label && ` - ${section.label}`}
        </span>
        {index > 0 && (
          <Button
            variant="ghost"
            size="icon"
            className="h-5 w-5"
            onClick={(e) => {
              e.stopPropagation();
              onMoveUp();
            }}
          >
            <GripVertical className="h-3 w-3" />
          </Button>
        )}
        {canDelete && (
          <Button
            variant="ghost"
            size="icon"
            className="h-5 w-5 text-destructive"
            onClick={(e) => {
              e.stopPropagation();
              onRemove();
            }}
          >
            <Trash2 className="h-3 w-3" />
          </Button>
        )}
      </div>

      {!collapsed && (
        <div className="space-y-3 border-t px-3 py-3">
          {/* 섹션 라벨 */}
          <div>
            <Label className="text-xs">섹션 라벨</Label>
            <Input
              value={section.label || ""}
              onChange={(e) => onUpdate({ label: e.target.value })}
              placeholder="선택사항"
              className="mt-1 h-7 text-xs"
            />
          </div>

          {/* 스타일 + 열 수 (가로 배치) */}
          <div className="grid grid-cols-2 gap-2">
            <div>
              <Label className="text-xs">스타일</Label>
              <Select
                value={resolvedStyle}
                onValueChange={(v) =>
                  onUpdate({ style: v as FieldSectionStyle })
                }
              >
                <SelectTrigger className="mt-1 h-7 text-xs">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {(
                    Object.entries(FIELD_SECTION_STYLE_LABELS) as [
                      FieldSectionStyle,
                      string,
                    ][]
                  ).map(([val, label]) => (
                    <SelectItem key={val} value={val} className="text-xs">
                      {label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div>
              <Label className="text-xs">열 수</Label>
              <Select
                value={String(section.columns)}
                onValueChange={(v) =>
                  onUpdate({
                    columns: v === "auto" ? "auto" : (Number(v) as 1 | 2 | 3 | 4),
                  })
                }
              >
                <SelectTrigger className="mt-1 h-7 text-xs">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="auto" className="text-xs">
                    자동
                  </SelectItem>
                  <SelectItem value="1" className="text-xs">
                    1열
                  </SelectItem>
                  <SelectItem value="2" className="text-xs">
                    2열
                  </SelectItem>
                  <SelectItem value="3" className="text-xs">
                    3열
                  </SelectItem>
                  <SelectItem value="4" className="text-xs">
                    4열
                  </SelectItem>
                </SelectContent>
              </Select>
            </div>
          </div>

          {/* 라벨 표시 토글 */}
          <div className="flex items-center justify-between">
            <Label className="text-xs">라벨 표시</Label>
            <Switch
              checked={section.showLabels}
              onCheckedChange={(v) => onUpdate({ showLabels: v })}
            />
          </div>

          {/* 커스텀 색상 */}
          <AppearanceEditor
            style={resolvedStyle}
            appearance={section.appearance}
            onUpdate={(appearance) => onUpdate({ appearance })}
          />

          {/* 필드 목록 */}
          <div className="space-y-2">
            <Label className="text-xs text-muted-foreground">
              필드 ({sectionFields.length})
            </Label>
            {sectionFields.map((field) => (
              <FieldItemEditor
                key={field.id}
                field={field}
                sectionStyle={resolvedStyle}
                onUpdate={(partial) => updateField(field.id, partial)}
                onRemove={() => removeField(field.id)}
              />
            ))}
            <Button
              variant="outline"
              size="sm"
              className="w-full text-xs"
              onClick={addField}
            >
              <Plus className="mr-1 h-3 w-3" />
              필드 추가
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}

// ========================================
// FieldItemEditor: 필드 단위 편집
// ========================================

interface FieldItemEditorProps {
  field: PopFieldItem;
  sectionStyle?: FieldSectionStyle;
  onUpdate: (partial: Partial<PopFieldItem>) => void;
  onRemove: () => void;
}

function FieldItemEditor({
  field,
  sectionStyle,
  onUpdate,
  onRemove,
}: FieldItemEditorProps) {
  const isDisplay = sectionStyle === "display";
  const [expanded, setExpanded] = useState(false);

  return (
    <div className="rounded border bg-background">
      {/* 필드 헤더 */}
      <div
        className="flex cursor-pointer items-center gap-2 px-2 py-1.5"
        onClick={() => setExpanded(!expanded)}
      >
        {expanded ? (
          <ChevronDown className="h-3 w-3 text-muted-foreground" />
        ) : (
          <ChevronRight className="h-3 w-3 text-muted-foreground" />
        )}
        <span className="flex-1 truncate text-xs">
          {field.labelText || "(미설정)"}
          <span className="ml-1 text-muted-foreground">
            [{FIELD_INPUT_TYPE_LABELS[field.inputType]}]
          </span>
          {field.readOnly && (
            <span className="ml-1 text-amber-500">(읽기전용)</span>
          )}
        </span>
        <Button
          variant="ghost"
          size="icon"
          className="h-5 w-5 text-destructive"
          onClick={(e) => {
            e.stopPropagation();
            onRemove();
          }}
        >
          <Trash2 className="h-3 w-3" />
        </Button>
      </div>

      {expanded && (
        <div className="space-y-2 border-t px-2 py-2">
          {/* 라벨 + 타입 */}
          <div className="grid grid-cols-2 gap-2">
            <div>
              <Label className="text-[10px]">라벨</Label>
              <Input
                value={field.labelText || ""}
                onChange={(e) => onUpdate({ labelText: e.target.value })}
                placeholder="표시 라벨"
                className="mt-0.5 h-7 text-xs"
              />
            </div>
            <div>
              <Label className="text-[10px]">타입</Label>
              <Select
                value={field.inputType}
                onValueChange={(v) =>
                  onUpdate({ inputType: v as FieldInputType })
                }
              >
                <SelectTrigger className="mt-0.5 h-7 text-xs">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {(
                    Object.entries(FIELD_INPUT_TYPE_LABELS) as [
                      FieldInputType,
                      string,
                    ][]
                  ).map(([val, label]) => (
                    <SelectItem key={val} value={val} className="text-xs">
                      {label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>

          {/* 플레이스홀더 */}
          <div>
            <Label className="text-[10px]">플레이스홀더</Label>
            <Input
              value={field.placeholder || ""}
              onChange={(e) => onUpdate({ placeholder: e.target.value })}
              placeholder="힌트 텍스트"
              className="mt-0.5 h-7 text-xs"
            />
          </div>

          {/* 읽기전용 + 필수 (입력 폼에서만 표시) */}
          {!isDisplay && (
            <div className="flex items-center gap-4">
              <div className="flex items-center gap-1.5">
                <Switch
                  checked={field.readOnly || false}
                  onCheckedChange={(v) => onUpdate({ readOnly: v })}
                />
                <Label className="text-[10px]">읽기전용</Label>
              </div>
              <div className="flex items-center gap-1.5">
                <Switch
                  checked={field.validation?.required || false}
                  onCheckedChange={(v) =>
                    onUpdate({
                      validation: { ...field.validation, required: v },
                    })
                  }
                />
                <Label className="text-[10px]">필수</Label>
              </div>
            </div>
          )}

          {/* 단위 (number, numpad) */}
          {(field.inputType === "number" || field.inputType === "numpad") && (
            <div>
              <Label className="text-[10px]">단위</Label>
              <Input
                value={field.unit || ""}
                onChange={(e) => onUpdate({ unit: e.target.value })}
                placeholder="EA, KG 등"
                className="mt-0.5 h-7 text-xs"
              />
            </div>
          )}

          {/* select 전용: 옵션 소스 */}
          {field.inputType === "select" && (
            <SelectSourceEditor
              source={field.selectSource}
              onUpdate={(source) => onUpdate({ selectSource: source })}
            />
          )}

          {/* auto 전용: 채번 설정 */}
          {field.inputType === "auto" && (
            <AutoNumberEditor
              config={field.autoNumber}
              onUpdate={(autoNumber) => onUpdate({ autoNumber })}
            />
          )}
        </div>
      )}
    </div>
  );
}

// ========================================
// SelectSourceEditor: select 옵션 소스 편집
// ========================================

function SelectSourceEditor({
  source,
  onUpdate,
}: {
  source?: FieldSelectSource;
  onUpdate: (source: FieldSelectSource) => void;
}) {
  const current: FieldSelectSource = source || {
    type: "static",
    staticOptions: [],
  };

  return (
    <div className="space-y-2 rounded border bg-muted/30 p-2">
      <Label className="text-[10px] text-muted-foreground">옵션 소스</Label>

      <Select
        value={current.type}
        onValueChange={(v) =>
          onUpdate({ ...current, type: v as "static" | "table" })
        }
      >
        <SelectTrigger className="h-7 text-xs">
          <SelectValue />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="static" className="text-xs">
            직접 입력
          </SelectItem>
          <SelectItem value="table" className="text-xs">
            테이블 조회
          </SelectItem>
        </SelectContent>
      </Select>

      {current.type === "static" && (
        <StaticOptionsEditor
          options={current.staticOptions || []}
          onUpdate={(opts) => onUpdate({ ...current, staticOptions: opts })}
        />
      )}

      {current.type === "table" && (
        <TableSourceEditor
          source={current}
          onUpdate={(partial) => onUpdate({ ...current, ...partial })}
        />
      )}
    </div>
  );
}

// ========================================
// StaticOptionsEditor: 정적 옵션 CRUD
// ========================================

function StaticOptionsEditor({
  options,
  onUpdate,
}: {
  options: { value: string; label: string }[];
  onUpdate: (options: { value: string; label: string }[]) => void;
}) {
  return (
    <div className="space-y-1">
      {options.map((opt, idx) => (
        <div key={idx} className="flex items-center gap-1">
          <Input
            value={opt.value}
            onChange={(e) => {
              const next = [...options];
              next[idx] = { ...opt, value: e.target.value };
              onUpdate(next);
            }}
            placeholder="값"
            className="h-6 flex-1 text-[10px]"
          />
          <Input
            value={opt.label}
            onChange={(e) => {
              const next = [...options];
              next[idx] = { ...opt, label: e.target.value };
              onUpdate(next);
            }}
            placeholder="표시"
            className="h-6 flex-1 text-[10px]"
          />
          <Button
            variant="ghost"
            size="icon"
            className="h-5 w-5 text-destructive"
            onClick={() => onUpdate(options.filter((_, i) => i !== idx))}
          >
            <Trash2 className="h-3 w-3" />
          </Button>
        </div>
      ))}
      <Button
        variant="outline"
        size="sm"
        className="h-6 w-full text-[10px]"
        onClick={() => onUpdate([...options, { value: "", label: "" }])}
      >
        <Plus className="mr-1 h-3 w-3" />
        옵션 추가
      </Button>
    </div>
  );
}

// ========================================
// TableSourceEditor: 테이블 소스 설정
// ========================================

function TableSourceEditor({
  source,
  onUpdate,
}: {
  source: FieldSelectSource;
  onUpdate: (partial: Partial<FieldSelectSource>) => void;
}) {
  const [tables, setTables] = useState<TableInfo[]>([]);
  const [columns, setColumns] = useState<ColumnInfo[]>([]);
  const [tblOpen, setTblOpen] = useState(false);

  useEffect(() => {
    fetchTableList().then(setTables);
  }, []);

  useEffect(() => {
    if (source.tableName) {
      fetchTableColumns(source.tableName).then(setColumns);
    } else {
      setColumns([]);
    }
  }, [source.tableName]);

  return (
    <div className="space-y-2">
      {/* 테이블 Combobox */}
      <Popover open={tblOpen} onOpenChange={setTblOpen}>
        <PopoverTrigger asChild>
          <Button
            variant="outline"
            role="combobox"
            className="h-7 w-full justify-between text-xs"
          >
            {source.tableName || "테이블 선택"}
            <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0 opacity-50" />
          </Button>
        </PopoverTrigger>
        <PopoverContent
          className="p-0"
          style={{ width: "var(--radix-popover-trigger-width)" }}
          align="start"
        >
          <Command>
            <CommandInput placeholder="테이블 검색..." className="text-xs" />
            <CommandList>
              <CommandEmpty className="text-xs">
                테이블을 찾을 수 없습니다.
              </CommandEmpty>
              <CommandGroup>
                {tables.map((t) => (
                  <CommandItem
                    key={t.tableName}
                    value={t.tableName}
                    onSelect={(v) => {
                      onUpdate({ tableName: v });
                      setTblOpen(false);
                    }}
                    className="text-xs"
                  >
                    <Check
                      className={cn(
                        "mr-2 h-3 w-3",
                        source.tableName === t.tableName
                          ? "opacity-100"
                          : "opacity-0"
                      )}
                    />
                    {t.tableName}
                  </CommandItem>
                ))}
              </CommandGroup>
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>

      {/* 값 컬럼 / 라벨 컬럼 */}
      <div className="grid grid-cols-2 gap-1">
        <div>
          <Label className="text-[10px]">값 컬럼</Label>
          <Select
            value={source.valueColumn || ""}
            onValueChange={(v) => onUpdate({ valueColumn: v })}
          >
            <SelectTrigger className="mt-0.5 h-7 text-xs">
              <SelectValue placeholder="선택" />
            </SelectTrigger>
            <SelectContent>
              {columns.map((c) => (
                <SelectItem
                  key={c.name}
                  value={c.name}
                  className="text-xs"
                >
                  {c.name}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div>
          <Label className="text-[10px]">라벨 컬럼</Label>
          <Select
            value={source.labelColumn || ""}
            onValueChange={(v) => onUpdate({ labelColumn: v })}
          >
            <SelectTrigger className="mt-0.5 h-7 text-xs">
              <SelectValue placeholder="선택" />
            </SelectTrigger>
            <SelectContent>
              {columns.map((c) => (
                <SelectItem
                  key={c.name}
                  value={c.name}
                  className="text-xs"
                >
                  {c.name}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>
    </div>
  );
}

// ========================================
// AutoNumberEditor: 자동 채번 설정
// ========================================

function AutoNumberEditor({
  config,
  onUpdate,
}: {
  config?: AutoNumberConfig;
  onUpdate: (config: AutoNumberConfig) => void;
}) {
  const current: AutoNumberConfig = config || {
    prefix: "",
    dateFormat: "YYYYMMDD",
    separator: "-",
    sequenceDigits: 3,
  };

  return (
    <div className="space-y-2 rounded border bg-muted/30 p-2">
      <Label className="text-[10px] text-muted-foreground">자동 채번 설정</Label>

      <div className="grid grid-cols-2 gap-2">
        <div>
          <Label className="text-[10px]">접두사</Label>
          <Input
            value={current.prefix || ""}
            onChange={(e) => onUpdate({ ...current, prefix: e.target.value })}
            placeholder="IN-"
            className="mt-0.5 h-7 text-xs"
          />
        </div>
        <div>
          <Label className="text-[10px]">날짜 형식</Label>
          <Select
            value={current.dateFormat || "YYYYMMDD"}
            onValueChange={(v) => onUpdate({ ...current, dateFormat: v })}
          >
            <SelectTrigger className="mt-0.5 h-7 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="YYYYMMDD" className="text-xs">
                YYYYMMDD
              </SelectItem>
              <SelectItem value="YYMMDD" className="text-xs">
                YYMMDD
              </SelectItem>
              <SelectItem value="YYMM" className="text-xs">
                YYMM
              </SelectItem>
            </SelectContent>
          </Select>
        </div>
      </div>

      <div className="grid grid-cols-2 gap-2">
        <div>
          <Label className="text-[10px]">구분자</Label>
          <Input
            value={current.separator || ""}
            onChange={(e) => onUpdate({ ...current, separator: e.target.value })}
            placeholder="-"
            className="mt-0.5 h-7 text-xs"
          />
        </div>
        <div>
          <Label className="text-[10px]">시퀀스 자릿수</Label>
          <Input
            type="number"
            value={current.sequenceDigits || 3}
            onChange={(e) =>
              onUpdate({
                ...current,
                sequenceDigits: Number(e.target.value) || 3,
              })
            }
            min={1}
            max={10}
            className="mt-0.5 h-7 text-xs"
          />
        </div>
      </div>

      {/* 미리보기 */}
      <div className="text-[10px] text-muted-foreground">
        미리보기:{" "}
        <span className="font-mono">
          {current.prefix || ""}
          {current.separator || ""}
          {current.dateFormat === "YYMM"
            ? "2602"
            : current.dateFormat === "YYMMDD"
              ? "260226"
              : "20260226"}
          {current.separator || ""}
          {"0".repeat(current.sequenceDigits || 3).slice(0, -1)}1
        </span>
      </div>
    </div>
  );
}

// ========================================
// JsonKeySelect: JSON 키 드롭다운 (자동 추출)
// ========================================

function JsonKeySelect({
  value,
  keys,
  onValueChange,
  onOpen,
}: {
  value: string;
  keys: string[];
  onValueChange: (v: string) => void;
  onOpen?: () => void;
}) {
  const [open, setOpen] = useState(false);

  const handleOpenChange = (nextOpen: boolean) => {
    setOpen(nextOpen);
    if (nextOpen) onOpen?.();
  };

  if (keys.length === 0 && !value) {
    return (
      <Input
        placeholder="키"
        value={value}
        onChange={(e) => onValueChange(e.target.value)}
        onFocus={() => onOpen?.()}
        className="h-7 w-24 text-xs"
      />
    );
  }

  return (
    <Popover open={open} onOpenChange={handleOpenChange}>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          role="combobox"
          className="h-7 w-24 justify-between text-xs"
        >
          <span className="truncate">{value || "키 선택"}</span>
          <ChevronsUpDown className="ml-1 h-3 w-3 shrink-0 opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-48 p-0" align="start">
        <Command>
          <CommandInput placeholder="키 검색..." className="text-xs" />
          <CommandList>
            <CommandEmpty className="py-2 text-center text-xs">
              {keys.length === 0 ? "데이터를 불러오는 중..." : "일치하는 키가 없습니다."}
            </CommandEmpty>
            <CommandGroup>
              {keys.map((k) => (
                <CommandItem
                  key={k}
                  value={k}
                  onSelect={(v) => {
                    onValueChange(v === value ? "" : v);
                    setOpen(false);
                  }}
                  className="text-xs"
                >
                  <Check
                    className={cn(
                      "mr-2 h-3 w-3",
                      value === k ? "opacity-100" : "opacity-0"
                    )}
                  />
                  {k}
                </CommandItem>
              ))}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  );
}

// ========================================
// AppearanceEditor: 섹션 외관 설정
// ========================================

const BG_COLOR_OPTIONS = [
  { value: "__default__", label: "기본" },
  { value: "bg-emerald-50", label: "초록" },
  { value: "bg-primary/10", label: "파랑" },
  { value: "bg-amber-50", label: "노랑" },
  { value: "bg-rose-50", label: "빨강" },
  { value: "bg-purple-50", label: "보라" },
  { value: "bg-muted", label: "회색" },
] as const;

const BORDER_COLOR_OPTIONS = [
  { value: "__default__", label: "기본" },
  { value: "border-emerald-200", label: "초록" },
  { value: "border-primary/20", label: "파랑" },
  { value: "border-amber-200", label: "노랑" },
  { value: "border-rose-200", label: "빨강" },
  { value: "border-purple-200", label: "보라" },
  { value: "border-border", label: "회색" },
] as const;

function AppearanceEditor({
  style,
  appearance,
  onUpdate,
}: {
  style: FieldSectionStyle;
  appearance?: FieldSectionAppearance;
  onUpdate: (appearance: FieldSectionAppearance) => void;
}) {
  const defaults = DEFAULT_SECTION_APPEARANCES[style];
  const current = appearance || {};

  return (
    <div className="space-y-2">
      <Label className="text-xs text-muted-foreground">외관 설정</Label>
      <div className="grid grid-cols-2 gap-2">
        <div>
          <Label className="text-[10px]">배경색</Label>
          <Select
            value={current.bgColor || "__default__"}
            onValueChange={(v) => onUpdate({ ...current, bgColor: v === "__default__" ? undefined : v })}
          >
            <SelectTrigger className="mt-0.5 h-7 text-xs">
              <SelectValue placeholder={defaults.bgColor} />
            </SelectTrigger>
            <SelectContent>
              {BG_COLOR_OPTIONS.map((opt) => (
                <SelectItem key={opt.value} value={opt.value} className="text-xs">
                  <span className="flex items-center gap-1.5">
                    {opt.value !== "__default__" && <span className={cn("inline-block h-3 w-3 rounded-sm border", opt.value)} />}
                    {opt.label}
                  </span>
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div>
          <Label className="text-[10px]">테두리색</Label>
          <Select
            value={current.borderColor || "__default__"}
            onValueChange={(v) => onUpdate({ ...current, borderColor: v === "__default__" ? undefined : v })}
          >
            <SelectTrigger className="mt-0.5 h-7 text-xs">
              <SelectValue placeholder={defaults.borderColor} />
            </SelectTrigger>
            <SelectContent>
              {BORDER_COLOR_OPTIONS.map((opt) => (
                <SelectItem key={opt.value} value={opt.value} className="text-xs">
                  <span className="flex items-center gap-1.5">
                    {opt.value !== "__default__" && <span className={cn("inline-block h-3 w-3 rounded-sm border-2", opt.value)} />}
                    {opt.label}
                  </span>
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>
    </div>
  );
}
