"use client";

/**
 * 제일그라스(COMPANY_9) 수주관리 — 하드코딩 페이지
 *
 * 좌측: 수주 마스터 목록 (order_no 그룹핑 집계)
 * 우측: 선택한 수주의 품목 상세 (sales_order_detail)
 *
 * 특화: 가로/세로/두께/면적 컬럼 (유리 업종)
 * 특화: 품목 자동 등록 (item_info에 없으면 저장 시 자동 INSERT)
 */

import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Badge } from "@/components/ui/badge";
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
import {
  Plus, Trash2, Save, Loader2, FileSpreadsheet, Download, Pencil,
  ClipboardList, Package, Search, X, Settings2, GripVertical,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";
import { useAuth } from "@/hooks/useAuth";
import { toast } from "sonner";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";
import { DataGrid, DataGridColumn } from "@/components/common/DataGrid";
import { useConfirmDialog } from "@/components/common/ConfirmDialog";
import { FullscreenDialog } from "@/components/common/FullscreenDialog";
import { ExcelUploadModal } from "@/components/common/ExcelUploadModal";
import { exportToExcel } from "@/lib/utils/excelExport";
import { FormDatePicker } from "@/components/screen/filters/FormDatePicker";
import { TableSettingsModal, TableSettings, loadTableSettings } from "@/components/common/TableSettingsModal";
import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule";

const MASTER_TABLE = "sales_order_mng";
const DETAIL_TABLE = "sales_order_detail";
const ITEM_TABLE = "item_info";

const formatNumber = (val: string) => {
  const num = val.replace(/[^\d.-]/g, "");
  if (!num) return "";
  const parts = num.split(".");
  parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return parts.join(".");
};
const parseNumber = (val: string) => val.replace(/,/g, "");

// 좌측: 수주 마스터 집계 목록
const LEFT_COLUMNS: DataGridColumn[] = [
  { key: "order_no", label: "수주번호", width: "w-[120px]" },
  { key: "partner_name", label: "거래처", minWidth: "min-w-[100px]" },
  { key: "item_count", label: "품목수", width: "w-[60px]", align: "right" },
  { key: "total_qty", label: "총수량", width: "w-[80px]", formatNumber: true, align: "right" },
  { key: "total_ship_qty", label: "출하량", width: "w-[70px]", formatNumber: true, align: "right" },
  { key: "total_balance", label: "잔량", width: "w-[70px]", formatNumber: true, align: "right" },
  { key: "total_amount", label: "총금액", width: "w-[100px]", formatNumber: true, align: "right" },
  { key: "due_date", label: "납기일", width: "w-[100px]" },
  { key: "status", label: "상태", width: "w-[70px]" },
];

// 우측: 품목 상세 (가로/세로/두께/면적 포함)
const RIGHT_COLUMNS: DataGridColumn[] = [
  { key: "division", label: "구분", width: "w-[70px]" },
  { key: "part_name", label: "품명", minWidth: "min-w-[120px]" },
  { key: "spec", label: "규격", width: "w-[100px]" },
  { key: "width", label: "가로", width: "w-[65px]", formatNumber: true, align: "right" },
  { key: "height", label: "세로", width: "w-[65px]", formatNumber: true, align: "right" },
  { key: "thickness", label: "두께", width: "w-[60px]", align: "right" },
  { key: "area", label: "면적", width: "w-[70px]", align: "right" },
  { key: "unit", label: "단위", width: "w-[50px]" },
  { key: "qty", label: "수량", width: "w-[70px]", formatNumber: true, align: "right" },
  { key: "ship_qty", label: "출하", width: "w-[60px]", formatNumber: true, align: "right" },
  { key: "balance_qty", label: "잔량", width: "w-[60px]", formatNumber: true, align: "right" },
  { key: "unit_price", label: "단가", width: "w-[85px]", formatNumber: true, align: "right" },
  { key: "amount", label: "금액", width: "w-[95px]", formatNumber: true, align: "right" },
  { key: "due_date", label: "납기일", width: "w-[100px]" },
  { key: "memo", label: "비고", width: "w-[80px]" },
];

export default function JeilGlassOrderPage() {
  const { user } = useAuth();
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();

  // 좌측: 수주 목록
  const [masterOrders, setMasterOrders] = useState<any[]>([]);
  const [allDetails, setAllDetails] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const [totalCount, setTotalCount] = useState(0);
  const [searchFilters, setSearchFilters] = useState<FilterValue[]>([]);
  const [selectedOrderNo, setSelectedOrderNo] = useState<string | null>(null);
  const [checkedIds, setCheckedIds] = useState<string[]>([]);

  // 우측: 디테일
  const [detailItems, setDetailItems] = useState<any[]>([]);
  const [detailLoading, setDetailLoading] = useState(false);

  // 모달
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [isEditMode, setIsEditMode] = useState(false);
  const [saving, setSaving] = useState(false);
  const [masterForm, setMasterForm] = useState<Record<string, any>>({});
  const [modalDetailRows, setModalDetailRows] = useState<any[]>([]);

  // 품목 선택 모달
  const [itemSelectOpen, setItemSelectOpen] = useState(false);
  const [itemSearchKeyword, setItemSearchKeyword] = useState("");
  const [itemSearchResults, setItemSearchResults] = useState<any[]>([]);
  const [itemSearchLoading, setItemSearchLoading] = useState(false);
  const [itemCheckedIds, setItemCheckedIds] = useState<Set<string>>(new Set());

  // 기타
  const [excelUploadOpen, setExcelUploadOpen] = useState(false);
  const [tableSettingsOpen, setTableSettingsOpen] = useState(false);
  const [filterConfig, setFilterConfig] = useState<TableSettings["filters"] | undefined>();
  const [categoryOptions, setCategoryOptions] = useState<Record<string, { code: string; label: string }[]>>({});

  // 채번
  const [numberingRuleId, setNumberingRuleId] = useState<string | null>(null);

  // 테이블 설정
  const applyTableSettings = (settings: TableSettings) => {
    if (settings.filters) setFilterConfig(settings.filters);
  };
  useEffect(() => {
    const saved = loadTableSettings(MASTER_TABLE, "jeilglass-order");
    if (saved?.filters) setFilterConfig(saved.filters);
  }, []);

  // 채번규칙 로드
  useEffect(() => {
    const loadRule = async () => {
      try {
        const res = await apiClient.get(`/numbering-rules/by-column/${MASTER_TABLE}/order_no`);
        const rule = res.data?.data;
        if (rule?.ruleId || rule?.rule_id) {
          setNumberingRuleId(rule.ruleId || rule.rule_id);
        }
      } catch { /* 채번규칙 없음 — fallback 사용 */ }
    };
    loadRule();
  }, []);

  // 카테고리 로드
  useEffect(() => {
    const loadCategories = async () => {
      const optMap: Record<string, { code: string; label: string }[]> = {};
      const flatten = (vals: any[]): { code: string; label: string }[] => {
        const result: { code: string; label: string }[] = [];
        for (const v of vals) {
          result.push({ code: v.valueCode || v.code, label: v.valueLabel || v.label || v.valueCode });
          if (v.children?.length) result.push(...flatten(v.children));
        }
        return result;
      };
      // 마스터 카테고리
      for (const col of ["sell_mode", "input_mode", "price_mode"]) {
        try {
          const res = await apiClient.get(`/table-categories/${MASTER_TABLE}/${col}/values`);
          optMap[col] = flatten(res.data?.data || []);
        } catch { /* skip */ }
      }
      // 거래처
      try {
        const res = await apiClient.post(`/table-management/tables/customer_mng/data`, { page: 1, size: 500, autoFilter: true });
        const custs = res.data?.data?.data || res.data?.data?.rows || [];
        optMap["partner_id"] = custs.map((c: any) => ({
          code: c.customer_code,
          label: `${c.customer_name} (${c.customer_code})`,
        }));
      } catch { /* skip */ }
      // 담당자
      try {
        const res = await apiClient.post(`/table-management/tables/user_info/data`, { page: 1, size: 200, autoFilter: true });
        const users = res.data?.data?.data || res.data?.data?.rows || [];
        optMap["manager_id"] = users.map((u: any) => ({
          code: u.user_id || u.id,
          label: `${u.user_name || ""}${u.position_name ? ` (${u.position_name})` : ""}`,
        }));
      } catch { /* skip */ }
      // 품목 카테고리 (단위, 구분, 재질, 유형)
      for (const col of ["unit", "division", "material", "type"]) {
        try {
          const res = await apiClient.get(`/table-categories/${ITEM_TABLE}/${col}/values`);
          if (res.data?.success && res.data.data?.length > 0) {
            optMap[`item_${col}`] = flatten(res.data.data);
          }
        } catch { /* skip */ }
      }
      setCategoryOptions(optMap);
    };
    loadCategories();
  }, []);

  // 수주 목록 조회 (디테일 전체 → order_no 그룹핑)
  const fetchMasterOrders = useCallback(async () => {
    setLoading(true);
    try {
      const filters: any[] = searchFilters.map((f) => ({
        columnName: f.columnName,
        operator: f.operator,
        value: f.value,
      }));
      const res = await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/data`, {
        page: 1, size: 500,
        dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
        autoFilter: true,
        sort: { columnName: "order_no", order: "desc" },
      });
      const rows = res.data?.data?.data || res.data?.data?.rows || [];
      setAllDetails(rows);

      // 마스터 조회 (거래처 정보 확보)
      const orderNos = [...new Set(rows.map((r: any) => r.order_no).filter(Boolean))];
      let masterMap: Record<string, any> = {};
      if (orderNos.length > 0) {
        try {
          const mRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/data`, {
            page: 1, size: orderNos.length + 10,
            dataFilter: { enabled: true, filters: [{ columnName: "order_no", operator: "in", value: orderNos }] },
            autoFilter: true,
          });
          const masters = mRes.data?.data?.data || mRes.data?.data?.rows || [];
          for (const m of masters) masterMap[m.order_no] = m;
        } catch { /* skip */ }
      }

      // 거래처 코드 → 이름 변환
      const resolvePartner = (code: string) => {
        if (!code) return "";
        return categoryOptions["partner_id"]?.find((o) => o.code === code)?.label?.split(" (")[0] || code;
      };

      // order_no 기준 집계
      const grouped: Record<string, any> = {};
      for (const row of rows) {
        const no = row.order_no;
        if (!no) continue;
        if (!grouped[no]) {
          const master = masterMap[no] || {};
          grouped[no] = {
            id: `master_${no}`,
            order_no: no,
            partner_name: resolvePartner(master.partner_id),
            item_count: 0,
            total_qty: 0,
            total_ship_qty: 0,
            total_balance: 0,
            total_amount: 0,
            due_date: row.due_date || "",
            status: master.status || "",
          };
        }
        const g = grouped[no];
        g.item_count += 1;
        g.total_qty += parseFloat(row.qty) || 0;
        g.total_ship_qty += parseFloat(row.ship_qty) || 0;
        g.total_balance += parseFloat(row.balance_qty) || 0;
        g.total_amount += parseFloat(row.amount) || 0;
        if (row.due_date && (!g.due_date || row.due_date > g.due_date)) g.due_date = row.due_date;
      }
      const list = Object.values(grouped);
      setMasterOrders(list);
      setTotalCount(list.length);
    } catch (err) {
      console.error("수주 조회 실패:", err);
      toast.error("수주 목록을 불러오는데 실패했습니다.");
    } finally {
      setLoading(false);
    }
  }, [searchFilters, categoryOptions]);

  useEffect(() => { fetchMasterOrders(); }, [fetchMasterOrders]);

  // 통계
  const stats = useMemo(() => {
    let totalAmount = 0, totalQty = 0;
    for (const m of masterOrders) {
      totalAmount += m.total_amount || 0;
      totalQty += m.total_qty || 0;
    }
    return { totalAmount, totalQty };
  }, [masterOrders]);

  // 우측: 선택된 수주 디테일 조회 (division 코드→라벨 변환)
  useEffect(() => {
    if (!selectedOrderNo) { setDetailItems([]); return; }
    const items = allDetails
      .filter((d) => d.order_no === selectedOrderNo)
      .map((d) => ({
        ...d,
        division: categoryOptions["item_division"]?.find((o) => o.code === d.division)?.label || d.division || "",
      }));
    setDetailItems(items);
  }, [selectedOrderNo, allDetails, categoryOptions]);

  // 좌측 행 클릭
  const handleMasterRowClick = (row: any) => {
    setSelectedOrderNo(row.order_no);
  };

  // 등록 모달
  const openRegisterModal = async () => {
    let previewOrderNo = "";
    if (numberingRuleId) {
      const res = await previewNumberingCode(numberingRuleId);
      if (res.success && res.data?.generatedCode) {
        previewOrderNo = res.data.generatedCode;
      }
    }
    if (!previewOrderNo) {
      previewOrderNo = `ORD-${new Date().toISOString().slice(0, 10).replace(/-/g, "")}-${String(Date.now()).slice(-4)}`;
    }
    setMasterForm({ order_no: previewOrderNo, manager_id: user?.userId || "" });
    setModalDetailRows([]);
    setIsEditMode(false);
    setIsModalOpen(true);
  };

  // 수정 모달
  const openEditModal = async (orderNo: string) => {
    try {
      const masterRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/data`, {
        page: 1, size: 1,
        dataFilter: { enabled: true, filters: [{ columnName: "order_no", operator: "equals", value: orderNo }] },
        autoFilter: true,
      });
      const masterData = (masterRes.data?.data?.data || masterRes.data?.data?.rows || [])[0];

      const detailRes = await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/data`, {
        page: 1, size: 100,
        dataFilter: { enabled: true, filters: [{ columnName: "order_no", operator: "equals", value: orderNo }] },
        autoFilter: true,
      });
      const detailData = detailRes.data?.data?.data || detailRes.data?.data?.rows || [];

      setMasterForm(masterData || {});
      setModalDetailRows(detailData.map((d: any, i: number) => ({
        ...d,
        _id: d.id || `row_${i}`,
        _fromItemInfo: !!d.part_code,
        _divisionLabel: categoryOptions["item_division"]?.find((o: any) => o.code === d.division)?.label || d.division || "",
      })));
      setIsEditMode(true);
      setIsModalOpen(true);
    } catch (err) {
      console.error("수주 상세 조회 실패:", err);
      toast.error("수주 정보를 불러오는데 실패했습니다.");
    }
  };

  // 삭제
  const handleDelete = async () => {
    if (checkedIds.length === 0) { toast.error("삭제할 수주를 선택해주세요."); return; }
    const selectedItems = masterOrders.filter((o) => checkedIds.includes(o.id));
    const orderNos = selectedItems.map((o) => o.order_no);
    const ok = await confirm(`${orderNos.length}건의 수주를 삭제하시겠습니까?`, {
      description: "삭제된 데이터는 복구할 수 없습니다.",
      variant: "destructive",
      confirmText: "삭제",
    });
    if (!ok) return;
    try {
      for (const orderNo of orderNos) {
        // 디테일 삭제
        const detailRes = await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/data`, {
          page: 1, size: 100,
          dataFilter: { enabled: true, filters: [{ columnName: "order_no", operator: "equals", value: orderNo }] },
          autoFilter: true,
        });
        const details = detailRes.data?.data?.data || detailRes.data?.data?.rows || [];
        if (details.length > 0) {
          await apiClient.delete(`/table-management/tables/${DETAIL_TABLE}/delete`, {
            data: details.map((d: any) => ({ id: d.id })),
          });
        }
        // 마스터 삭제
        const masterRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/data`, {
          page: 1, size: 1,
          dataFilter: { enabled: true, filters: [{ columnName: "order_no", operator: "equals", value: orderNo }] },
          autoFilter: true,
        });
        const masters = masterRes.data?.data?.data || masterRes.data?.data?.rows || [];
        if (masters.length > 0) {
          await apiClient.delete(`/table-management/tables/${MASTER_TABLE}/delete`, {
            data: masters.map((m: any) => ({ id: m.id })),
          });
        }
      }
      toast.success("삭제되었습니다.");
      setCheckedIds([]);
      setSelectedOrderNo(null);
      fetchMasterOrders();
    } catch (err) {
      console.error("삭제 실패:", err);
      toast.error("삭제에 실패했습니다.");
    }
  };

  // 품목 자동 등록 (item_info에 없으면 등록)
  const autoRegisterItems = async (rows: any[]) => {
    for (const row of rows) {
      if (row.part_code || !row.part_name) continue;
      try {
        // item_info에서 품명으로 검색
        const searchRes = await apiClient.post(`/table-management/tables/${ITEM_TABLE}/data`, {
          page: 1, size: 1,
          dataFilter: { enabled: true, filters: [{ columnName: "item_name", operator: "equals", value: row.part_name }] },
          autoFilter: true,
        });
        const found = (searchRes.data?.data?.data || searchRes.data?.data?.rows || [])[0];
        if (found) {
          row.part_code = found.item_number;
          continue;
        }
        // 없으면 자동 등록
        await apiClient.post(`/table-management/tables/${ITEM_TABLE}/add`, {
          item_name: row.part_name,
          size: row.spec || "",
          unit: row.unit || "",
        });
        // 등록 후 재조회하여 item_number 획득
        const reSearch = await apiClient.post(`/table-management/tables/${ITEM_TABLE}/data`, {
          page: 1, size: 1,
          dataFilter: { enabled: true, filters: [{ columnName: "item_name", operator: "equals", value: row.part_name }] },
          autoFilter: true,
          sort: { columnName: "created_date", order: "desc" },
        });
        const newItem = (reSearch.data?.data?.data || reSearch.data?.data?.rows || [])[0];
        if (newItem) row.part_code = newItem.item_number;
      } catch (err) {
        console.warn("품목 자동 등록 실패:", row.part_name, err);
      }
    }
  };

  // 저장
  const handleSave = async () => {
    if (modalDetailRows.length === 0) {
      toast.error("품목을 1개 이상 추가해주세요.");
      return;
    }

    setSaving(true);
    try {
      // 품목 자동 등록
      await autoRegisterItems(modalDetailRows);

      // 신규 등록 시 채번 할당
      if (!isEditMode) {
        if (numberingRuleId) {
          const allocRes = await allocateNumberingCode(numberingRuleId, masterForm.order_no);
          if (allocRes.success && allocRes.data?.generatedCode) {
            masterForm.order_no = allocRes.data.generatedCode;
          }
        }
        if (!masterForm.order_no) {
          masterForm.order_no = `ORD-${new Date().toISOString().slice(0, 10).replace(/-/g, "")}-${String(Date.now()).slice(-4)}`;
        }
      }

      const { id, created_date, updated_date, writer, company_code, created_by, updated_by, ...masterFields } = masterForm;

      if (isEditMode && id) {
        await apiClient.put(`/table-management/tables/${MASTER_TABLE}/edit`, {
          originalData: { id },
          updatedData: masterFields,
        });
        const existingDetails = await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/data`, {
          page: 1, size: 100,
          dataFilter: { enabled: true, filters: [{ columnName: "order_no", operator: "equals", value: masterForm.order_no }] },
          autoFilter: true,
        });
        const existings = existingDetails.data?.data?.data || existingDetails.data?.data?.rows || [];
        if (existings.length > 0) {
          await apiClient.delete(`/table-management/tables/${DETAIL_TABLE}/delete`, {
            data: existings.map((d: any) => ({ id: d.id })),
          });
        }
      } else {
        await apiClient.post(`/table-management/tables/${MASTER_TABLE}/add`, masterFields);
      }

      for (let i = 0; i < modalDetailRows.length; i++) {
        const row = modalDetailRows[i];
        const { _id, _fromItemInfo, _divisionLabel, id: rowId, created_date: _cd, updated_date: _ud, writer: _w, company_code: _cc, ...detailFields } = row;
        await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/add`, {
          ...detailFields,
          order_no: masterForm.order_no,
          seq_no: String(i + 1),
        });
      }

      toast.success(isEditMode ? "수정되었습니다." : "등록되었습니다.");
      setIsModalOpen(false);
      fetchMasterOrders();
    } catch (err: any) {
      console.error("저장 실패:", err);
      toast.error(err.response?.data?.message || "저장에 실패했습니다.");
    } finally {
      setSaving(false);
    }
  };

  // 품목 검색
  const searchItems = async () => {
    setItemSearchLoading(true);
    try {
      const filters: any[] = [];
      if (itemSearchKeyword) {
        filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
      }
      const res = await apiClient.post(`/table-management/tables/${ITEM_TABLE}/data`, {
        page: 1, size: 50,
        dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
        autoFilter: true,
      });
      setItemSearchResults(res.data?.data?.data || res.data?.data?.rows || []);
    } catch { setItemSearchResults([]); }
    finally { setItemSearchLoading(false); }
  };

  // 품목 선택 → 리피터에 추가
  const addSelectedItemsToDetail = () => {
    const selected = itemSearchResults.filter((i) => itemCheckedIds.has(i.id));
    const resolveUnit = (code: string) => {
      if (!code) return "";
      return categoryOptions["item_unit"]?.find((o) => o.code === code)?.label || code;
    };
    const resolveDivision = (code: string) => {
      if (!code) return "";
      return categoryOptions["item_division"]?.find((o) => o.code === code)?.label || code;
    };
    const newRows = selected.map((item) => ({
      _id: `new_${Date.now()}_${Math.random()}`,
      _fromItemInfo: true,
      part_code: item.item_number || "",
      part_name: item.item_name || "",
      spec: item.size || "",
      division: item.division || "",
      _divisionLabel: resolveDivision(item.division),
      unit: resolveUnit(item.unit) || "",
      width: "", height: "", thickness: "", area: "",
      qty: "", unit_price: item.selling_price || item.standard_price || "", amount: "",
      due_date: "", memo: "",
    }));
    setModalDetailRows((prev) => [...prev, ...newRows]);
    setItemSelectOpen(false);
    setItemCheckedIds(new Set());
  };

  // 빈 행 추가 (품명 직접 입력용)
  const addEmptyRow = () => {
    setModalDetailRows((prev) => [...prev, {
      _id: `new_${Date.now()}_${Math.random()}`,
      _fromItemInfo: false,
      part_code: "", part_name: "", spec: "", division: "", _divisionLabel: "", unit: "㎡",
      width: "", height: "", thickness: "", area: "",
      qty: "", unit_price: "", amount: "",
      due_date: "", memo: "",
    }]);
  };

  // 구분(division) 라벨로 면적 계산 제수 결정
  const getAreaDivisor = (divisionCode: string) => {
    const label = categoryOptions["item_division"]?.find((o) => o.code === divisionCode)?.label || "";
    // 원판, 원자재 → 92,094 / 그 외(제품 등) → 91,808
    if (label.includes("원판") || label.includes("원자재")) return 92094;
    return 91808;
  };

  // 면적 계산 (구분에 따른 제수 적용)
  const calcArea = (row: any) => {
    const w = parseFloat(row.width) || 0;
    const h = parseFloat(row.height) || 0;
    if (w <= 0 || h <= 0) return "";
    const divisor = getAreaDivisor(row.division);
    return (w * h / divisor).toFixed(4);
  };

  // 리피터 행 값 변경 + 면적/금액 자동 계산
  const updateDetailRow = (idx: number, field: string, value: string) => {
    setModalDetailRows((prev) => {
      const next = [...prev];
      next[idx] = { ...next[idx], [field]: value };
      // 면적 자동 계산 (구분/가로/세로 변경 시)
      if (field === "width" || field === "height" || field === "division") {
        next[idx].area = calcArea(next[idx]);
      }
      // 금액 자동 계산
      if (field === "qty" || field === "unit_price") {
        const qty = parseFloat(field === "qty" ? value : next[idx].qty) || 0;
        const price = parseFloat(field === "unit_price" ? value : next[idx].unit_price) || 0;
        next[idx].amount = (qty * price).toString();
      }
      return next;
    });
  };

  const removeDetailRow = (idx: number) => {
    setModalDetailRows((prev) => prev.filter((_, i) => i !== idx));
  };

  // 엑셀 다운로드 (마스터+디테일 통합)
  const handleExcelDownload = async () => {
    if (allDetails.length === 0) { toast.error("다운로드할 데이터가 없습니다."); return; }
    // 마스터 정보 매핑
    const masterMap: Record<string, any> = {};
    for (const m of masterOrders) masterMap[m.order_no] = m;

    const resolveDiv = (code: string) =>
      categoryOptions["item_division"]?.find((o) => o.code === code)?.label || code || "";

    const data = allDetails.map((o) => {
      const master = masterMap[o.order_no] || {};
      return {
        "수주번호": o.order_no || "",
        "거래처": master.partner_name || "",
        "상태": master.status || "",
        "구분": resolveDiv(o.division),
        "품명": o.part_name || "",
        "규격": o.spec || "",
        "가로": o.width || "",
        "세로": o.height || "",
        "두께": o.thickness || "",
        "면적": o.area || "",
        "단위": o.unit || "",
        "수량": o.qty || "",
        "출하": o.ship_qty || "",
        "잔량": o.balance_qty || "",
        "단가": o.unit_price || "",
        "금액": o.amount || "",
        "납기일": o.due_date || "",
        "비고": o.memo || "",
      };
    });
    await exportToExcel(data, "제일그라스_수주관리.xlsx", "수주목록");
    toast.success("다운로드 완료");
  };

  // 엑셀 업로드 후처리: order_no가 비어있는 디테일에 마스터 자동 생성
  const handleExcelUploadSuccess = async () => {
    try {
      // 마스터 없는 디테일(order_no 비어있는) 조회
      const res = await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/data`, {
        page: 1, size: 500, autoFilter: true,
        sort: { columnName: "created_date", order: "desc" },
      });
      const allRows = res.data?.data?.data || res.data?.data?.rows || [];

      // order_no가 비어있는 행들 수집
      const noOrderRows = allRows.filter((r: any) => !r.order_no);
      if (noOrderRows.length > 0) {
        // 채번 후 마스터 생성 + 디테일에 order_no 설정
        let orderNo = "";
        if (numberingRuleId) {
          const allocRes = await allocateNumberingCode(numberingRuleId);
          if (allocRes.success && allocRes.data?.generatedCode) orderNo = allocRes.data.generatedCode;
        }
        if (!orderNo) {
          orderNo = `ORD-${new Date().toISOString().slice(0, 10).replace(/-/g, "")}-${String(Date.now()).slice(-4)}`;
        }

        // 마스터 생성
        await apiClient.post(`/table-management/tables/${MASTER_TABLE}/add`, {
          order_no: orderNo,
          status: "수주",
          manager_id: user?.userId || "",
          order_date: new Date().toISOString().slice(0, 10),
        });

        // 디테일에 order_no + 면적/금액 계산하여 업데이트
        for (let i = 0; i < noOrderRows.length; i++) {
          const row = noOrderRows[i];
          const w = parseFloat(row.width) || 0;
          const h = parseFloat(row.height) || 0;
          const qty = parseFloat(row.qty) || 0;
          const price = parseFloat(row.unit_price) || 0;
          const area = w > 0 && h > 0 ? (w * h / 91808).toFixed(4) : "";
          const amount = (qty * price).toString();

          await apiClient.put(`/table-management/tables/${DETAIL_TABLE}/edit`, {
            originalData: { id: row.id },
            updatedData: {
              order_no: orderNo,
              seq_no: String(i + 1),
              area: area || row.area || "",
              amount: amount || row.amount || "",
            },
          });
        }
        toast.success(`${noOrderRows.length}건의 품목에 수주번호 ${orderNo} 할당 완료`);
      }
    } catch (err) {
      console.error("엑셀 업로드 후처리 실패:", err);
    }
    fetchMasterOrders();
  };

  return (
    <div className="flex h-full flex-col gap-3 p-3">
      {/* 검색 필터 */}
      <DynamicSearchFilter
        tableName={MASTER_TABLE}
        filterId="jeilglass-sales-order"
        onFilterChange={setSearchFilters}
        dataCount={totalCount}
        externalFilterConfig={filterConfig}
      />

      {/* 통계 바 */}
      <div className="flex items-center gap-4 px-1">
        <div className="flex items-center gap-2 text-sm">
          <span className="text-muted-foreground">총 금액</span>
          <span className="font-semibold text-blue-600">{stats.totalAmount.toLocaleString()}원</span>
        </div>
        <div className="flex items-center gap-2 text-sm">
          <span className="text-muted-foreground">총 수량</span>
          <span className="font-semibold">{stats.totalQty.toLocaleString()}개</span>
        </div>
      </div>

      {/* 좌우 분할 */}
      <div className="flex-1 overflow-hidden border rounded-lg bg-background shadow-sm">
        <ResizablePanelGroup direction="horizontal">
          {/* 좌측: 수주 목록 */}
          <ResizablePanel defaultSize={45} minSize={25}>
            <div className="flex flex-col h-full">
              <div className="flex items-center justify-between p-3 border-b bg-muted/10 shrink-0">
                <div className="font-semibold flex items-center gap-2 text-sm">
                  <ClipboardList className="w-4 h-4" /> 수주 목록
                  <Badge variant="secondary" className="font-normal">{totalCount}건</Badge>
                </div>
                <div className="flex items-center gap-1.5">
                  <Button size="sm" onClick={openRegisterModal}>
                    <Plus className="w-4 h-4 mr-1" /> 수주 등록
                  </Button>
                  <Button variant="outline" size="sm" disabled={checkedIds.length !== 1} onClick={() => {
                    const item = masterOrders.find((o) => o.id === checkedIds[0]);
                    if (item) openEditModal(item.order_no);
                  }}>
                    <Pencil className="w-4 h-4 mr-1" /> 수정
                  </Button>
                  <Button variant="destructive" size="sm" disabled={checkedIds.length === 0} onClick={handleDelete}>
                    <Trash2 className="w-4 h-4 mr-1" /> 삭제
                  </Button>
                </div>
              </div>
              <DataGrid
                gridId="jeilglass-order-master"
                columns={LEFT_COLUMNS}
                data={masterOrders}
                loading={loading}
                showCheckbox
                checkedIds={checkedIds}
                onCheckedChange={setCheckedIds}
                onRowClick={handleMasterRowClick}
                onRowDoubleClick={(row) => openEditModal(row.order_no)}
                tableName={MASTER_TABLE}
                emptyMessage="등록된 수주가 없습니다"
              />
            </div>
          </ResizablePanel>

          <ResizableHandle withHandle />

          {/* 우측: 품목 상세 */}
          <ResizablePanel defaultSize={55} minSize={30}>
            <div className="flex flex-col h-full">
              <div className="flex items-center justify-between p-3 border-b bg-muted/10 shrink-0">
                <div className="font-semibold flex items-center gap-2 text-sm">
                  <Package className="w-4 h-4" /> 품목 상세
                  {selectedOrderNo && (
                    <Badge variant="outline" className="font-normal">{selectedOrderNo}</Badge>
                  )}
                  {detailItems.length > 0 && (
                    <span className="text-muted-foreground font-normal">({detailItems.length}건)</span>
                  )}
                </div>
                <div className="flex items-center gap-1.5">
                  <Button variant="outline" size="sm" onClick={() => setExcelUploadOpen(true)}>
                    <FileSpreadsheet className="w-4 h-4 mr-1" /> 엑셀 업로드
                  </Button>
                  <Button variant="outline" size="sm" onClick={handleExcelDownload}>
                    <Download className="w-4 h-4 mr-1" /> 엑셀 다운로드
                  </Button>
                  <Button variant="outline" size="sm" onClick={() => setTableSettingsOpen(true)}>
                    <Settings2 className="w-4 h-4" />
                  </Button>
                </div>
              </div>
              {!selectedOrderNo ? (
                <div className="flex-1 flex items-center justify-center text-muted-foreground text-sm">
                  좌측에서 수주를 선택하세요
                </div>
              ) : (
                <DataGrid
                  gridId="jeilglass-order-detail"
                  columns={RIGHT_COLUMNS}
                  data={detailItems}
                  loading={detailLoading}
                  showRowNumber
                  tableName={DETAIL_TABLE}
                  emptyMessage="품목이 없습니다"
                />
              )}
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>

      {/* 등록/수정 모달 */}
      <FullscreenDialog
        open={isModalOpen}
        onOpenChange={setIsModalOpen}
        title={isEditMode ? "수주 수정" : "수주 등록"}
        description={isEditMode ? "수주 정보를 수정합니다." : "새로운 수주를 등록합니다."}
        defaultMaxWidth="max-w-7xl"
        defaultWidth="w-[98vw]"
        footer={
          <>
            <Button variant="outline" onClick={() => setIsModalOpen(false)}>취소</Button>
            <Button onClick={handleSave} disabled={saving}>
              {saving ? <Loader2 className="w-4 h-4 mr-1.5 animate-spin" /> : <Save className="w-4 h-4 mr-1.5" />} 저장
            </Button>
          </>
        }
      >
        <div className="space-y-4 py-2">
          {/* 기본 정보 */}
          <div className="grid grid-cols-4 gap-4">
            <div className="space-y-1.5">
              <Label className="text-sm">수주번호 <span className="text-destructive">*</span></Label>
              <Input
                value={masterForm.order_no || ""}
                readOnly
                placeholder="저장 시 자동 채번"
                className="h-9 bg-muted text-muted-foreground"
              />
            </div>
            <div className="space-y-1.5">
              <Label className="text-sm">거래처</Label>
              <Select value={masterForm.partner_id || ""} onValueChange={(v) => setMasterForm((p) => ({ ...p, partner_id: v }))}>
                <SelectTrigger className="h-9"><SelectValue placeholder="거래처 선택" /></SelectTrigger>
                <SelectContent>
                  {(categoryOptions["partner_id"] || []).map((o) => <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>)}
                </SelectContent>
              </Select>
            </div>
            <div className="space-y-1.5">
              <Label className="text-sm">상태</Label>
              <Select value={masterForm.status || "수주"} onValueChange={(v) => setMasterForm((p) => ({ ...p, status: v }))}>
                <SelectTrigger className="h-9"><SelectValue /></SelectTrigger>
                <SelectContent>
                  <SelectItem value="수주">수주</SelectItem>
                  <SelectItem value="진행중">진행중</SelectItem>
                  <SelectItem value="완료">완료</SelectItem>
                  <SelectItem value="취소">취소</SelectItem>
                </SelectContent>
              </Select>
            </div>
            <div className="space-y-1.5">
              <Label className="text-sm">수주일</Label>
              <FormDatePicker value={masterForm.order_date || ""} onChange={(v) => setMasterForm((p) => ({ ...p, order_date: v }))} placeholder="수주일" />
            </div>
          </div>
          <div className="grid grid-cols-4 gap-4">
            <div className="space-y-1.5">
              <Label className="text-sm">납기일</Label>
              <FormDatePicker value={masterForm.due_date || ""} onChange={(v) => setMasterForm((p) => ({ ...p, due_date: v }))} placeholder="납기일" />
            </div>
            <div className="space-y-1.5">
              <Label className="text-sm">담당자</Label>
              <Select value={masterForm.manager_id || ""} onValueChange={(v) => setMasterForm((p) => ({ ...p, manager_id: v }))}>
                <SelectTrigger className="h-9"><SelectValue placeholder="담당자 선택" /></SelectTrigger>
                <SelectContent>
                  {(categoryOptions["manager_id"] || []).map((o) => <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>)}
                </SelectContent>
              </Select>
            </div>
            <div className="col-span-2 space-y-1.5">
              <Label className="text-sm">메모</Label>
              <Input value={masterForm.memo || ""} onChange={(e) => setMasterForm((p) => ({ ...p, memo: e.target.value }))}
                placeholder="메모" className="h-9" />
            </div>
          </div>

          {/* 품목 리피터 */}
          <div className="border rounded-lg">
            <div className="flex items-center justify-between p-3 border-b bg-muted/10">
              <span className="text-sm font-semibold">수주 품목 ({modalDetailRows.length}건)</span>
              <div className="flex gap-1.5">
                <Button size="sm" variant="outline" onClick={addEmptyRow}>
                  <Plus className="w-4 h-4 mr-1" /> 행 추가
                </Button>
                <Button size="sm" variant="outline" onClick={() => { setItemCheckedIds(new Set()); setItemSelectOpen(true); searchItems(); }}>
                  <Search className="w-4 h-4 mr-1" /> 품목 검색
                </Button>
              </div>
            </div>
            <div className="overflow-x-auto overflow-y-visible">
              <Table>
                <TableHeader className="sticky top-0 bg-background z-10">
                  <TableRow>
                    <TableHead className="w-[30px]"></TableHead>
                    <TableHead className="w-[36px]"></TableHead>
                    <TableHead className="w-[40px]">No</TableHead>
                    <TableHead className="min-w-[90px]">구분</TableHead>
                    <TableHead className="min-w-[150px]">품명</TableHead>
                    <TableHead className="min-w-[100px]">규격</TableHead>
                    <TableHead className="min-w-[80px]">가로</TableHead>
                    <TableHead className="min-w-[80px]">세로</TableHead>
                    <TableHead className="min-w-[80px]">두께</TableHead>
                    <TableHead className="min-w-[80px]">면적(㎡)</TableHead>
                    <TableHead className="min-w-[60px]">단위</TableHead>
                    <TableHead className="min-w-[80px]">수량</TableHead>
                    <TableHead className="min-w-[90px]">단가</TableHead>
                    <TableHead className="min-w-[90px]">금액</TableHead>
                    <TableHead className="min-w-[140px]">납기일</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {modalDetailRows.length === 0 ? (
                    <TableRow><TableCell colSpan={15} className="text-center text-muted-foreground py-8">품목을 추가해주세요</TableCell></TableRow>
                  ) : modalDetailRows.map((row, idx) => (
                    <TableRow
                      key={row._id || idx}
                      draggable
                      onDragStart={(e) => { e.dataTransfer.setData("text/plain", String(idx)); e.currentTarget.classList.add("opacity-50"); }}
                      onDragEnd={(e) => { e.currentTarget.classList.remove("opacity-50"); }}
                      onDragOver={(e) => { e.preventDefault(); e.currentTarget.classList.add("border-t-2", "border-primary"); }}
                      onDragLeave={(e) => { e.currentTarget.classList.remove("border-t-2", "border-primary"); }}
                      onDrop={(e) => {
                        e.preventDefault();
                        e.currentTarget.classList.remove("border-t-2", "border-primary");
                        const fromIdx = parseInt(e.dataTransfer.getData("text/plain"));
                        if (!isNaN(fromIdx) && fromIdx !== idx) {
                          setModalDetailRows((prev) => {
                            const next = [...prev];
                            const [moved] = next.splice(fromIdx, 1);
                            next.splice(idx, 0, moved);
                            return next;
                          });
                        }
                      }}
                    >
                      <TableCell className="cursor-grab active:cursor-grabbing">
                        <GripVertical className="w-4 h-4 text-muted-foreground" />
                      </TableCell>
                      <TableCell>
                        <Button variant="ghost" size="sm" className="h-7 w-7 p-0 text-destructive" onClick={() => removeDetailRow(idx)}>
                          <X className="w-3.5 h-3.5" />
                        </Button>
                      </TableCell>
                      <TableCell className="text-center text-xs text-muted-foreground">{idx + 1}</TableCell>
                      {/* 구분: 품목검색 → 읽기전용, 행추가 → Select */}
                      <TableCell>
                        {row._fromItemInfo ? (
                          <span className="text-sm px-2">{row._divisionLabel || "-"}</span>
                        ) : (
                          <Select value={row.division || ""} onValueChange={(v) => updateDetailRow(idx, "division", v)}>
                            <SelectTrigger className="h-8 text-sm"><SelectValue placeholder="구분" /></SelectTrigger>
                            <SelectContent position="popper" sideOffset={4} className="z-[9999]">
                              {(categoryOptions["item_division"] || []).map((o) => <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>)}
                            </SelectContent>
                          </Select>
                        )}
                      </TableCell>
                      {/* 품명: 품목검색 → 읽기전용, 행추가 → 입력 */}
                      <TableCell>
                        {row._fromItemInfo ? (
                          <span className="text-sm px-2">{row.part_name || "-"}</span>
                        ) : (
                          <Input value={row.part_name || ""} onChange={(e) => updateDetailRow(idx, "part_name", e.target.value)}
                            className="h-8 text-sm" placeholder="품명" />
                        )}
                      </TableCell>
                      {/* 규격: 품목검색 → 읽기전용, 행추가 → 입력 */}
                      <TableCell>
                        {row._fromItemInfo ? (
                          <span className="text-sm px-2">{row.spec || "-"}</span>
                        ) : (
                          <Input value={row.spec || ""} onChange={(e) => updateDetailRow(idx, "spec", e.target.value)}
                            className="h-8 text-sm" placeholder="규격" />
                        )}
                      </TableCell>
                      <TableCell>
                        <Input value={formatNumber(row.width || "")} onChange={(e) => updateDetailRow(idx, "width", parseNumber(e.target.value))}
                          className="h-8 text-sm text-right" placeholder="mm" />
                      </TableCell>
                      <TableCell>
                        <Input value={formatNumber(row.height || "")} onChange={(e) => updateDetailRow(idx, "height", parseNumber(e.target.value))}
                          className="h-8 text-sm text-right" placeholder="mm" />
                      </TableCell>
                      <TableCell>
                        <Input value={row.thickness || ""} onChange={(e) => updateDetailRow(idx, "thickness", e.target.value)}
                          className="h-8 text-sm text-right" placeholder="mm" />
                      </TableCell>
                      <TableCell className="text-sm text-right text-muted-foreground">
                        {row.area || "-"}
                      </TableCell>
                      {/* 단위: 품목검색 → 읽기전용, 행추가 → 입력 */}
                      <TableCell>
                        {row._fromItemInfo ? (
                          <span className="text-sm px-2">{row.unit || "-"}</span>
                        ) : (
                          <Input value={row.unit || ""} onChange={(e) => updateDetailRow(idx, "unit", e.target.value)}
                            className="h-8 text-sm" placeholder="㎡" />
                        )}
                      </TableCell>
                      <TableCell>
                        <Input value={formatNumber(row.qty || "")} onChange={(e) => updateDetailRow(idx, "qty", parseNumber(e.target.value))}
                          className="h-8 text-sm text-right" />
                      </TableCell>
                      <TableCell>
                        <Input value={formatNumber(row.unit_price || "")} onChange={(e) => updateDetailRow(idx, "unit_price", parseNumber(e.target.value))}
                          className="h-8 text-sm text-right" />
                      </TableCell>
                      <TableCell className="text-sm text-right font-medium">
                        {row.amount ? Number(row.amount).toLocaleString() : ""}
                      </TableCell>
                      <TableCell>
                        <FormDatePicker value={row.due_date || ""} onChange={(v) => updateDetailRow(idx, "due_date", v)} placeholder="납기일" />
                      </TableCell>
                    </TableRow>
                  ))}
                  {/* 합계 행 */}
                  {modalDetailRows.length > 0 && (
                    <TableRow className="bg-muted/30 font-semibold">
                      <TableCell colSpan={11} className="text-right text-sm">합계</TableCell>
                      <TableCell className="text-sm text-right">
                        {modalDetailRows.reduce((s, r) => s + (parseFloat(r.qty) || 0), 0).toLocaleString()}
                      </TableCell>
                      <TableCell></TableCell>
                      <TableCell className="text-sm text-right text-blue-600">
                        {modalDetailRows.reduce((s, r) => s + (parseFloat(r.amount) || 0), 0).toLocaleString()}원
                      </TableCell>
                      <TableCell></TableCell>
                    </TableRow>
                  )}
                </TableBody>
              </Table>
            </div>
          </div>
        </div>

        {/* 품목 선택 모달 */}
        <Dialog open={itemSelectOpen} onOpenChange={setItemSelectOpen}>
          <DialogContent className="max-w-3xl max-h-[70vh]" onInteractOutside={(e) => e.preventDefault()}>
            <DialogHeader>
              <DialogTitle>품목 선택</DialogTitle>
              <DialogDescription>수주에 추가할 품목을 선택하세요. 품목이 없으면 &quot;행 추가&quot;로 직접 입력도 가능합니다.</DialogDescription>
            </DialogHeader>
            <div className="flex gap-2 mb-3">
              <Input placeholder="품명 검색" value={itemSearchKeyword}
                onChange={(e) => setItemSearchKeyword(e.target.value)}
                onKeyDown={(e) => e.key === "Enter" && searchItems()}
                className="h-9 flex-1" />
              <Button size="sm" onClick={searchItems} disabled={itemSearchLoading} className="h-9">
                {itemSearchLoading ? <Loader2 className="w-4 h-4 animate-spin" /> : <><Search className="w-4 h-4 mr-1" /> 조회</>}
              </Button>
            </div>
            <div className="overflow-auto max-h-[350px] border rounded-lg">
              <Table>
                <TableHeader className="sticky top-0 bg-background z-10">
                  <TableRow>
                    <TableHead className="w-[40px] text-center">
                      <input type="checkbox"
                        checked={itemSearchResults.length > 0 && itemCheckedIds.size === itemSearchResults.length}
                        onChange={(e) => {
                          if (e.target.checked) setItemCheckedIds(new Set(itemSearchResults.map((i) => i.id)));
                          else setItemCheckedIds(new Set());
                        }} />
                    </TableHead>
                    <TableHead className="w-[120px]">품목코드</TableHead>
                    <TableHead className="min-w-[150px]">품명</TableHead>
                    <TableHead className="w-[100px]">규격</TableHead>
                    <TableHead className="w-[60px]">단위</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {itemSearchResults.length === 0 ? (
                    <TableRow><TableCell colSpan={5} className="text-center text-muted-foreground py-8">검색 결과가 없습니다</TableCell></TableRow>
                  ) : itemSearchResults.map((item) => (
                    <TableRow key={item.id} className={cn("cursor-pointer", itemCheckedIds.has(item.id) && "bg-primary/5")}
                      onClick={() => setItemCheckedIds((prev) => {
                        const next = new Set(prev);
                        if (next.has(item.id)) next.delete(item.id); else next.add(item.id);
                        return next;
                      })}>
                      <TableCell className="text-center"><input type="checkbox" checked={itemCheckedIds.has(item.id)} readOnly /></TableCell>
                      <TableCell className="text-xs">{item.item_number}</TableCell>
                      <TableCell className="text-sm">{item.item_name}</TableCell>
                      <TableCell className="text-xs">{item.size}</TableCell>
                      <TableCell className="text-xs">{item.unit}</TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>
            <DialogFooter>
              <div className="flex items-center gap-2 w-full justify-between">
                <span className="text-sm text-muted-foreground">{itemCheckedIds.size}개 선택됨</span>
                <div className="flex gap-2">
                  <Button variant="outline" onClick={() => { setItemCheckedIds(new Set()); setItemSelectOpen(false); }}>취소</Button>
                  <Button onClick={addSelectedItemsToDetail} disabled={itemCheckedIds.size === 0}>
                    <Plus className="w-4 h-4 mr-1" /> {itemCheckedIds.size}개 추가
                  </Button>
                </div>
              </div>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      </FullscreenDialog>

      {/* 엑셀 업로드 — 단일 테이블 모드 + 커스텀 후처리 */}
      <ExcelUploadModal
        open={excelUploadOpen}
        onOpenChange={setExcelUploadOpen}
        tableName={DETAIL_TABLE}
        userId={user?.userId}
        onSuccess={handleExcelUploadSuccess}
      />

      {/* 테이블 설정 */}
      <TableSettingsModal
        open={tableSettingsOpen}
        onOpenChange={setTableSettingsOpen}
        tableName={MASTER_TABLE}
        settingsId="jeilglass-order"
        onSave={applyTableSettings}
      />

      {ConfirmDialogComponent}
    </div>
  );
}
