"use client";

import React, { useState, useEffect, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog";
import {
  Plus, Trash2, Save, Loader2, Pencil, Cpu, Settings2, Search, Inbox,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";
import { useAuth } from "@/hooks/useAuth";
import { useTableSettings } from "@/hooks/useTableSettings";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";
import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable";
import { toast } from "sonner";
import { useConfirmDialog } from "@/components/common/ConfirmDialog";

/* ───── 테이블명 ───── */
const DATATYPE_TABLE = "plc_data_type";

const DATATYPE_COLUMNS = [
  { key: "equipment_code", label: "설비코드" },
  { key: "data_type", label: "데이터타입" },
  { key: "unit", label: "단위" },
  { key: "tag_address", label: "태그주소" },
  { key: "collection_interval", label: "수집주기" },
  { key: "lower_limit", label: "하한값" },
  { key: "upper_limit", label: "상한값" },
  { key: "is_active", label: "사용여부" },
];
const COLLECTION_TABLE = "plc_collection_config";
const EQUIPMENT_TABLE = "equipment_mng";

/* ───── Cron 한글 변환 ───── */
const cronToKorean = (cron: string): string => {
  if (!cron) return "";
  const parts = cron.trim().split(/\s+/);
  if (parts.length < 5) return cron;
  const [min, hour] = parts;
  if (min === "*" && hour === "*") return "매 분마다";
  if (min !== "*" && hour === "*") return `매시 ${min}분마다`;
  if (min === "0" && hour !== "*") return `매일 ${hour}시 정각`;
  if (min === "*/5") return "5분마다";
  if (min === "*/10") return "10분마다";
  if (min === "*/30") return "30분마다";
  return cron;
};

/* ───── 카테고리 flatten ───── */
const flattenCategories = (vals: any[]): { code: string; label: string }[] => {
  const result: { code: string; label: string }[] = [];
  for (const v of vals) {
    result.push({ code: v.valueCode, label: v.valueLabel });
    if (v.children?.length) result.push(...flattenCategories(v.children));
  }
  return result;
};

export default function PlcSettingsPage() {
  const { user } = useAuth();
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();
  const ts = useTableSettings("c16-plc-settings", DATATYPE_TABLE, DATATYPE_COLUMNS);

  const [activeTab, setActiveTab] = useState("datatype");

  /* ───── PLC 데이터타입 ───── */
  const [datatypes, setDatatypes] = useState<any[]>([]);
  const [dtLoading, setDtLoading] = useState(false);
  const [dtCount, setDtCount] = useState(0);
  const [dtChecked, setDtChecked] = useState<string[]>([]);
  const [dtModalOpen, setDtModalOpen] = useState(false);
  const [dtEditMode, setDtEditMode] = useState(false);
  const [dtForm, setDtForm] = useState<Record<string, any>>({});
  const [dtSaving, setDtSaving] = useState(false);
  const [dtKeyword, setDtKeyword] = useState("");

  /* ───── 수집 설정 ───── */
  const [configs, setConfigs] = useState<any[]>([]);
  const [cfgLoading, setCfgLoading] = useState(false);
  const [cfgCount, setCfgCount] = useState(0);
  const [cfgChecked, setCfgChecked] = useState<string[]>([]);
  const [cfgModalOpen, setCfgModalOpen] = useState(false);
  const [cfgEditMode, setCfgEditMode] = useState(false);
  const [cfgForm, setCfgForm] = useState<Record<string, any>>({});
  const [cfgSaving, setCfgSaving] = useState(false);
  const [cfgKeyword, setCfgKeyword] = useState("");

  /* ───── FK + 카테고리 옵션 ───── */
  const [equipOptions, setEquipOptions] = useState<{ code: string; label: string }[]>([]);
  const [collectionTypeOptions, setCollectionTypeOptions] = useState<{ code: string; label: string }[]>([]);

  useEffect(() => {
    const load = async () => {
      try {
        const eqRes = await apiClient.post(`/table-management/tables/${EQUIPMENT_TABLE}/data`, { page: 1, size: 0, autoFilter: true });
        const eqs = eqRes.data?.data?.data || eqRes.data?.data?.rows || [];
        setEquipOptions(eqs.map((r: any) => ({ code: r.equipment_code, label: `${r.equipment_code} - ${r.equipment_name || ""}` })));
      } catch { /* skip */ }
      try {
        const catRes = await apiClient.get(`/table-categories/${COLLECTION_TABLE}/collection_type/values`);
        if (catRes.data?.data?.length > 0) {
          setCollectionTypeOptions(flattenCategories(catRes.data.data));
        }
      } catch { /* skip */ }
    };
    load();
  }, []);

  /* ═══════════════════ 데이터 조회 ═══════════════════ */
  const fetchDatatypes = useCallback(async (keyword?: string) => {
    setDtLoading(true);
    try {
      const kw = keyword !== undefined ? keyword : dtKeyword;
      const filters: any[] = [];
      if (kw.trim()) filters.push({ columnName: "equipment_code", operator: "contains", value: kw.trim() });
      const res = await apiClient.post(`/table-management/tables/${DATATYPE_TABLE}/data`, {
        page: 1, size: 0,
        dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
        autoFilter: true,
      });
      const rows = res.data?.data?.data || res.data?.data?.rows || [];
      setDatatypes(rows);
      setDtCount(rows.length);
    } catch { toast.error("PLC 데이터타입 조회에 실패했어요"); }
    finally { setDtLoading(false); }
  }, [dtKeyword]);

  const fetchConfigs = useCallback(async (keyword?: string) => {
    setCfgLoading(true);
    try {
      const kw = keyword !== undefined ? keyword : cfgKeyword;
      const filters: any[] = [];
      if (kw.trim()) filters.push({ columnName: "config_name", operator: "contains", value: kw.trim() });
      const res = await apiClient.post(`/table-management/tables/${COLLECTION_TABLE}/data`, {
        page: 1, size: 0,
        dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
        autoFilter: true,
      });
      const rows = res.data?.data?.data || res.data?.data?.rows || [];
      setConfigs(rows);
      setCfgCount(rows.length);
    } catch { toast.error("수집 설정 조회에 실패했어요"); }
    finally { setCfgLoading(false); }
  }, [cfgKeyword]);

  useEffect(() => { fetchDatatypes(); fetchConfigs(); }, []);

  /* ═══════════════════ 데이터타입 CRUD ═══════════════════ */
  const openDtCreate = () => { setDtForm({}); setDtEditMode(false); setDtModalOpen(true); };
  const openDtEdit = (row: any) => { setDtForm({ ...row }); setDtEditMode(true); setDtModalOpen(true); };
  const saveDt = async () => {
    if (!dtForm.equipment_code) { toast.error("설비코드는 필수 입력이에요"); return; }
    setDtSaving(true);
    try {
      if (dtEditMode) {
        await apiClient.put(`/table-management/tables/${DATATYPE_TABLE}/edit`, {
          originalData: { id: dtForm.id }, updatedData: dtForm,
        });
        toast.success("PLC 데이터타입을 수정했어요");
      } else {
        await apiClient.post(`/table-management/tables/${DATATYPE_TABLE}/add`, dtForm);
        toast.success("PLC 데이터타입을 등록했어요");
      }
      setDtModalOpen(false);
      fetchDatatypes();
    } catch { toast.error("저장에 실패했어요"); }
    finally { setDtSaving(false); }
  };
  const deleteDt = async () => {
    if (dtChecked.length === 0) { toast.error("삭제할 항목을 선택해주세요"); return; }
    const ok = await confirm("PLC 데이터타입 삭제", { description: `선택한 ${dtChecked.length}건을 삭제할까요? 이 작업은 되돌릴 수 없어요.` });
    if (!ok) return;
    try {
      await apiClient.delete(`/table-management/tables/${DATATYPE_TABLE}/delete`, {
        data: dtChecked.map(id => ({ id })),
      });
      toast.success(`${dtChecked.length}건을 삭제했어요`);
      setDtChecked([]);
      fetchDatatypes();
    } catch { toast.error("삭제에 실패했어요"); }
  };

  /* ═══════════════════ 수집 설정 CRUD ═══════════════════ */
  const openCfgCreate = () => { setCfgForm({}); setCfgEditMode(false); setCfgModalOpen(true); };
  const openCfgEdit = (row: any) => { setCfgForm({ ...row }); setCfgEditMode(true); setCfgModalOpen(true); };
  const saveCfg = async () => {
    if (!cfgForm.config_name) { toast.error("설정명은 필수 입력이에요"); return; }
    setCfgSaving(true);
    try {
      if (cfgEditMode) {
        await apiClient.put(`/table-management/tables/${COLLECTION_TABLE}/edit`, {
          originalData: { id: cfgForm.id }, updatedData: cfgForm,
        });
        toast.success("수집 설정을 수정했어요");
      } else {
        await apiClient.post(`/table-management/tables/${COLLECTION_TABLE}/add`, cfgForm);
        toast.success("수집 설정을 등록했어요");
      }
      setCfgModalOpen(false);
      fetchConfigs();
    } catch { toast.error("저장에 실패했어요"); }
    finally { setCfgSaving(false); }
  };
  const deleteCfg = async () => {
    if (cfgChecked.length === 0) { toast.error("삭제할 항목을 선택해주세요"); return; }
    const ok = await confirm("수집 설정 삭제", { description: `선택한 ${cfgChecked.length}건을 삭제할까요? 이 작업은 되돌릴 수 없어요.` });
    if (!ok) return;
    try {
      await apiClient.delete(`/table-management/tables/${COLLECTION_TABLE}/delete`, {
        data: cfgChecked.map(id => ({ id })),
      });
      toast.success(`${cfgChecked.length}건을 삭제했어요`);
      setCfgChecked([]);
      fetchConfigs();
    } catch { toast.error("삭제에 실패했어요"); }
  };

  /* ═══════════════════ JSX ═══════════════════ */
  return (
    <div className="flex flex-col gap-3 p-3">
      {ConfirmDialogComponent}

      <div className="rounded-lg border bg-card">
        <Tabs value={activeTab} onValueChange={setActiveTab}>
          <div className="border-b px-3">
            <TabsList className="bg-transparent h-auto p-0 gap-0">
              <TabsTrigger
                value="datatype"
                className="rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:shadow-none px-4 py-3 text-sm font-medium"
              >
                <Cpu className="w-4 h-4 mr-2" />
                PLC 데이터타입
                <Badge variant="secondary" className="ml-2 bg-primary/10 text-primary text-xs">{dtCount}</Badge>
              </TabsTrigger>
              <TabsTrigger
                value="collection"
                className="rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:shadow-none px-4 py-3 text-sm font-medium"
              >
                <Settings2 className="w-4 h-4 mr-2" />
                수집 설정
                <Badge variant="secondary" className="ml-2 bg-primary/10 text-primary text-xs">{cfgCount}</Badge>
              </TabsTrigger>
            </TabsList>
          </div>

          {/* ──── PLC 데이터타입 탭 ──── */}
          <TabsContent value="datatype" className="p-3 mt-0">
            <div className="flex items-center justify-between mb-3">
              <div className="flex items-center gap-2">
                <div className="relative">
                  <Search className="absolute left-2.5 top-2 h-3.5 w-3.5 text-muted-foreground" />
                  <Input
                    className="h-8 pl-8 w-56 text-sm"
                    placeholder="설비코드 검색..."
                    value={dtKeyword}
                    onChange={(e) => setDtKeyword(e.target.value)}
                    onKeyDown={(e) => e.key === "Enter" && fetchDatatypes(dtKeyword)}
                  />
                </div>
                <Button size="sm" variant="outline" className="h-8" onClick={() => fetchDatatypes(dtKeyword)}>
                  <Search className="w-3.5 h-3.5 mr-1" />검색
                </Button>
                <Button size="sm" variant="ghost" className="h-8" onClick={() => { setDtKeyword(""); fetchDatatypes(""); }}>
                  초기화
                </Button>
                <Badge variant="secondary" className="bg-primary/10 text-primary">{dtCount}건</Badge>
              </div>
              <div className="flex items-center gap-2">
                <Button size="sm" onClick={openDtCreate}><Plus className="w-4 h-4 mr-1" />등록</Button>
                <Button size="sm" variant="outline" onClick={() => {
                  const sel = datatypes.find(r => dtChecked.includes(r.id));
                  if (sel) openDtEdit(sel); else toast.error("수정할 항목을 선택해주세요");
                }}><Pencil className="w-4 h-4 mr-1" />수정</Button>
                <Button size="sm" variant="destructive" onClick={deleteDt}><Trash2 className="w-4 h-4 mr-1" />삭제</Button>
                <Button variant="ghost" size="sm" onClick={() => ts.setOpen(true)} title="테이블 설정">
                  <Settings2 className="h-4 w-4" />
                </Button>
              </div>
            </div>
            <div className="border rounded-lg overflow-hidden">
              <EDataTable
                columns={ts.visibleColumns.map((col): EDataTableColumn => ({
                  key: col.key,
                  label: col.label,
                  align: col.key === "is_active" ? "center" : undefined,
                  render: col.key === "is_active"
                    ? (val: any) => <Badge variant={val ? "default" : "secondary"} className="text-xs">{val ? "사용" : "미사용"}</Badge>
                    : undefined,
                }))}
                data={ts.groupData(datatypes)}
                loading={dtLoading}
                emptyMessage="등록된 PLC 데이터타입이 없어요"
                showCheckbox
                checkedIds={dtChecked}
                onCheckedChange={setDtChecked}
                onRowDoubleClick={(row) => openDtEdit(row)}
                showPagination={false}
                draggableColumns={false}
              />
            </div>
          </TabsContent>

          {/* ──── 수집 설정 탭 ──── */}
          <TabsContent value="collection" className="p-3 mt-0">
            <div className="flex items-center justify-between mb-3">
              <div className="flex items-center gap-2">
                <div className="relative">
                  <Search className="absolute left-2.5 top-2 h-3.5 w-3.5 text-muted-foreground" />
                  <Input
                    className="h-8 pl-8 w-56 text-sm"
                    placeholder="설정명 검색..."
                    value={cfgKeyword}
                    onChange={(e) => setCfgKeyword(e.target.value)}
                    onKeyDown={(e) => e.key === "Enter" && fetchConfigs(cfgKeyword)}
                  />
                </div>
                <Button size="sm" variant="outline" className="h-8" onClick={() => fetchConfigs(cfgKeyword)}>
                  <Search className="w-3.5 h-3.5 mr-1" />검색
                </Button>
                <Button size="sm" variant="ghost" className="h-8" onClick={() => { setCfgKeyword(""); fetchConfigs(""); }}>
                  초기화
                </Button>
                <Badge variant="secondary" className="bg-primary/10 text-primary">{cfgCount}건</Badge>
              </div>
              <div className="flex items-center gap-2">
                <Button size="sm" onClick={openCfgCreate}><Plus className="w-4 h-4 mr-1" />등록</Button>
                <Button size="sm" variant="outline" onClick={() => {
                  const sel = configs.find(r => cfgChecked.includes(r.id));
                  if (sel) openCfgEdit(sel); else toast.error("수정할 항목을 선택해주세요");
                }}><Pencil className="w-4 h-4 mr-1" />수정</Button>
                <Button size="sm" variant="destructive" onClick={deleteCfg}><Trash2 className="w-4 h-4 mr-1" />삭제</Button>
              </div>
            </div>
            <div className="border rounded-lg overflow-hidden">
              <EDataTable
                columns={[
                  { key: "config_name", label: "설정명" },
                  { key: "source_connection_id", label: "소스연결ID", width: "w-[110px]" },
                  { key: "source_table", label: "소스테이블", width: "w-[120px]" },
                  { key: "target_table", label: "대상테이블", width: "w-[120px]" },
                  { key: "collection_type", label: "수집유형", width: "w-[90px]" },
                  { key: "schedule_cron", label: "스케줄(Cron)", width: "w-[120px]", render: (val: any) => <span className="font-mono text-[13px]">{val}</span> },
                  { key: "is_active", label: "사용여부", width: "w-[80px]", align: "center" as const, render: (val: any) => <Badge variant={val ? "default" : "secondary"} className="text-xs">{val ? "사용" : "미사용"}</Badge> },
                ] as EDataTableColumn[]}
                data={configs}
                loading={cfgLoading}
                emptyMessage="등록된 수집 설정이 없어요"
                showCheckbox
                checkedIds={cfgChecked}
                onCheckedChange={setCfgChecked}
                onRowDoubleClick={(row) => openCfgEdit(row)}
                showPagination={false}
                draggableColumns={false}
              />
            </div>
          </TabsContent>
        </Tabs>
      </div>

      {/* ═══════════════════ PLC 데이터타입 모달 ═══════════════════ */}
      <Dialog open={dtModalOpen} onOpenChange={setDtModalOpen}>
        <DialogContent className="max-w-[95vw] sm:max-w-lg max-h-[85vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>{dtEditMode ? "PLC 데이터타입 수정" : "PLC 데이터타입 등록"}</DialogTitle>
            <DialogDescription>PLC 데이터타입 정보를 입력해주세요</DialogDescription>
          </DialogHeader>
          <div className="grid grid-cols-2 gap-3">
            <div className="space-y-1.5 col-span-2">
              <Label className="text-xs font-semibold text-muted-foreground">설비코드 <span className="text-destructive">*</span></Label>
              <Select value={dtForm.equipment_code || ""} onValueChange={(v) => setDtForm(p => ({ ...p, equipment_code: v }))}>
                <SelectTrigger className="h-9"><SelectValue placeholder="설비를 선택해주세요" /></SelectTrigger>
                <SelectContent>
                  {equipOptions.map(o => (
                    <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">데이터타입</Label>
              <Input className="h-9" value={dtForm.data_type || ""} onChange={(e) => setDtForm(p => ({ ...p, data_type: e.target.value }))} placeholder="예: 온도, 압력" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">단위</Label>
              <Input className="h-9" value={dtForm.unit || ""} onChange={(e) => setDtForm(p => ({ ...p, unit: e.target.value }))} placeholder="예: ℃, bar" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">태그주소</Label>
              <Input className="h-9" value={dtForm.tag_address || ""} onChange={(e) => setDtForm(p => ({ ...p, tag_address: e.target.value }))} placeholder="예: D100" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">수집주기</Label>
              <Input className="h-9" value={dtForm.collection_interval || ""} onChange={(e) => setDtForm(p => ({ ...p, collection_interval: e.target.value }))} placeholder="예: 1000ms" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">하한값</Label>
              <Input className="h-9" type="number" value={dtForm.lower_limit ?? ""} onChange={(e) => setDtForm(p => ({ ...p, lower_limit: e.target.value }))} placeholder="하한값" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">상한값</Label>
              <Input className="h-9" type="number" value={dtForm.upper_limit ?? ""} onChange={(e) => setDtForm(p => ({ ...p, upper_limit: e.target.value }))} placeholder="상한값" />
            </div>
            <div className="space-y-1.5 col-span-2">
              <div className="flex items-center gap-2">
                <Checkbox checked={dtForm.is_active ?? true} onCheckedChange={(v) => setDtForm(p => ({ ...p, is_active: !!v }))} />
                <Label className="text-sm">사용</Label>
              </div>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setDtModalOpen(false)}>취소</Button>
            <Button onClick={saveDt} disabled={dtSaving}>
              {dtSaving ? <Loader2 className="w-4 h-4 animate-spin mr-1" /> : <Save className="w-4 h-4 mr-1" />}
              저장해요
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ═══════════════════ 수집 설정 모달 ═══════════════════ */}
      <Dialog open={cfgModalOpen} onOpenChange={setCfgModalOpen}>
        <DialogContent className="max-w-[95vw] sm:max-w-lg max-h-[85vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>{cfgEditMode ? "수집 설정 수정" : "수집 설정 등록"}</DialogTitle>
            <DialogDescription>수집 설정 정보를 입력해주세요</DialogDescription>
          </DialogHeader>
          <div className="grid grid-cols-2 gap-3">
            <div className="space-y-1.5 col-span-2">
              <Label className="text-xs font-semibold text-muted-foreground">설정명 <span className="text-destructive">*</span></Label>
              <Input className="h-9" value={cfgForm.config_name || ""} onChange={(e) => setCfgForm(p => ({ ...p, config_name: e.target.value }))} placeholder="설정명을 입력해주세요" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">소스연결ID</Label>
              <Input className="h-9" value={cfgForm.source_connection_id || ""} onChange={(e) => setCfgForm(p => ({ ...p, source_connection_id: e.target.value }))} placeholder="소스연결ID" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">수집유형</Label>
              {collectionTypeOptions.length > 0 ? (
                <Select value={cfgForm.collection_type || ""} onValueChange={(v) => setCfgForm(p => ({ ...p, collection_type: v }))}>
                  <SelectTrigger className="h-9"><SelectValue placeholder="선택해주세요" /></SelectTrigger>
                  <SelectContent>
                    {collectionTypeOptions.map(o => (
                      <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              ) : (
                <Input className="h-9" value={cfgForm.collection_type || ""} onChange={(e) => setCfgForm(p => ({ ...p, collection_type: e.target.value }))} placeholder="수집유형" />
              )}
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">소스테이블</Label>
              <Input className="h-9" value={cfgForm.source_table || ""} onChange={(e) => setCfgForm(p => ({ ...p, source_table: e.target.value }))} placeholder="소스테이블명" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground">대상테이블</Label>
              <Input className="h-9" value={cfgForm.target_table || ""} onChange={(e) => setCfgForm(p => ({ ...p, target_table: e.target.value }))} placeholder="대상테이블명" />
            </div>
            <div className="space-y-1.5 col-span-2">
              <Label className="text-xs font-semibold text-muted-foreground">스케줄 (Cron)</Label>
              <Input className="h-9 font-mono text-sm" value={cfgForm.schedule_cron || ""} onChange={(e) => setCfgForm(p => ({ ...p, schedule_cron: e.target.value }))} placeholder="예: */5 * * * * (5분마다)" />
              {cfgForm.schedule_cron && (
                <p className="text-xs text-muted-foreground mt-1">{cronToKorean(cfgForm.schedule_cron)}</p>
              )}
            </div>
            <div className="space-y-1.5 col-span-2">
              <div className="flex items-center gap-2">
                <Checkbox checked={cfgForm.is_active ?? true} onCheckedChange={(v) => setCfgForm(p => ({ ...p, is_active: !!v }))} />
                <Label className="text-sm">사용</Label>
              </div>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setCfgModalOpen(false)}>취소</Button>
            <Button onClick={saveCfg} disabled={cfgSaving}>
              {cfgSaving ? <Loader2 className="w-4 h-4 animate-spin mr-1" /> : <Save className="w-4 h-4 mr-1" />}
              저장해요
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <TableSettingsModal
        open={ts.open}
        onOpenChange={ts.setOpen}
        tableName={ts.tableName}
        settingsId={ts.settingsId}
        defaultVisibleKeys={ts.defaultVisibleKeys}
        onSave={ts.applySettings}
      />
    </div>
  );
}
