"use client";

import React, { useState, useEffect, useCallback } 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 {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription,
} from "@/components/ui/dialog";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import {
  Plus, Trash2, Save, Loader2, FileSpreadsheet, Download,
  ClipboardList, Pencil, Search, X, Package,
  ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight,
  Settings2,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";
import { useConfirmDialog } from "@/components/common/ConfirmDialog";
import { ExcelUploadModal } from "@/components/common/ExcelUploadModal";
import { exportToExcel } from "@/lib/utils/excelExport";
import { useAuth } from "@/hooks/useAuth";
import { toast } from "sonner";
import { useTableSettings } from "@/hooks/useTableSettings";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";

const MASTER_TABLE = "purchase_order_mng";
const DETAIL_TABLE = "purchase_detail";

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 STATUS_OPTIONS = [
  { code: "작성중", label: "작성중" },
  { code: "발주확정", label: "발주확정" },
  { code: "입고완료", label: "입고완료" },
  { code: "취소", label: "취소" },
];

const STATUS_BADGE_CLASS: Record<string, string> = {
  "작성중": "bg-warning/10 text-warning border-warning/20",
  "발주확정": "bg-primary/10 text-primary border-primary/20",
  "입고완료": "bg-success/10 text-success border-success/20",
  "취소": "bg-destructive/10 text-destructive border-destructive/20",
};

const EXCEL_COLUMNS = [
  { key: "purchase_no", label: "발주번호" },
  { key: "order_date", label: "발주일" },
  { key: "supplier_name", label: "공급업체명" },
  { key: "item_code", label: "품번" },
  { key: "item_name", label: "품명" },
  { key: "order_qty", label: "발주수량" },
  { key: "unit_price", label: "단가" },
  { key: "amount", label: "금액" },
  { key: "due_date", label: "납기일" },
];

const GRID_COLUMNS_CONFIG = [
  { key: "purchase_no", label: "발주번호" },
  { key: "order_date", label: "발주일" },
  { key: "supplier_name", label: "공급업체" },
  { key: "item_code", label: "품번" },
  { key: "item_name", label: "품명" },
  { key: "spec", label: "규격" },
  { key: "order_qty", label: "발주수량" },
  { key: "received_qty", label: "입고수량" },
  { key: "remain_qty", label: "잔량" },
  { key: "unit_price", label: "단가" },
  { key: "amount", label: "금액" },
  { key: "due_date", label: "납기일" },
  { key: "status", label: "상태" },
  { key: "memo", label: "메모" },
];

export default function PurchaseOrderPage() {
  const { user } = useAuth();
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();
  const [orders, setOrders] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const [totalCount, setTotalCount] = useState(0);

  // 검색 필터 (DynamicSearchFilter)
  const [searchFilters, setSearchFilters] = useState<FilterValue[]>([]);

  const [isModalOpen, setIsModalOpen] = useState(false);
  const [isEditMode, setIsEditMode] = useState(false);
  const [saving, setSaving] = useState(false);
  const [masterForm, setMasterForm] = useState<Record<string, any>>({});
  const [detailRows, setDetailRows] = useState<any[]>([]);

  // 품목 선택 모달
  const [itemSelectOpen, setItemSelectOpen] = useState(false);
  const [itemSearchKeyword, setItemSearchKeyword] = useState("");
  const [itemSearchResults, setItemSearchResults] = useState<any[]>([]);
  const [itemSearchLoading, setItemSearchLoading] = useState(false);
  const [itemSelectedMap, setItemSelectedMap] = useState<Map<string, any>>(new Map());
  const [itemSearchDivision, setItemSearchDivision] = useState("all");
  const [itemPage, setItemPage] = useState(1);
  const [itemPageSize, setItemPageSize] = useState(20);
  const [itemTotalPages, setItemTotalPages] = useState(0);
  const [itemTotal, setItemTotal] = useState(0);
  const [itemPageInput, setItemPageInput] = useState("1");

  const [excelUploadOpen, setExcelUploadOpen] = useState(false);
  const [categoryOptions, setCategoryOptions] = useState<Record<string, { code: string; label: string }[]>>({});
  const [checkedIds, setCheckedIds] = useState<string[]>([]);

  // 테이블 설정
  const ts = useTableSettings("c16-purchase-order", DETAIL_TABLE, GRID_COLUMNS_CONFIG);

  const isReadOnly = masterForm.status === "입고완료" || masterForm.status === "취소";

  // 카테고리 로드
  useEffect(() => {
    const loadCategories = async () => {
      const catColumns = ["input_mode", "price_mode"];
      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, label: v.valueLabel });
          if (v.children?.length) result.push(...flatten(v.children));
        }
        return result;
      };
      const dedup = (items: { code: string; label: string }[]) => {
        const seen = new Set<string>();
        return items.filter((item) => {
          const key = item.label.replace(/\s/g, "");
          if (seen.has(key)) return false;
          seen.add(key);
          return true;
        });
      };
      await Promise.all(
        catColumns.map(async (col) => {
          try {
            const res = await apiClient.get(`/table-categories/${MASTER_TABLE}/${col}/values`);
            if (res.data?.success && res.data.data?.length > 0) {
              optMap[col] = dedup(flatten(res.data.data));
            }
          } catch { /* skip */ }
        })
      );
      try {
        const suppRes = await apiClient.post(`/table-management/tables/supplier_mng/data`, {
          page: 1, size: 500, autoFilter: true,
        });
        const supps = suppRes.data?.data?.data || suppRes.data?.data?.rows || [];
        optMap["supplier_code"] = supps.map((s: any) => ({
          code: s.supplier_code,
          label: `${s.supplier_name} (${s.supplier_code})`,
        }));
      } catch { /* skip */ }
      try {
        const userRes = await apiClient.post(`/table-management/tables/user_info/data`, {
          page: 1, size: 500, autoFilter: true,
        });
        const users = userRes.data?.data?.data || userRes.data?.data?.rows || [];
        optMap["manager"] = users.map((u: any) => ({
          code: u.user_id || u.id,
          label: `${u.user_name || u.name || u.user_id}${u.position_name ? ` (${u.position_name})` : ""}`,
        }));
      } catch { /* skip */ }
      for (const col of ["unit", "material", "division"]) {
        try {
          const res = await apiClient.get(`/table-categories/item_info/${col}/values`);
          if (res.data?.success && res.data.data?.length > 0) {
            optMap[`item_${col}`] = flatten(res.data.data);
          }
        } catch { /* skip */ }
      }
      setCategoryOptions(optMap);
      const divs = optMap["item_division"] || [];
      const purchaseDiv = divs.find((o) => o.label === "구매관리")
        || divs.find((o) => o.label === "원자재")
        || divs.find((o) => o.label === "부자재");
      if (purchaseDiv) setItemSearchDivision(purchaseDiv.code);
    };
    loadCategories();
  }, []);

  // 마스터 테이블 컬럼 (supplier_name, order_date 등)
  const MASTER_COLUMNS = new Set(["supplier_name", "supplier_code", "order_date", "status"]);

  // 데이터 조회
  const fetchOrders = useCallback(async () => {
    setLoading(true);
    try {
      // searchFilters를 detail / master로 분리
      const detailFilters: any[] = [];
      const masterExtraFilters: any[] = [];
      for (const f of searchFilters) {
        const filter = { columnName: f.columnName, operator: f.operator, value: f.value };
        if (MASTER_COLUMNS.has(f.columnName)) {
          masterExtraFilters.push(filter);
        } else {
          detailFilters.push(filter);
        }
      }

      const res = await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/data`, {
        page: 1, size: 500,
        dataFilter: detailFilters.length > 0 ? { enabled: true, filters: detailFilters } : undefined,
        autoFilter: true,
        sort: { columnName: "purchase_no", order: "desc" },
      });
      const rows = res.data?.data?.data || res.data?.data?.rows || [];

      const purchaseNos = [...new Set(rows.map((r: any) => r.purchase_no).filter(Boolean))];
      let masterMap: Record<string, any> = {};
      if (purchaseNos.length > 0) {
        try {
          const masterFilters: any[] = [{ columnName: "purchase_no", operator: "in", value: purchaseNos }, ...masterExtraFilters];
          const masterRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/data`, {
            page: 1, size: purchaseNos.length + 10,
            dataFilter: { enabled: true, filters: masterFilters },
            autoFilter: true,
          });
          const masters = masterRes.data?.data?.data || masterRes.data?.data?.rows || [];
          for (const m of masters) masterMap[m.purchase_no] = m;
        } catch { /* skip */ }
      }

      const itemCodes = [...new Set(rows.map((r: any) => r.item_code).filter(Boolean))];
      let itemMap: Record<string, any> = {};
      if (itemCodes.length > 0) {
        try {
          const itemRes = await apiClient.post(`/table-management/tables/item_info/data`, {
            page: 1, size: itemCodes.length + 10,
            dataFilter: { enabled: true, filters: [{ columnName: "item_number", operator: "in", value: itemCodes }] },
            autoFilter: true,
          });
          const items = itemRes.data?.data?.data || itemRes.data?.data?.rows || [];
          for (const item of items) itemMap[item.item_number] = item;
        } catch { /* skip */ }
      }

      const resolveLabel = (key: string, code: string) => {
        if (!code) return "";
        const opts = categoryOptions[key];
        if (!opts) return code;
        return opts.find((o) => o.code === code)?.label || code;
      };

      const hasMasterFilters = masterExtraFilters.length > 0;
      const data = rows
        .filter((row: any) => {
          const master = masterMap[row.purchase_no];
          if (hasMasterFilters && !master) return false;
          return true;
        })
        .map((row: any) => {
          const item = itemMap[row.item_code];
          const master = masterMap[row.purchase_no];
          const rawUnit = row.unit || item?.unit || "";
          return {
            ...row,
            item_name: row.item_name || item?.item_name || "",
            spec: row.spec || item?.size || "",
            unit: resolveLabel("item_unit", rawUnit) || rawUnit,
            status: master?.status || "",
            supplier_name: master?.supplier_name || "",
            order_date: master?.order_date || "",
            memo: row.memo || master?.memo || "",
          };
        });

      setOrders(data);
      setTotalCount(data.length);
    } catch {
      toast.error("발주 목록을 불러오는데 실패했어요.");
    } finally {
      setLoading(false);
    }
  }, [searchFilters, categoryOptions]);

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

  const getCategoryLabel = (col: string, code: string) => {
    if (!code) return "";
    const found = categoryOptions[col]?.find((o) => o.code === code);
    return found?.label || code;
  };

  // 등록 모달 열기
  const openRegisterModal = () => {
    const defaultInputMode = categoryOptions["input_mode"]?.[0]?.code || "";
    const defaultPriceMode = categoryOptions["price_mode"]?.[0]?.code || "";
    setMasterForm({
      input_mode: defaultInputMode,
      price_mode: defaultPriceMode,
      manager: user?.userId || "",
      order_date: new Date().toISOString().split("T")[0],
      status: "작성중",
    });
    setDetailRows([]);
    setIsEditMode(false);
    setIsModalOpen(true);
  };

  // 수정 모달 열기
  const openEditModal = async (purchaseNo: string) => {
    try {
      const masterRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/data`, {
        page: 1, size: 1,
        dataFilter: { enabled: true, filters: [{ columnName: "purchase_no", operator: "equals", value: purchaseNo }] },
        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: "purchase_no", operator: "equals", value: purchaseNo }] },
        autoFilter: true,
      });
      const detailData = detailRes.data?.data?.data || detailRes.data?.data?.rows || [];

      setMasterForm(masterData || {});
      setDetailRows(detailData.map((d: any, i: number) => ({ ...d, _id: d.id || `row_${i}` })));
      setIsEditMode(true);
      setIsModalOpen(true);
    } catch {
      toast.error("발주 정보를 불러오는데 실패했어요.");
    }
  };

  // 삭제 (다중 선택)
  const handleDelete = async () => {
    if (checkedIds.length === 0) { toast.error("삭제할 발주를 선택해주세요."); return; }
    const selectedItems = orders.filter((o) => checkedIds.includes(o.id));
    const purchaseNos = [...new Set(selectedItems.map((o) => o.purchase_no))];
    const ok = await confirm(`${checkedIds.length}건의 발주 데이터를 삭제하시겠어요?`, {
      description: "삭제된 데이터는 복구할 수 없어요.",
      variant: "destructive",
      confirmText: "삭제",
    });
    if (!ok) return;
    try {
      await apiClient.delete(`/table-management/tables/${DETAIL_TABLE}/delete`, {
        data: checkedIds.map((id) => ({ id })),
      });
      for (const purchaseNo of purchaseNos) {
        const remaining = await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/data`, {
          page: 1, size: 1,
          dataFilter: { enabled: true, filters: [{ columnName: "purchase_no", operator: "equals", value: purchaseNo }] },
          autoFilter: true,
        });
        const remainRows = remaining.data?.data?.data || remaining.data?.data?.rows || [];
        if (remainRows.length === 0) {
          const masterRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/data`, {
            page: 1, size: 1,
            dataFilter: { enabled: true, filters: [{ columnName: "purchase_no", operator: "equals", value: purchaseNo }] },
            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([]);
      fetchOrders();
    } catch {
      toast.error("삭제에 실패했어요.");
    }
  };

  // 저장 (마스터 + 디테일)
  const handleSave = async () => {
    if (detailRows.length === 0) {
      toast.error("품목을 1개 이상 추가해주세요.");
      return;
    }
    setSaving(true);
    try {
      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: "purchase_no", operator: "equals", value: masterForm.purchase_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 })),
          });
        }
        for (const [idx, row] of detailRows.entries()) {
          const { _id, id: rowId, created_date: _cd, updated_date: _ud, writer: _w, company_code: _cc, ...detailFields } = row;
          await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/add`, {
            id: crypto.randomUUID(),
            ...detailFields,
            purchase_no: masterForm.purchase_no,
            seq_no: idx + 1,
          });
        }
      } else {
        const { purchase_no: _pn, ...fieldsWithoutPurchaseNo } = masterFields;
        const masterRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/add`, { id: crypto.randomUUID(), ...fieldsWithoutPurchaseNo });
        const createdData = masterRes.data?.data;
        let purchaseNo = createdData?.purchase_no;
        if (!purchaseNo) {
          const queryRes = await apiClient.post(`/table-management/tables/${MASTER_TABLE}/data`, {
            page: 1, size: 1,
            sort: { columnName: "created_date", order: "desc" },
            autoFilter: true,
          });
          const records = queryRes.data?.data?.data || queryRes.data?.data?.rows || [];
          purchaseNo = records[0]?.purchase_no;
        }
        if (!purchaseNo) {
          toast.error("발주번호를 가져올 수 없어요. 다시 시도해주세요.");
          return;
        }
        for (const [idx, row] of detailRows.entries()) {
          const { _id, id: rowId, created_date: _cd, updated_date: _ud, writer: _w, company_code: _cc, ...detailFields } = row;
          await apiClient.post(`/table-management/tables/${DETAIL_TABLE}/add`, {
            id: crypto.randomUUID(),
            ...detailFields,
            purchase_no: purchaseNo,
            seq_no: idx + 1,
          });
        }
      }

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

  // 품목 검색
  const searchItems = async (page?: number, size?: number) => {
    const p = page ?? itemPage;
    const s = size ?? itemPageSize;
    setItemSearchLoading(true);
    try {
      const filters: any[] = [];
      if (itemSearchKeyword) {
        filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
      }
      if (itemSearchDivision !== "all") {
        filters.push({ columnName: "division", operator: "contains", value: itemSearchDivision });
      }
      const res = await apiClient.post(`/table-management/tables/item_info/data`, {
        page: p, size: s,
        dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
        autoFilter: true,
      });
      const resData = res.data?.data;
      setItemSearchResults(resData?.data || resData?.rows || []);
      setItemTotal(resData?.total || 0);
      setItemTotalPages(resData?.totalPages || Math.ceil((resData?.total || 0) / s));
    } catch { /* skip */ } finally {
      setItemSearchLoading(false);
    }
  };

  const handleItemPageChange = (newPage: number) => {
    if (newPage < 1 || newPage > itemTotalPages) return;
    setItemPage(newPage);
    setItemPageInput(String(newPage));
    searchItems(newPage);
  };

  const commitItemPageInput = () => {
    const parsed = parseInt(itemPageInput, 10);
    if (isNaN(parsed) || itemPageInput.trim() === "") {
      setItemPageInput(String(itemPage));
      return;
    }
    const clamped = Math.max(1, Math.min(parsed, itemTotalPages || 1));
    if (clamped !== itemPage) handleItemPageChange(clamped);
    setItemPageInput(String(clamped));
  };

  const triggerNewSearch = () => {
    setItemPage(1);
    setItemPageInput("1");
    searchItems(1);
  };

  const addSelectedItemsToDetail = async () => {
    const selected = Array.from(itemSelectedMap.values());
    if (selected.length === 0) { toast.error("품목을 선택해주세요."); return; }

    const supplierCode = masterForm.supplier_code;
    let supplierPriceMap: Record<string, string> = {};
    if (supplierCode) {
      try {
        const itemIds = selected.map((item) => item.item_number || item.id);
        const res = await apiClient.post(`/table-management/tables/supplier_item_mapping/data`, {
          page: 1, size: 500,
          dataFilter: {
            enabled: true,
            filters: [
              { columnName: "supplier_code", operator: "equals", value: supplierCode },
              { columnName: "item_code", operator: "in", value: itemIds },
            ],
          },
          autoFilter: true,
        });
        const mappings = res.data?.data?.data || res.data?.data?.rows || [];
        for (const m of mappings) {
          const price = m.base_price || m.unit_price || "";
          if (price) supplierPriceMap[m.item_code] = String(price);
        }
      } catch { /* skip */ }
    }

    const newRows = selected.map((item) => {
      const itemCode = item.item_number || item.id;
      const unitPrice = supplierPriceMap[itemCode] || item.purchase_price || item.standard_price || "";
      return {
        _id: `new_${Date.now()}_${Math.random()}`,
        item_code: itemCode,
        item_name: item.item_name,
        spec: item.size || "",
        material: getCategoryLabel("item_material", item.material) || item.material || "",
        unit: getCategoryLabel("item_unit", item.unit) || item.unit || "",
        order_qty: "",
        received_qty: "0",
        remain_qty: "0",
        unit_price: unitPrice,
        amount: "",
        due_date: "",
        memo: "",
      };
    });

    setDetailRows((prev) => [...prev, ...newRows]);
    toast.success(`${selected.length}개 품목이 추가되었어요.`);
    setItemSelectedMap(new Map());
    setItemSelectOpen(false);
  };

  const updateDetailRow = (idx: number, field: string, value: string) => {
    setDetailRows((prev) => {
      const next = [...prev];
      next[idx] = { ...next[idx], [field]: value };
      if (field === "order_qty" || field === "unit_price") {
        const qty = parseFloat(field === "order_qty" ? value : next[idx].order_qty) || 0;
        const price = parseFloat(field === "unit_price" ? value : next[idx].unit_price) || 0;
        next[idx].amount = (qty * price).toString();
        const received = parseFloat(next[idx].received_qty) || 0;
        next[idx].remain_qty = (qty - received).toString();
      }
      return next;
    });
  };

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

  const handleExcelDownload = async () => {
    if (orders.length === 0) { toast.error("다운로드할 데이터가 없어요."); return; }
    const data = orders.map((o) => {
      const row: Record<string, any> = {};
      for (const col of EXCEL_COLUMNS) row[col.label] = o[col.key] || "";
      return row;
    });
    await exportToExcel(data, "발주관리.xlsx", "발주목록");
    toast.success("다운로드 완료");
  };

  const allChecked = orders.length > 0 && checkedIds.length === orders.length;
  const someChecked = checkedIds.length > 0 && checkedIds.length < orders.length;

  return (
    <div className="flex h-full flex-col gap-3 p-3">
      {/* 검색 필터 바 */}
      <DynamicSearchFilter
        tableName={DETAIL_TABLE}
        filterId="c16-purchase-order"
        onFilterChange={setSearchFilters}
        dataCount={totalCount}
        externalFilterConfig={ts.filterConfig}
      />

      {/* 액션 바 */}
      <div className="flex items-center justify-between flex-wrap gap-3">
        <div className="flex items-center gap-3">
          <h2 className="text-lg font-bold">발주 목록</h2>
          <span className="inline-flex items-center rounded-full border border-primary/15 bg-primary/5 px-2.5 py-0.5 font-mono text-[11px] font-bold text-primary">
            {totalCount}건
          </span>
        </div>
        <div className="flex items-center gap-2">
          <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 = orders.find((o) => o.id === checkedIds[0]);
            if (item) openEditModal(item.purchase_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" /> 삭제 {checkedIds.length > 0 && `(${checkedIds.length})`}
          </Button>
          <div className="h-5 w-px bg-border mx-0.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>
          <div className="h-5 w-px bg-border mx-0.5" />
          <Button variant="outline" size="sm" onClick={() => ts.setOpen(true)}>
            <Settings2 className="w-4 h-4 mr-1" /> 설정
          </Button>
        </div>
      </div>

      {/* 데이터 테이블 */}
      <div className="flex-1 overflow-auto border rounded-lg bg-card">
        <Table>
          <TableHeader className="sticky top-0 z-10">
            <TableRow className="bg-muted hover:bg-muted">
              <TableHead className="w-[44px] text-center">
                <Checkbox
                  checked={allChecked}
                  data-state={someChecked ? "indeterminate" : undefined}
                  onCheckedChange={(checked) => {
                    setCheckedIds(checked ? orders.map((o) => o.id) : []);
                  }}
                />
              </TableHead>
              {ts.isVisible("purchase_no") && <TableHead className="w-[120px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">발주번호</TableHead>}
              {ts.isVisible("order_date") && <TableHead className="w-[110px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">발주일</TableHead>}
              {ts.isVisible("supplier_name") && <TableHead className="w-[140px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">공급업체</TableHead>}
              {ts.isVisible("item_code") && <TableHead className="w-[120px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품번</TableHead>}
              {ts.isVisible("item_name") && <TableHead className="w-[140px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품명</TableHead>}
              {ts.isVisible("spec") && <TableHead className="w-[100px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">규격</TableHead>}
              {ts.isVisible("order_qty") && <TableHead className="w-[80px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">발주수량</TableHead>}
              {ts.isVisible("received_qty") && <TableHead className="w-[80px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">입고수량</TableHead>}
              {ts.isVisible("remain_qty") && <TableHead className="w-[70px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">잔량</TableHead>}
              {ts.isVisible("unit_price") && <TableHead className="w-[100px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">단가</TableHead>}
              {ts.isVisible("amount") && <TableHead className="w-[110px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">금액</TableHead>}
              {ts.isVisible("due_date") && <TableHead className="w-[110px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">납기일</TableHead>}
              {ts.isVisible("status") && <TableHead className="w-[90px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">상태</TableHead>}
              {ts.isVisible("memo") && <TableHead className="w-[120px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">메모</TableHead>}
            </TableRow>
          </TableHeader>
          <TableBody>
            {loading ? (
              <TableRow>
                <TableCell colSpan={ts.visibleColumns.length + 1} className="text-center py-12">
                  <Loader2 className="w-6 h-6 animate-spin mx-auto text-muted-foreground" />
                </TableCell>
              </TableRow>
            ) : orders.length === 0 ? (
              <TableRow>
                <TableCell colSpan={ts.visibleColumns.length + 1} className="text-center py-12 text-muted-foreground text-sm">
                  등록된 발주가 없어요
                </TableCell>
              </TableRow>
            ) : orders.map((row) => (
              <TableRow
                key={row.id}
                className={cn("cursor-pointer", checkedIds.includes(row.id) && "bg-primary/5")}
                onDoubleClick={() => openEditModal(row.purchase_no)}
              >
                <TableCell className="text-center" onClick={(e) => e.stopPropagation()}>
                  <Checkbox
                    checked={checkedIds.includes(row.id)}
                    onCheckedChange={(checked) => {
                      setCheckedIds((prev) =>
                        checked ? [...prev, row.id] : prev.filter((id) => id !== row.id)
                      );
                    }}
                  />
                </TableCell>
                {ts.isVisible("purchase_no") && <TableCell className="text-[13px] font-mono">{row.purchase_no}</TableCell>}
                {ts.isVisible("order_date") && <TableCell className="text-[13px]">{row.order_date}</TableCell>}
                {ts.isVisible("supplier_name") && <TableCell className="text-[13px] max-w-[140px]"><span className="block truncate" title={row.supplier_name}>{row.supplier_name}</span></TableCell>}
                {ts.isVisible("item_code") && <TableCell className="text-[13px] font-mono max-w-[120px]"><span className="block truncate" title={row.item_code}>{row.item_code}</span></TableCell>}
                {ts.isVisible("item_name") && <TableCell className="text-[13px] max-w-[140px]"><span className="block truncate" title={row.item_name}>{row.item_name}</span></TableCell>}
                {ts.isVisible("spec") && <TableCell className="text-[13px] text-muted-foreground">{row.spec}</TableCell>}
                {ts.isVisible("order_qty") && <TableCell className="text-[13px] text-right font-mono">{row.order_qty ? Number(row.order_qty).toLocaleString() : ""}</TableCell>}
                {ts.isVisible("received_qty") && <TableCell className="text-[13px] text-right font-mono">{row.received_qty ? Number(row.received_qty).toLocaleString() : ""}</TableCell>}
                {ts.isVisible("remain_qty") && <TableCell className="text-[13px] text-right font-mono">{row.remain_qty ? Number(row.remain_qty).toLocaleString() : ""}</TableCell>}
                {ts.isVisible("unit_price") && <TableCell className="text-[13px] text-right font-mono">{row.unit_price ? Number(row.unit_price).toLocaleString() : ""}</TableCell>}
                {ts.isVisible("amount") && <TableCell className="text-[13px] text-right font-mono font-semibold">{row.amount ? Number(row.amount).toLocaleString() : ""}</TableCell>}
                {ts.isVisible("due_date") && <TableCell className="text-[13px]">{row.due_date}</TableCell>}
                {ts.isVisible("status") && (
                  <TableCell>
                    {row.status && (
                      <span className={cn("inline-flex items-center rounded-full border px-2 py-0.5 text-[11px] font-semibold", STATUS_BADGE_CLASS[row.status] || "")}>
                        {row.status}
                      </span>
                    )}
                  </TableCell>
                )}
                {ts.isVisible("memo") && <TableCell className="text-[13px] text-muted-foreground max-w-[120px]"><span className="block truncate">{row.memo}</span></TableCell>}
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </div>

      {/* 발주 등록/수정 모달 */}
      <Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
        <DialogContent
          className="max-w-[95vw] w-[1200px]"
          style={{ maxHeight: "90vh", display: "flex", flexDirection: "column" }}
        >
          <DialogHeader>
            <DialogTitle>{isEditMode ? (isReadOnly ? "발주 상세" : "발주 수정") : "발주 등록"}</DialogTitle>
            <DialogDescription>
              {isEditMode ? (isReadOnly ? "발주 상세 정보를 확인해요." : "발주 정보를 수정해요.") : "새로운 발주를 등록해요."}
            </DialogDescription>
          </DialogHeader>

          <div className="flex-1 overflow-y-auto">
            <div className="space-y-6 py-2 pr-1">
              {/* 기본 정보 */}
              <div className="space-y-3">
                <div className="flex items-center gap-2 text-[13px] font-bold text-muted-foreground">
                  기본 정보
                  <div className="flex-1 h-px bg-border" />
                </div>
                <div className="grid grid-cols-4 gap-3.5">
                  <div className="space-y-1">
                    <Label className="text-[11px] font-semibold text-muted-foreground tracking-wide">발주번호</Label>
                    <Input value={masterForm.purchase_no || ""} placeholder={isEditMode ? "" : "자동생성"} className="h-9" disabled />
                  </div>
                  <div className="space-y-1">
                    <Label className="text-[11px] font-semibold text-muted-foreground tracking-wide">발주일 <span className="text-destructive">*</span></Label>
                    <Input
                      type="date"
                      value={masterForm.order_date || ""}
                      onChange={(e) => setMasterForm((p) => ({ ...p, order_date: e.target.value }))}
                      className="h-9"
                      disabled={isReadOnly}
                    />
                  </div>
                  <div className="space-y-1">
                    <Label className="text-[11px] font-semibold text-muted-foreground tracking-wide">상태</Label>
                    {isReadOnly ? (
                      <div className="flex items-center h-9">
                        <span className={cn("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold", STATUS_BADGE_CLASS[masterForm.status] || "")}>
                          {masterForm.status}
                        </span>
                      </div>
                    ) : (
                      <Select value={masterForm.status || "작성중"} onValueChange={(v) => setMasterForm((p) => ({ ...p, status: v }))}>
                        <SelectTrigger className="h-9"><SelectValue /></SelectTrigger>
                        <SelectContent>
                          {STATUS_OPTIONS.map((s) => (
                            <SelectItem key={s.code} value={s.code}>{s.label}</SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    )}
                  </div>
                  <div className="space-y-1">
                    <Label className="text-[11px] font-semibold text-muted-foreground tracking-wide">입력방식</Label>
                    <Select value={masterForm.input_mode || ""} onValueChange={(v) => setMasterForm((p) => ({ ...p, input_mode: v }))} disabled={isReadOnly}>
                      <SelectTrigger className="h-9"><SelectValue placeholder="선택" /></SelectTrigger>
                      <SelectContent>
                        {(categoryOptions["input_mode"] || []).map((o) => (
                          <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                  <div className="space-y-1">
                    <Label className="text-[11px] font-semibold text-muted-foreground tracking-wide">단가방식</Label>
                    <Select value={masterForm.price_mode || ""} onValueChange={(v) => setMasterForm((p) => ({ ...p, price_mode: v }))} disabled={isReadOnly}>
                      <SelectTrigger className="h-9"><SelectValue placeholder="선택" /></SelectTrigger>
                      <SelectContent>
                        {(categoryOptions["price_mode"] || []).map((o) => (
                          <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                </div>
              </div>

              {/* 공급업체 / 담당자 */}
              <div className="p-4 bg-muted/50 border border-dashed border-border rounded-lg space-y-3">
                <div className="text-xs font-semibold text-primary flex items-center gap-1.5">
                  <ClipboardList className="w-3.5 h-3.5" /> 공급업체 정보
                </div>
                <div className="grid grid-cols-3 gap-3.5">
                  <div className="space-y-1">
                    <Label className="text-[11px] font-semibold text-muted-foreground tracking-wide">공급업체</Label>
                    <Select
                      value={masterForm.supplier_code || ""}
                      onValueChange={(v) => {
                        const supp = categoryOptions["supplier_code"]?.find((o) => o.code === v);
                        const name = supp?.label.replace(` (${v})`, "") || "";
                        setMasterForm((p) => ({ ...p, supplier_code: v, supplier_name: name }));
                      }}
                      disabled={isReadOnly}
                    >
                      <SelectTrigger className="h-9"><SelectValue placeholder="공급업체 선택" /></SelectTrigger>
                      <SelectContent>
                        {(categoryOptions["supplier_code"] || []).map((o) => (
                          <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                  <div className="space-y-1">
                    <Label className="text-[11px] font-semibold text-muted-foreground tracking-wide">담당자</Label>
                    <Select
                      value={masterForm.manager || ""}
                      onValueChange={(v) => setMasterForm((p) => ({ ...p, manager: v }))}
                      disabled={isReadOnly}
                    >
                      <SelectTrigger className="h-9"><SelectValue placeholder="담당자 선택" /></SelectTrigger>
                      <SelectContent>
                        {(categoryOptions["manager"] || []).map((o) => (
                          <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                </div>
              </div>

              {/* 품목 내역 */}
              <div className="space-y-2.5">
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-2 text-[13px] font-bold text-muted-foreground">
                    <Package className="w-4 h-4" /> 품목 내역
                    <span className="inline-flex items-center rounded-full border border-primary/15 bg-primary/5 px-2 py-0.5 font-mono text-[11px] font-bold text-primary">
                      {detailRows.length}
                    </span>
                  </div>
                  {!isReadOnly && (
                    <Button size="sm" onClick={() => {
                      setItemSelectedMap(new Map());
                      setItemPage(1);
                      setItemPageInput("1");
                      setItemSearchKeyword("");
                      setItemSelectOpen(true);
                      searchItems(1);
                    }}>
                      <Plus className="w-4 h-4 mr-1" /> 품목 추가
                    </Button>
                  )}
                </div>
                {detailRows.length === 0 ? (
                  <div className="flex flex-col items-center gap-2 py-8 border border-dashed border-border rounded-lg text-muted-foreground">
                    <Package className="w-8 h-8 opacity-40" />
                    <span className="text-sm">아직 추가된 품목이 없어요. 위 버튼으로 품목을 추가해주세요.</span>
                  </div>
                ) : (
                  <div className="border rounded-lg overflow-x-auto">
                    <Table className="table-fixed">
                      <TableHeader className="sticky top-0 z-10">
                        <TableRow className="bg-muted hover:bg-muted">
                          {!isReadOnly && <TableHead className="w-[40px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground"></TableHead>}
                          <TableHead className="w-[120px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품번</TableHead>
                          <TableHead className="w-[120px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품명</TableHead>
                          <TableHead className="w-[80px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">규격</TableHead>
                          <TableHead className="w-[60px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">단위</TableHead>
                          <TableHead className="w-[90px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">발주수량</TableHead>
                          <TableHead className="w-[90px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">입고수량</TableHead>
                          <TableHead className="w-[80px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">잔량</TableHead>
                          <TableHead className="w-[100px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">단가</TableHead>
                          <TableHead className="w-[100px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">금액</TableHead>
                          <TableHead className="w-[160px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">납기일</TableHead>
                          <TableHead className="w-[120px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">메모</TableHead>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {detailRows.map((row, idx) => (
                          <TableRow key={row._id || idx}>
                            {!isReadOnly && (
                              <TableCell>
                                <Button variant="ghost" size="sm" className="h-7 w-7 p-0 text-muted-foreground/50 hover:text-destructive hover:bg-destructive/5" onClick={() => removeDetailRow(idx)}>
                                  <X className="w-3.5 h-3.5" />
                                </Button>
                              </TableCell>
                            )}
                            <TableCell className="text-[13px] font-mono max-w-[120px]"><span className="block truncate" title={row.item_code}>{row.item_code}</span></TableCell>
                            <TableCell className="text-[13px] max-w-[120px]"><span className="block truncate" title={row.item_name}>{row.item_name}</span></TableCell>
                            <TableCell className="text-[13px] text-muted-foreground">{row.spec}</TableCell>
                            <TableCell className="text-[13px]">{row.unit}</TableCell>
                            <TableCell>
                              {isReadOnly ? (
                                <span className="text-xs text-right font-mono block">{row.order_qty ? Number(row.order_qty).toLocaleString() : ""}</span>
                              ) : (
                                <Input value={formatNumber(row.order_qty || "")} onChange={(e) => updateDetailRow(idx, "order_qty", parseNumber(e.target.value))} className="h-8 text-xs text-right font-mono" />
                              )}
                            </TableCell>
                            <TableCell className="text-[13px] text-right font-mono text-muted-foreground">{row.received_qty ? Number(row.received_qty).toLocaleString() : "0"}</TableCell>
                            <TableCell className="text-[13px] text-right font-mono">{row.remain_qty ? Number(row.remain_qty).toLocaleString() : "0"}</TableCell>
                            <TableCell>
                              {isReadOnly ? (
                                <span className="text-xs text-right font-mono block">{row.unit_price ? Number(row.unit_price).toLocaleString() : ""}</span>
                              ) : (
                                <Input value={formatNumber(row.unit_price || "")} onChange={(e) => updateDetailRow(idx, "unit_price", parseNumber(e.target.value))} className="h-8 text-xs text-right font-mono" />
                              )}
                            </TableCell>
                            <TableCell className="text-[13px] text-right font-mono font-semibold">{row.amount ? Number(row.amount).toLocaleString() : ""}</TableCell>
                            <TableCell>
                              {isReadOnly ? (
                                <span className="text-xs">{row.due_date}</span>
                              ) : (
                                <Input type="date" value={row.due_date || ""} onChange={(e) => updateDetailRow(idx, "due_date", e.target.value)} className="h-8 text-xs" />
                              )}
                            </TableCell>
                            <TableCell>
                              {isReadOnly ? (
                                <span className="text-xs">{row.memo}</span>
                              ) : (
                                <Input value={row.memo || ""} onChange={(e) => updateDetailRow(idx, "memo", e.target.value)} className="h-8 text-xs" />
                              )}
                            </TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </div>
                )}
              </div>

              {/* 비고 */}
              <div className="space-y-3">
                <div className="flex items-center gap-2 text-[13px] font-bold text-muted-foreground">
                  비고
                  <div className="flex-1 h-px bg-border" />
                </div>
                <Input
                  value={masterForm.memo || ""}
                  onChange={(e) => setMasterForm((p) => ({ ...p, memo: e.target.value }))}
                  placeholder="특이사항이나 메모를 입력해주세요"
                  className="h-9"
                  disabled={isReadOnly}
                />
              </div>
            </div>
          </div>

          <DialogFooter className="border-t pt-3 mt-2">
            {isReadOnly ? (
              <Button variant="outline" onClick={() => setIsModalOpen(false)}>닫기</Button>
            ) : (
              <>
                <Button variant="outline" onClick={() => setIsModalOpen(false)}>취소</Button>
                <Button onClick={handleSave} disabled={saving}>
                  {saving ? <Loader2 className="w-4 h-4 animate-spin mr-1" /> : <Save className="w-4 h-4 mr-1" />} 저장
                </Button>
              </>
            )}
          </DialogFooter>

          {/* 품목 선택 모달 (중첩) */}
          <Dialog open={itemSelectOpen} onOpenChange={setItemSelectOpen}>
            <DialogContent className="max-w-3xl" style={{ maxHeight: "70vh", display: "flex", flexDirection: "column" }} onInteractOutside={(e) => e.preventDefault()}>
              <DialogHeader>
                <DialogTitle>품목 선택</DialogTitle>
                <DialogDescription>발주에 추가할 품목을 선택 후 하단 버튼을 눌러주세요.</DialogDescription>
              </DialogHeader>
              <div className="flex gap-2">
                <Input
                  placeholder="품명/품목코드 검색"
                  value={itemSearchKeyword}
                  onChange={(e) => setItemSearchKeyword(e.target.value)}
                  onKeyDown={(e) => e.key === "Enter" && triggerNewSearch()}
                  className="h-9 flex-1"
                />
                <Select value={itemSearchDivision} onValueChange={setItemSearchDivision}>
                  <SelectTrigger className="h-9 w-[130px]"><SelectValue placeholder="관리품목" /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="all">전체</SelectItem>
                    {(categoryOptions["item_division"] || []).map((o) => (
                      <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <Button size="sm" onClick={triggerNewSearch} 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="flex-1 overflow-auto border rounded-lg">
                <Table>
                  <TableHeader className="sticky top-0 z-10">
                    <TableRow className="bg-muted hover:bg-muted">
                      <TableHead className="w-[40px] text-center">
                        <input type="checkbox"
                          checked={itemSearchResults.length > 0 && itemSearchResults.every((i) => itemSelectedMap.has(i.id))}
                          onChange={(e) => {
                            setItemSelectedMap((prev) => {
                              const next = new Map(prev);
                              if (e.target.checked) itemSearchResults.forEach((i) => next.set(i.id, i));
                              else itemSearchResults.forEach((i) => next.delete(i.id));
                              return next;
                            });
                          }} />
                      </TableHead>
                      <TableHead className="w-[130px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품목코드</TableHead>
                      <TableHead className="min-w-[150px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품명</TableHead>
                      <TableHead className="w-[100px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">규격</TableHead>
                      <TableHead className="w-[100px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">재질</TableHead>
                      <TableHead className="w-[60px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">단위</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {itemSearchResults.length === 0 ? (
                      <TableRow><TableCell colSpan={6} className="text-center text-muted-foreground py-8">검색 결과가 없어요</TableCell></TableRow>
                    ) : itemSearchResults.map((item) => (
                      <TableRow key={item.id} className={cn("cursor-pointer", itemSelectedMap.has(item.id) && "bg-primary/5")}
                        onClick={() => setItemSelectedMap((prev) => {
                          const next = new Map(prev);
                          if (next.has(item.id)) next.delete(item.id); else next.set(item.id, item);
                          return next;
                        })}>
                        <TableCell className="text-center">
                          <input type="checkbox" checked={itemSelectedMap.has(item.id)} readOnly />
                        </TableCell>
                        <TableCell className="text-[13px] max-w-[130px]"><span className="block truncate" title={item.item_number}>{item.item_number}</span></TableCell>
                        <TableCell className="text-sm max-w-[150px]"><span className="block truncate" title={item.item_name}>{item.item_name}</span></TableCell>
                        <TableCell className="text-[13px]">{item.size}</TableCell>
                        <TableCell className="text-[13px]">{categoryOptions["item_material"]?.find((o) => o.code === item.material)?.label || item.material}</TableCell>
                        <TableCell className="text-[13px]">{categoryOptions["item_unit"]?.find((o) => o.code === item.unit)?.label || item.unit}</TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>
              <div className="flex items-center justify-between border-t pt-2">
                <div className="flex items-center gap-1">
                  <span className="text-xs text-muted-foreground">표시:</span>
                  <input type="number" min={1} max={200} value={itemPageSize}
                    onChange={(e) => {
                      const v = Math.min(200, Math.max(1, Number(e.target.value) || 20));
                      setItemPageSize(v);
                      setItemPage(1);
                      setItemPageInput("1");
                      searchItems(1, v);
                    }}
                    className="h-7 w-14 rounded-md border px-1 text-center text-xs" />
                </div>
                <div className="flex items-center gap-1">
                  <Button variant="outline" size="sm" className="h-7 w-7 p-0" onClick={() => handleItemPageChange(1)} disabled={itemPage === 1 || itemSearchLoading}>
                    <ChevronsLeft className="h-3 w-3" />
                  </Button>
                  <Button variant="outline" size="sm" className="h-7 w-7 p-0" onClick={() => handleItemPageChange(itemPage - 1)} disabled={itemPage === 1 || itemSearchLoading}>
                    <ChevronLeft className="h-3 w-3" />
                  </Button>
                  <input type="text" inputMode="numeric" value={itemPageInput}
                    onChange={(e) => setItemPageInput(e.target.value)}
                    onKeyDown={(e) => { if (e.key === "Enter") { commitItemPageInput(); (e.target as HTMLInputElement).blur(); } }}
                    onBlur={commitItemPageInput}
                    onFocus={(e) => e.target.select()}
                    className="h-7 w-10 rounded-md border px-1 text-center text-xs" />
                  <span className="text-xs text-muted-foreground">/ {itemTotalPages || 1}</span>
                  <Button variant="outline" size="sm" className="h-7 w-7 p-0" onClick={() => handleItemPageChange(itemPage + 1)} disabled={itemPage >= itemTotalPages || itemSearchLoading}>
                    <ChevronRight className="h-3 w-3" />
                  </Button>
                  <Button variant="outline" size="sm" className="h-7 w-7 p-0" onClick={() => handleItemPageChange(itemTotalPages)} disabled={itemPage >= itemTotalPages || itemSearchLoading}>
                    <ChevronsRight className="h-3 w-3" />
                  </Button>
                </div>
                <span className="text-xs text-muted-foreground">총 {itemTotal}건</span>
              </div>
              <DialogFooter>
                <div className="flex items-center gap-2 w-full justify-between">
                  <span className="text-sm text-muted-foreground">{itemSelectedMap.size}개 선택됨</span>
                  <div className="flex gap-2">
                    <Button variant="outline" onClick={() => { setItemSelectedMap(new Map()); setItemSelectOpen(false); }}>취소</Button>
                    <Button onClick={addSelectedItemsToDetail} disabled={itemSelectedMap.size === 0}>
                      <Plus className="w-4 h-4 mr-1" /> {itemSelectedMap.size}개 추가
                    </Button>
                  </div>
                </div>
              </DialogFooter>
            </DialogContent>
          </Dialog>
        </DialogContent>
      </Dialog>

      {/* 엑셀 업로드 */}
      <ExcelUploadModal
        open={excelUploadOpen}
        onOpenChange={setExcelUploadOpen}
        tableName={DETAIL_TABLE}
        userId={user?.userId}
        onSuccess={() => fetchOrders()}
      />

      {/* 테이블 설정 모달 */}
      <TableSettingsModal
        open={ts.open}
        onOpenChange={ts.setOpen}
        tableName={ts.tableName}
        settingsId={ts.settingsId}
        defaultVisibleKeys={ts.defaultVisibleKeys}
        onSave={ts.applySettings}
      />

      {ConfirmDialogComponent}
    </div>
  );
}
