"use client";

import React, { useState, useEffect, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  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, DialogDescription, DialogFooter } from "@/components/ui/dialog";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandInput, CommandList, CommandEmpty, CommandItem } from "@/components/ui/command";
import { useConfirmDialog } from "@/components/common/ConfirmDialog";
import {
  Plus, Trash2, Loader2, Package, Box, X, Save, Edit2, Download, ChevronsUpDown, Check, Inbox, Settings2,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { toast } from "sonner";
import {
  getPkgUnits, createPkgUnit, updatePkgUnit, deletePkgUnit,
  getPkgUnitItems, createPkgUnitItem, deletePkgUnitItem,
  getLoadingUnits, createLoadingUnit, updateLoadingUnit, deleteLoadingUnit,
  getLoadingUnitPkgs, createLoadingUnitPkg, deleteLoadingUnitPkg,
  getItemsByDivision, getGeneralItems,
  type PkgUnit, type PkgUnitItem, type LoadingUnit, type LoadingUnitPkg, type ItemInfoForPkg,
} from "@/lib/api/packaging";
import { apiClient } from "@/lib/api/client";
import { useTableSettings } from "@/hooks/useTableSettings";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";
import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable";

const GRID_COLUMNS = [
  { key: "pkg_code", label: "품목코드" },
  { key: "pkg_name", label: "포장명" },
  { key: "pkg_type", label: "유형" },
  { key: "size", label: "크기(mm)" },
  { key: "max_load_kg", label: "최대중량" },
  { key: "status", label: "상태" },
];

// --- 코드 → 라벨 매핑 ---
const PKG_TYPE_LABEL: Record<string, string> = {
  BOX: "박스", PACK: "팩", CANBOARD: "캔보드", AIRCAP: "에어캡",
  ZIPCOS: "집코스", CYLINDER: "원통형", POLYCARTON: "포리/카톤",
};
const LOADING_TYPE_LABEL: Record<string, string> = {
  PALLET: "파렛트", WOOD_PALLET: "목재파렛트", PLASTIC_PALLET: "플라스틱파렛트",
  ALU_PALLET: "알루미늄파렛트", CONTAINER: "컨테이너", STEEL_BOX: "철재함",
  CAGE: "케이지", ETC: "기타",
};
const STATUS_LABEL: Record<string, string> = { ACTIVE: "사용", INACTIVE: "미사용", UNREGISTERED: "미등록" };

const getStatusColor = (s: string) => s === "ACTIVE" ? "bg-success/10 text-success" : "bg-muted text-muted-foreground";
const fmtSize = (w: any, l: any, h: any) => {
  const vals = [w, l, h].map(v => Number(v) || 0);
  return vals.some(v => v > 0) ? vals.join("×") : "-";
};

// 규격 문자열에서 치수 파싱
function parseSpecDimensions(spec: string | null) {
  if (!spec) return { w: 0, l: 0, h: 0 };
  const m3 = spec.match(/(\d+)\s*[x×]\s*(\d+)\s*[x×]\s*(\d+)/i);
  if (m3) return { w: parseInt(m3[1]), l: parseInt(m3[2]), h: parseInt(m3[3]) };
  const m2 = spec.match(/(\d+)\s*[x×]\s*(\d+)/i);
  if (m2) return { w: parseInt(m2[1]), l: parseInt(m2[2]), h: 0 };
  return { w: 0, l: 0, h: 0 };
}

export default function PackagingPage() {
  const ts = useTableSettings("c16-packaging", "pkg_unit", GRID_COLUMNS);
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();
  const [activeTab, setActiveTab] = useState<"packing" | "loading">("packing");

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

  // 포장재 데이터
  const [pkgUnits, setPkgUnits] = useState<PkgUnit[]>([]);
  const [pkgLoading, setPkgLoading] = useState(false);
  const [selectedPkg, setSelectedPkg] = useState<PkgUnit | null>(null);
  const [pkgItems, setPkgItems] = useState<PkgUnitItem[]>([]);
  const [pkgItemsLoading, setPkgItemsLoading] = useState(false);

  // 적재함 데이터
  const [loadingUnits, setLoadingUnits] = useState<LoadingUnit[]>([]);
  const [loadingLoading, setLoadingLoading] = useState(false);
  const [selectedLoading, setSelectedLoading] = useState<LoadingUnit | null>(null);
  const [loadingPkgs, setLoadingPkgs] = useState<LoadingUnitPkg[]>([]);
  const [loadingPkgsLoading, setLoadingPkgsLoading] = useState(false);

  // 모달
  const [pkgModalOpen, setPkgModalOpen] = useState(false);
  const [pkgModalMode, setPkgModalMode] = useState<"create" | "edit">("create");
  const [pkgForm, setPkgForm] = useState<Record<string, any>>({});
  const [pkgItemOptions, setPkgItemOptions] = useState<ItemInfoForPkg[]>([]);
  const [pkgItemPopoverOpen, setPkgItemPopoverOpen] = useState(false);

  const [loadModalOpen, setLoadModalOpen] = useState(false);
  const [loadModalMode, setLoadModalMode] = useState<"create" | "edit">("create");
  const [loadForm, setLoadForm] = useState<Record<string, any>>({});
  const [loadItemOptions, setLoadItemOptions] = useState<ItemInfoForPkg[]>([]);
  const [loadItemPopoverOpen, setLoadItemPopoverOpen] = useState(false);

  const [itemMatchModalOpen, setItemMatchModalOpen] = useState(false);
  const [itemMatchKeyword, setItemMatchKeyword] = useState("");
  const [itemMatchResults, setItemMatchResults] = useState<ItemInfoForPkg[]>([]);
  const [itemMatchSelected, setItemMatchSelected] = useState<ItemInfoForPkg | null>(null);
  const [itemMatchQty, setItemMatchQty] = useState(1);

  const [pkgMatchModalOpen, setPkgMatchModalOpen] = useState(false);
  const [pkgMatchQty, setPkgMatchQty] = useState(1);
  const [pkgMatchMethod, setPkgMatchMethod] = useState("");
  const [pkgMatchSelected, setPkgMatchSelected] = useState<PkgUnit | null>(null);
  const [pkgMatchSearchKw, setPkgMatchSearchKw] = useState("");

  const [saving, setSaving] = useState(false);

  // 카테고리 옵션 (inventory_unit / material) — 코드 → 라벨 변환
  const [categoryOptions, setCategoryOptions] = useState<
    Record<string, { code: string; label: string }[]>
  >({});

  useEffect(() => {
    const load = async () => {
      const flatten = (vals: any[]): { code: string; label: string }[] => {
        const out: { code: string; label: string }[] = [];
        for (const v of vals) {
          out.push({
            code: v.valueCode || v.value_code || v.code,
            label: v.valueLabel || v.value_label || v.label,
          });
          if (v.children?.length) out.push(...flatten(v.children));
        }
        return out;
      };
      const optMap: Record<string, { code: string; label: string }[]> = {};
      for (const col of ["inventory_unit", "material"]) {
        try {
          const res = await apiClient.get(
            `/table-categories/item_info/${col}/values`
          );
          if (res.data?.success) optMap[col] = flatten(res.data.data || []);
        } catch {
          /* skip */
        }
      }
      setCategoryOptions(optMap);
    };
    load();
  }, []);

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

  // --- 데이터 로드 (item_info 기반 + pkg_unit/loading_unit LEFT JOIN 방식) ---
  const fetchPkgUnits = useCallback(async () => {
    setPkgLoading(true);
    try {
      const [itemRes, pkgRes] = await Promise.all([
        getItemsByDivision("포장재"),
        getPkgUnits(),
      ]);
      const items = itemRes.success ? itemRes.data : [];
      const existing = pkgRes.success ? pkgRes.data : [];
      // item_info 기준으로 병합: item_number 매칭되는 pkg_unit이 있으면 그 데이터 사용, 없으면 미등록 placeholder
      const merged: PkgUnit[] = items.map((item) => {
        const match = existing.find((p) => p.item_number === item.item_number || p.pkg_code === item.item_number);
        if (match) return { ...match, pkg_code: match.pkg_code || item.item_number, pkg_name: match.pkg_name || item.item_name };
        const dims = parseSpecDimensions(item.size);
        return {
          id: "",
          company_code: "",
          pkg_code: item.item_number,
          pkg_name: item.item_name,
          pkg_type: "",
          status: "INACTIVE",
          width_mm: dims.w || null,
          length_mm: dims.l || null,
          height_mm: dims.h || null,
          self_weight_kg: null,
          max_load_kg: null,
          volume_l: null,
          remarks: null,
          created_date: "",
          writer: null,
          item_number: item.item_number,
        } as PkgUnit;
      });
      // 품목정보에 없지만 pkg_unit에만 있는 항목 (고아) 추가
      const orphans = existing.filter((p) => !items.some((i) => i.item_number === p.item_number || i.item_number === p.pkg_code));
      setPkgUnits([...merged, ...orphans]);
    } catch { /* ignore */ } finally { setPkgLoading(false); }
  }, []);

  const fetchLoadingUnits = useCallback(async () => {
    setLoadingLoading(true);
    try {
      const [itemRes, luRes] = await Promise.all([
        getItemsByDivision("적재함"),
        getLoadingUnits(),
      ]);
      const items = itemRes.success ? itemRes.data : [];
      const existing = luRes.success ? luRes.data : [];
      const merged: LoadingUnit[] = items.map((item) => {
        const match = existing.find((l) => l.item_number === item.item_number || l.loading_code === item.item_number);
        if (match) return { ...match, loading_code: match.loading_code || item.item_number, loading_name: match.loading_name || item.item_name };
        const dims = parseSpecDimensions(item.size);
        return {
          id: "",
          company_code: "",
          loading_code: item.item_number,
          loading_name: item.item_name,
          loading_type: "",
          status: "INACTIVE",
          width_mm: dims.w || null,
          length_mm: dims.l || null,
          height_mm: dims.h || null,
          self_weight_kg: null,
          max_load_kg: null,
          max_stack: null,
          remarks: null,
          created_date: "",
          writer: null,
          item_number: item.item_number,
        } as LoadingUnit;
      });
      const orphans = existing.filter((l) => !items.some((i) => i.item_number === l.item_number || i.item_number === l.loading_code));
      setLoadingUnits([...merged, ...orphans]);
    } catch { /* ignore */ } finally { setLoadingLoading(false); }
  }, []);

  useEffect(() => { fetchPkgUnits(); fetchLoadingUnits(); }, [fetchPkgUnits, fetchLoadingUnits]);

  // 포장재 선택 시 매칭 품목 로드
  const selectPkg = useCallback(async (pkg: PkgUnit) => {
    setSelectedPkg(pkg);
    setPkgItemsLoading(true);
    try {
      const res = await getPkgUnitItems(pkg.pkg_code);
      if (res.success) setPkgItems(res.data);
    } catch { setPkgItems([]); } finally { setPkgItemsLoading(false); }
  }, []);

  // 적재함 선택 시 포장구성 로드
  const selectLoading = useCallback(async (lu: LoadingUnit) => {
    setSelectedLoading(lu);
    setLoadingPkgsLoading(true);
    try {
      const res = await getLoadingUnitPkgs(lu.loading_code);
      if (res.success) setLoadingPkgs(res.data);
    } catch { setLoadingPkgs([]); } finally { setLoadingPkgsLoading(false); }
  }, []);

  // 검색 필터 적용
  const filteredPkgUnits = pkgUnits.filter((p) => {
    if (searchFilters.length === 0) return true;
    return searchFilters.every((f) => {
      if (!f.value) return true;
      const kw = f.value.toLowerCase();
      return Object.values(p).some((v) => String(v ?? "").toLowerCase().includes(kw));
    });
  });

  const filteredLoadingUnits = loadingUnits.filter((l) => {
    if (searchFilters.length === 0) return true;
    return searchFilters.every((f) => {
      if (!f.value) return true;
      const kw = f.value.toLowerCase();
      return Object.values(l).some((v) => String(v ?? "").toLowerCase().includes(kw));
    });
  });

  // --- 포장재 등록/수정 모달 ---
  // row: 리스트에서 클릭한 행. id가 빈 문자열이면 미등록 상태(item_info만 있음) → 등록 모달
  const openPkgModal = async (mode: "create" | "edit", row?: PkgUnit) => {
    const target = row || selectedPkg;
    const isRegistered = !!(target && target.id);
    const actualMode: "create" | "edit" = isRegistered ? "edit" : "create";
    setPkgModalMode(actualMode);
    if (target) {
      // 기존 데이터 or 품목정보 기반 초기값 세팅
      setPkgForm({
        ...target,
        status: target.status || "ACTIVE",
        item_number: target.item_number || target.pkg_code || "",
      });
    } else {
      setPkgForm({ pkg_code: "", pkg_name: "", pkg_type: "", status: "ACTIVE", width_mm: "", length_mm: "", height_mm: "", self_weight_kg: "", max_load_kg: "", volume_l: "", remarks: "", item_number: "" });
    }
    setPkgItemPopoverOpen(false);
    try {
      const res = await getItemsByDivision("포장재");
      if (res.success) setPkgItemOptions(res.data);
    } catch { setPkgItemOptions([]); }
    setPkgModalOpen(true);
  };

  const onPkgItemSelect = (item: ItemInfoForPkg) => {
    setPkgItemPopoverOpen(false);
    const dims = parseSpecDimensions(item.size);
    setPkgForm((prev) => ({
      ...prev,
      pkg_code: item.item_number,
      pkg_name: item.item_name,
      width_mm: dims.w || prev.width_mm,
      length_mm: dims.l || prev.length_mm,
      height_mm: dims.h || prev.height_mm,
    }));
  };

  const savePkgUnit = async () => {
    if (!pkgForm.pkg_code || !pkgForm.pkg_name) { toast.error("포장코드와 포장명은 필수입니다."); return; }
    if (!pkgForm.pkg_type) { toast.error("포장유형을 선택해주세요."); return; }
    setSaving(true);
    try {
      if (pkgModalMode === "create") {
        const res = await createPkgUnit(pkgForm);
        if (res.success) { toast.success("포장재 등록 완료"); setPkgModalOpen(false); fetchPkgUnits(); }
      } else {
        const res = await updatePkgUnit(pkgForm.id, pkgForm);
        if (res.success) { toast.success("포장재 수정 완료"); setPkgModalOpen(false); fetchPkgUnits(); setSelectedPkg(res.data); }
      }
    } catch { toast.error("저장 실패"); } finally { setSaving(false); }
  };

  const handleDeletePkg = async (pkg: PkgUnit) => {
    const ok = await confirm(`"${pkg.pkg_name}" 포장재를 삭제하시겠습니까?`, { variant: "destructive", confirmText: "삭제" });
    if (!ok) return;
    try {
      await deletePkgUnit(pkg.id);
      toast.success("삭제 완료");
      setSelectedPkg(null); setPkgItems([]);
      fetchPkgUnits();
    } catch { toast.error("삭제 실패"); }
  };

  // --- 적재함 등록/수정 모달 ---
  const openLoadModal = async (mode: "create" | "edit", row?: LoadingUnit) => {
    const target = row || selectedLoading;
    const isRegistered = !!(target && target.id);
    const actualMode: "create" | "edit" = isRegistered ? "edit" : "create";
    setLoadModalMode(actualMode);
    if (target) {
      setLoadForm({
        ...target,
        status: target.status || "ACTIVE",
        item_number: target.item_number || target.loading_code || "",
      });
    } else {
      setLoadForm({ loading_code: "", loading_name: "", loading_type: "", status: "ACTIVE", width_mm: "", length_mm: "", height_mm: "", self_weight_kg: "", max_load_kg: "", max_stack: "", remarks: "", item_number: "" });
    }
    setLoadItemPopoverOpen(false);
    try {
      const res = await getItemsByDivision("적재함");
      if (res.success) setLoadItemOptions(res.data);
    } catch { setLoadItemOptions([]); }
    setLoadModalOpen(true);
  };

  const onLoadItemSelect = (item: ItemInfoForPkg) => {
    setLoadItemPopoverOpen(false);
    const dims = parseSpecDimensions(item.size);
    setLoadForm((prev) => ({
      ...prev,
      loading_code: item.item_number,
      loading_name: item.item_name,
      width_mm: dims.w || prev.width_mm,
      length_mm: dims.l || prev.length_mm,
      height_mm: dims.h || prev.height_mm,
    }));
  };

  const saveLoadingUnit = async () => {
    if (!loadForm.loading_code || !loadForm.loading_name) { toast.error("적재함코드와 적재함명은 필수입니다."); return; }
    if (!loadForm.loading_type) { toast.error("적재유형을 선택해주세요."); return; }
    setSaving(true);
    try {
      if (loadModalMode === "create") {
        const res = await createLoadingUnit(loadForm);
        if (res.success) { toast.success("적재함 등록 완료"); setLoadModalOpen(false); fetchLoadingUnits(); }
      } else {
        const res = await updateLoadingUnit(loadForm.id, loadForm);
        if (res.success) { toast.success("적재함 수정 완료"); setLoadModalOpen(false); fetchLoadingUnits(); setSelectedLoading(res.data); }
      }
    } catch { toast.error("저장 실패"); } finally { setSaving(false); }
  };

  const handleDeleteLoading = async (lu: LoadingUnit) => {
    const ok = await confirm(`"${lu.loading_name}" 적재함을 삭제하시겠습니까?`, { variant: "destructive", confirmText: "삭제" });
    if (!ok) return;
    try {
      await deleteLoadingUnit(lu.id);
      toast.success("삭제 완료");
      setSelectedLoading(null); setLoadingPkgs([]);
      fetchLoadingUnits();
    } catch { toast.error("삭제 실패"); }
  };

  // --- 품목 추가 모달 (포장재 매칭) ---
  const openItemMatchModal = async () => {
    setItemMatchKeyword(""); setItemMatchSelected(null); setItemMatchQty(1);
    setItemMatchModalOpen(true);
    try {
      const res = await getGeneralItems();
      if (res.success) setItemMatchResults(res.data);
    } catch { setItemMatchResults([]); }
  };

  const searchItemsForMatch = async () => {
    try {
      const res = await getGeneralItems(itemMatchKeyword || undefined);
      if (res.success) setItemMatchResults(res.data);
    } catch { setItemMatchResults([]); }
  };

  const saveItemMatch = async () => {
    if (!selectedPkg || !itemMatchSelected) { toast.error("품목을 선택해주세요."); return; }
    if (itemMatchQty <= 0) { toast.error("포장수량을 입력해주세요."); return; }
    setSaving(true);
    try {
      const res = await createPkgUnitItem({
        pkg_code: selectedPkg.pkg_code,
        item_number: itemMatchSelected.item_number,
        pkg_qty: itemMatchQty,
      });
      if (res.success) { toast.success("품목 추가 완료"); setItemMatchModalOpen(false); selectPkg(selectedPkg); }
    } catch { toast.error("추가 실패"); } finally { setSaving(false); }
  };

  const handleDeletePkgItem = async (item: PkgUnitItem) => {
    const ok = await confirm("매칭 품목을 삭제하시겠습니까?", { variant: "destructive", confirmText: "삭제" });
    if (!ok) return;
    try {
      await deletePkgUnitItem(item.id);
      toast.success("삭제 완료");
      if (selectedPkg) selectPkg(selectedPkg);
    } catch { toast.error("삭제 실패"); }
  };

  // --- 포장단위 추가 모달 (적재함 구성) ---
  const openPkgMatchModal = () => {
    setPkgMatchSelected(null); setPkgMatchQty(1); setPkgMatchMethod(""); setPkgMatchSearchKw("");
    setPkgMatchModalOpen(true);
  };

  const savePkgMatch = async () => {
    if (!selectedLoading || !pkgMatchSelected) { toast.error("포장단위를 선택해주세요."); return; }
    if (pkgMatchQty <= 0) { toast.error("최대적재수량을 입력해주세요."); return; }
    setSaving(true);
    try {
      const res = await createLoadingUnitPkg({
        loading_code: selectedLoading.loading_code,
        pkg_code: pkgMatchSelected.pkg_code,
        max_load_qty: pkgMatchQty,
        load_method: pkgMatchMethod || undefined,
      });
      if (res.success) { toast.success("포장단위 추가 완료"); setPkgMatchModalOpen(false); selectLoading(selectedLoading); }
    } catch { toast.error("추가 실패"); } finally { setSaving(false); }
  };

  const handleDeleteLoadPkg = async (lp: LoadingUnitPkg) => {
    const ok = await confirm("적재 구성을 삭제하시겠습니까?", { variant: "destructive", confirmText: "삭제" });
    if (!ok) return;
    try {
      await deleteLoadingUnitPkg(lp.id);
      toast.success("삭제 완료");
      if (selectedLoading) selectLoading(selectedLoading);
    } catch { toast.error("삭제 실패"); }
  };

  return (
    <div className="flex h-[calc(100vh-4rem)] flex-col gap-3 p-4">

      {/* 1. 필터 바 */}
      <DynamicSearchFilter
        tableName="pkg_unit"
        filterId="c16-packaging"
        onFilterChange={setSearchFilters}
        externalFilterConfig={ts.filterConfig}
        dataCount={activeTab === "packing" ? filteredPkgUnits.length : filteredLoadingUnits.length}
      />

      {/* 2. 탭 바 */}
      <div className="flex shrink-0 gap-1 border-b">
        {(
          [
            ["packing", "포장재 관리", filteredPkgUnits.length],
            ["loading", "적재함 관리", filteredLoadingUnits.length],
          ] as const
        ).map(([tab, label, count]) => (
          <button
            key={tab}
            onClick={() => {
              setActiveTab(tab);
              if (tab === "packing") { setSelectedLoading(null); setLoadingPkgs([]); }
              else { setSelectedPkg(null); setPkgItems([]); }
            }}
            className={cn(
              "-mb-px flex items-center gap-2 border-b-2 px-4 py-2.5 text-sm font-medium transition-colors",
              activeTab === tab
                ? "border-primary text-primary"
                : "border-transparent text-muted-foreground hover:text-foreground"
            )}
          >
            {tab === "packing" ? <Package className="h-4 w-4" /> : <Box className="h-4 w-4" />}
            {label}
            <span className="rounded-full border border-primary/15 bg-primary/10 px-2 py-0.5 font-mono text-[11px] font-semibold text-primary">
              {count}
            </span>
          </button>
        ))}
      </div>

      {/* 3. 액션 바 */}
      <div className="flex shrink-0 items-center justify-between">
        <div className="flex items-center gap-2">
          <h3 className="text-sm font-semibold">
            {activeTab === "packing" ? "포장재 목록" : "적재함 목록"}
          </h3>
          {(activeTab === "packing" ? pkgLoading : loadingLoading) && (
            <Loader2 className="h-3.5 w-3.5 animate-spin text-muted-foreground" />
          )}
        </div>
        <div className="flex items-center gap-1.5">
          {activeTab === "packing" && selectedPkg && (
            <>
              <Button size="sm" variant="outline" className="h-7 text-xs" onClick={() => openPkgModal("edit")}>
                <Edit2 className="mr-1 h-3 w-3" /> 수정
              </Button>
              <Button
                size="sm" variant="outline"
                className="h-7 text-xs text-destructive border-destructive/20 bg-destructive/5 hover:bg-destructive/10"
                onClick={() => handleDeletePkg(selectedPkg)}
              >
                <Trash2 className="mr-1 h-3 w-3" /> 삭제
              </Button>
              <div className="h-4 w-px bg-border" />
            </>
          )}
          {activeTab === "loading" && selectedLoading && (
            <>
              <Button size="sm" variant="outline" className="h-7 text-xs" onClick={() => openLoadModal("edit")}>
                <Edit2 className="mr-1 h-3 w-3" /> 수정
              </Button>
              <Button
                size="sm" variant="outline"
                className="h-7 text-xs text-destructive border-destructive/20 bg-destructive/5 hover:bg-destructive/10"
                onClick={() => handleDeleteLoading(selectedLoading)}
              >
                <Trash2 className="mr-1 h-3 w-3" /> 삭제
              </Button>
              <div className="h-4 w-px bg-border" />
            </>
          )}
          {/* 메인 리스트가 품목정보 기반으로 자동 구성되므로 등록 버튼 제거.
              미등록 상태의 품목을 직접 클릭하면 등록 모달이 열림. */}
          <Button variant="ghost" size="sm" onClick={() => ts.setOpen(true)} title="테이블 설정">
            <Settings2 className="h-4 w-4" />
          </Button>
        </div>
      </div>

      {/* 4. 콘텐츠 영역 */}
      {activeTab === "packing" ? (
        <div className="flex flex-1 flex-row overflow-hidden rounded-lg border bg-card">
          {/* 포장재 목록 테이블 */}
          <div className="flex-[0_0_50%] overflow-auto border-r">
            <EDataTable
              columns={ts.visibleColumns.map((col): EDataTableColumn<PkgUnit> => {
                const renderMap: Record<string, Partial<EDataTableColumn<PkgUnit>>> = {
                  pkg_type: { width: "w-[80px]", render: (v: any) => PKG_TYPE_LABEL[v] || v || "-" },
                  size: { width: "w-[100px]", render: (_v: any, row: any) => fmtSize(row.width_mm, row.length_mm, row.height_mm) },
                  max_weight: { width: "w-[80px]", align: "right", render: (v: any) => Number(v || 0) > 0 ? `${v}kg` : "-" },
                  max_load_kg: { width: "w-[80px]", align: "right", render: (v: any) => Number(v || 0) > 0 ? `${v}kg` : "-" },
                  status: { width: "w-[60px]", align: "center", render: (v: any, row: any) => {
                    const isUnreg = !row.id;
                    const cls = isUnreg ? "bg-warning/10 text-warning" : getStatusColor(v);
                    const label = isUnreg ? "미등록" : (STATUS_LABEL[v] || v);
                    return <span className={cn("rounded px-1.5 py-0.5 text-[10px] font-medium", cls)}>{label}</span>;
                  }},
                };
                return { key: col.key, label: col.label, ...renderMap[col.key] };
              })}
              data={ts.groupData(filteredPkgUnits)}
              rowKey={(row) => row.id ? `reg-${row.id}` : `new-${row.pkg_code || row.item_number}`}
              loading={pkgLoading}
              emptyMessage="포장재 품목이 없어요. 품목정보에서 관리품목을 '포장재'로 등록해주세요."
              selectedId={selectedPkg ? (selectedPkg.id ? `reg-${selectedPkg.id}` : `new-${selectedPkg.pkg_code || selectedPkg.item_number}`) : null}
              onSelect={(id) => {
                const pkg = filteredPkgUnits.find((p) => (p.id ? `reg-${p.id}` : `new-${p.pkg_code || p.item_number}`) === id);
                if (pkg) {
                  if (!pkg.id) {
                    // 미등록 → 바로 등록 모달
                    openPkgModal("create", pkg);
                  } else {
                    selectPkg(pkg);
                  }
                }
              }}
              showPagination={false}
              draggableColumns
              columnOrderKey="c16-packaging-pkg"
            />
          </div>

          {/* 매칭 품목 서브패널 */}
          {selectedPkg ? (
            <div className="flex flex-1 flex-col overflow-hidden">
              <div className="flex shrink-0 items-center justify-between bg-muted/50 px-4 py-2">
                <div className="flex items-center gap-2">
                  <span className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">매칭 품목</span>
                  <span className="rounded-full border border-primary/15 bg-primary/10 px-2 py-0.5 font-mono text-[11px] font-semibold text-primary">
                    {pkgItems.length}건
                  </span>
                  <span className="max-w-[200px] truncate text-[11px] text-muted-foreground">
                    — {selectedPkg.pkg_name}
                  </span>
                </div>
                <div className="flex items-center gap-1.5">
                  <Button size="sm" variant="outline" className="h-7 text-xs" onClick={openItemMatchModal}>
                    <Plus className="mr-1 h-3 w-3" /> 품목 추가
                  </Button>
                  <Button
                    size="sm" variant="ghost" className="h-7 w-7 p-0 text-muted-foreground"
                    onClick={() => { setSelectedPkg(null); setPkgItems([]); }}
                  >
                    <X className="h-3.5 w-3.5" />
                  </Button>
                </div>
              </div>
              <div className="flex-1 overflow-auto">
                {pkgItemsLoading ? (
                  <div className="flex h-24 items-center justify-center">
                    <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
                  </div>
                ) : pkgItems.length === 0 ? (
                  <div className="flex h-24 flex-col items-center justify-center gap-1.5">
                    <Inbox className="h-5 w-5 text-muted-foreground/40" />
                    <p className="text-xs text-muted-foreground">매칭된 품목이 없어요</p>
                  </div>
                ) : (
                  <Table>
                    <TableHeader className="sticky top-0 z-10">
                      <TableRow className="bg-muted hover:bg-muted">
                        <TableHead className="p-2 text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품목코드</TableHead>
                        <TableHead className="p-2 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-[50px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">단위</TableHead>
                        <TableHead className="w-[80px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">포장수량</TableHead>
                        <TableHead className="p-2 w-[40px]" />
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {pkgItems.map((item) => (
                        <TableRow key={item.id} className="text-xs">
                          <TableCell className="p-2 font-medium">{item.item_number}</TableCell>
                          <TableCell className="p-2">{item.item_name || "-"}</TableCell>
                          <TableCell className="p-2">{item.spec || "-"}</TableCell>
                          <TableCell className="p-2">{resolveCat("inventory_unit", item.inventory_unit) || "EA"}</TableCell>
                          <TableCell className="p-2 text-right font-semibold">{Number(item.pkg_qty).toLocaleString()}</TableCell>
                          <TableCell className="p-2 text-center">
                            <Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => handleDeletePkgItem(item)}>
                              <X className="h-3 w-3" />
                            </Button>
                          </TableCell>
                        </TableRow>
                      ))}
                    </TableBody>
                  </Table>
                )}
              </div>
            </div>
          ) : (
            <div className="flex flex-1 items-center justify-center p-8">
              <div className="text-center">
                <Package className="mx-auto mb-2 h-10 w-10 text-muted-foreground/30" />
                <p className="text-sm text-muted-foreground">좌측 목록에서 포장재를 선택하세요</p>
              </div>
            </div>
          )}
        </div>
      ) : (
        /* 적재함 관리 탭 */
        <div className="flex flex-1 flex-row overflow-hidden rounded-lg border bg-card">
          {/* 적재함 목록 테이블 */}
          <div className="flex-[0_0_50%] overflow-auto border-r">
            <Table>
              <TableHeader className="sticky top-0 z-10">
                <TableRow className="bg-muted hover:bg-muted">
                  <TableHead className="p-2 text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품목코드</TableHead>
                  <TableHead className="p-2 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-[100px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">크기(mm)</TableHead>
                  <TableHead className="w-[80px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">최대적재</TableHead>
                  <TableHead className="w-[60px] text-center text-[11px] font-bold uppercase tracking-wide text-muted-foreground">상태</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {loadingLoading ? (
                  <TableRow>
                    <TableCell colSpan={6} className="h-32 text-center">
                      <Loader2 className="mx-auto h-5 w-5 animate-spin text-muted-foreground" />
                    </TableCell>
                  </TableRow>
                ) : filteredLoadingUnits.length === 0 ? (
                  <TableRow>
                    <TableCell colSpan={6} className="h-40 text-center">
                      <div className="flex flex-col items-center justify-center gap-2">
                        <div className="flex h-12 w-12 items-center justify-center rounded-full border-2 border-dashed border-muted-foreground/20">
                          <Inbox className="h-6 w-6 text-muted-foreground/40" />
                        </div>
                        <p className="text-xs text-muted-foreground">등록된 적재함이 없어요</p>
                      </div>
                    </TableCell>
                  </TableRow>
                ) : filteredLoadingUnits.map((l) => {
                  const isUnreg = !l.id;
                  const rowKey = l.id ? `reg-${l.id}` : `new-${l.loading_code || l.item_number}`;
                  const selKey = selectedLoading ? (selectedLoading.id ? `reg-${selectedLoading.id}` : `new-${selectedLoading.loading_code || selectedLoading.item_number}`) : null;
                  return (
                  <TableRow
                    key={rowKey}
                    className={cn(
                      "cursor-pointer text-xs transition-colors",
                      selKey === rowKey ? "bg-primary/5" : "hover:bg-muted/50"
                    )}
                    onClick={() => {
                      if (isUnreg) {
                        openLoadModal("create", l);
                      } else {
                        selectLoading(l);
                      }
                    }}
                  >
                    <TableCell className="p-2 font-medium">{l.loading_code}</TableCell>
                    <TableCell className="p-2">{l.loading_name}</TableCell>
                    <TableCell className="p-2">{LOADING_TYPE_LABEL[l.loading_type] || l.loading_type || "-"}</TableCell>
                    <TableCell className="p-2 text-[10px] tabular-nums">{fmtSize(l.width_mm, l.length_mm, l.height_mm)}</TableCell>
                    <TableCell className="p-2 text-right">{Number(l.max_load_kg || 0) > 0 ? `${l.max_load_kg}kg` : "-"}</TableCell>
                    <TableCell className="p-2 text-center">
                      <span className={cn("rounded px-1.5 py-0.5 text-[10px] font-medium", isUnreg ? "bg-warning/10 text-warning" : getStatusColor(l.status))}>
                        {isUnreg ? "미등록" : (STATUS_LABEL[l.status] || l.status)}
                      </span>
                    </TableCell>
                  </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </div>

          {/* 포장구성 서브패널 */}
          {selectedLoading ? (
            <div className="flex flex-1 flex-col overflow-hidden">
              <div className="flex shrink-0 items-center justify-between bg-muted/50 px-4 py-2">
                <div className="flex items-center gap-2">
                  <span className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">적재 가능 포장단위</span>
                  <span className="rounded-full border border-primary/15 bg-primary/10 px-2 py-0.5 font-mono text-[11px] font-semibold text-primary">
                    {loadingPkgs.length}건
                  </span>
                  <span className="max-w-[200px] truncate text-[11px] text-muted-foreground">
                    — {selectedLoading.loading_name}
                  </span>
                </div>
                <div className="flex items-center gap-1.5">
                  <Button size="sm" variant="outline" className="h-7 text-xs" onClick={openPkgMatchModal}>
                    <Plus className="mr-1 h-3 w-3" /> 포장단위 추가
                  </Button>
                  <Button
                    size="sm" variant="ghost" className="h-7 w-7 p-0 text-muted-foreground"
                    onClick={() => { setSelectedLoading(null); setLoadingPkgs([]); }}
                  >
                    <X className="h-3.5 w-3.5" />
                  </Button>
                </div>
              </div>
              <div className="flex-1 overflow-auto">
                {loadingPkgsLoading ? (
                  <div className="flex h-24 items-center justify-center">
                    <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
                  </div>
                ) : loadingPkgs.length === 0 ? (
                  <div className="flex h-24 flex-col items-center justify-center gap-1.5">
                    <Inbox className="h-5 w-5 text-muted-foreground/40" />
                    <p className="text-xs text-muted-foreground">등록된 포장단위가 없어요</p>
                  </div>
                ) : (
                  <Table>
                    <TableHeader className="sticky top-0 z-10">
                      <TableRow className="bg-muted hover:bg-muted">
                        <TableHead className="p-2 text-[11px] font-bold uppercase tracking-wide text-muted-foreground">포장코드</TableHead>
                        <TableHead className="p-2 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-[90px] text-right 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="p-2 w-[40px]" />
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {loadingPkgs.map((lp) => (
                        <TableRow key={lp.id} className="text-xs">
                          <TableCell className="p-2 font-medium">{lp.pkg_code}</TableCell>
                          <TableCell className="p-2">{lp.pkg_name || "-"}</TableCell>
                          <TableCell className="p-2">{PKG_TYPE_LABEL[lp.pkg_type || ""] || lp.pkg_type || "-"}</TableCell>
                          <TableCell className="p-2 text-right font-semibold">{Number(lp.max_load_qty).toLocaleString()}</TableCell>
                          <TableCell className="p-2">{lp.load_method || "-"}</TableCell>
                          <TableCell className="p-2 text-center">
                            <Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => handleDeleteLoadPkg(lp)}>
                              <X className="h-3 w-3" />
                            </Button>
                          </TableCell>
                        </TableRow>
                      ))}
                    </TableBody>
                  </Table>
                )}
              </div>
            </div>
          ) : (
            <div className="flex flex-1 items-center justify-center p-8">
              <div className="text-center">
                <Box className="mx-auto mb-2 h-10 w-10 text-muted-foreground/30" />
                <p className="text-sm text-muted-foreground">좌측 목록에서 적재함을 선택하세요</p>
              </div>
            </div>
          )}
        </div>
      )}

      {/* 포장재 등록/수정 모달 */}
      <Dialog open={pkgModalOpen} onOpenChange={setPkgModalOpen}>
        <DialogContent className="max-w-2xl" style={{ maxHeight: "90vh", overflowY: "auto" }}>
          <DialogHeader>
            <DialogTitle>{pkgModalMode === "create" ? "포장재 등록" : "포장재 수정"}</DialogTitle>
            <DialogDescription>품목정보에서 포장재를 선택하면 코드와 이름이 자동 연동됩니다.</DialogDescription>
          </DialogHeader>
          <div className="space-y-4">
            {pkgModalMode === "create" && (
              <div className="rounded-lg border bg-muted/50 p-4">
                <Label className="mb-2 block text-xs font-semibold">품목정보 연결 (구분: 포장재)</Label>
                <div className="h-9 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground flex items-center">
                  {pkgForm.pkg_code ? `${pkgForm.pkg_name} (${pkgForm.pkg_code})` : "-"}
                </div>
              </div>
            )}
            <div className="grid grid-cols-2 gap-4">
              <div><Label className="text-xs">품목코드</Label><Input value={pkgForm.pkg_code || ""} readOnly className="h-9 bg-muted text-xs" /></div>
              <div><Label className="text-xs">포장명</Label><Input value={pkgForm.pkg_name || ""} readOnly className="h-9 bg-muted text-xs" /></div>
              <div>
                <Label className="text-xs">포장유형 <span className="text-destructive">*</span></Label>
                <Select value={pkgForm.pkg_type || ""} onValueChange={(v) => setPkgForm((p) => ({ ...p, pkg_type: v }))}>
                  <SelectTrigger className="h-9 text-xs"><SelectValue placeholder="선택" /></SelectTrigger>
                  <SelectContent>{Object.entries(PKG_TYPE_LABEL).map(([k, v]) => <SelectItem key={k} value={k}>{v}</SelectItem>)}</SelectContent>
                </Select>
              </div>
              <div>
                <Label className="text-xs">상태</Label>
                <Select value={pkgForm.status || "ACTIVE"} onValueChange={(v) => setPkgForm((p) => ({ ...p, status: v }))}>
                  <SelectTrigger className="h-9 text-xs"><SelectValue /></SelectTrigger>
                  <SelectContent>{Object.entries(STATUS_LABEL).map(([k, v]) => <SelectItem key={k} value={k}>{v}</SelectItem>)}</SelectContent>
                </Select>
              </div>
            </div>
            <div>
              <Label className="text-xs font-semibold">규격정보</Label>
              <div className="mt-2 grid grid-cols-3 gap-3">
                <div><Label className="text-[10px]">가로(mm)</Label><Input type="number" value={pkgForm.width_mm || ""} onChange={(e) => setPkgForm((p) => ({ ...p, width_mm: e.target.value }))} className="h-9 text-xs" /></div>
                <div><Label className="text-[10px]">세로(mm)</Label><Input type="number" value={pkgForm.length_mm || ""} onChange={(e) => setPkgForm((p) => ({ ...p, length_mm: e.target.value }))} className="h-9 text-xs" /></div>
                <div><Label className="text-[10px]">높이(mm)</Label><Input type="number" value={pkgForm.height_mm || ""} onChange={(e) => setPkgForm((p) => ({ ...p, height_mm: e.target.value }))} className="h-9 text-xs" /></div>
                <div><Label className="text-[10px]">자체중량(kg)</Label><Input type="number" value={pkgForm.self_weight_kg || ""} onChange={(e) => setPkgForm((p) => ({ ...p, self_weight_kg: e.target.value }))} className="h-9 text-xs" step="0.1" /></div>
                <div><Label className="text-[10px]">최대적재중량(kg)</Label><Input type="number" value={pkgForm.max_load_kg || ""} onChange={(e) => setPkgForm((p) => ({ ...p, max_load_kg: e.target.value }))} className="h-9 text-xs" step="0.1" /></div>
                <div><Label className="text-[10px]">내용적(L)</Label><Input type="number" value={pkgForm.volume_l || ""} onChange={(e) => setPkgForm((p) => ({ ...p, volume_l: e.target.value }))} className="h-9 text-xs" step="0.1" /></div>
              </div>
            </div>
            <div><Label className="text-xs">비고</Label><Input value={pkgForm.remarks || ""} onChange={(e) => setPkgForm((p) => ({ ...p, remarks: e.target.value }))} className="h-9 text-xs" placeholder="메모" /></div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setPkgModalOpen(false)}>취소</Button>
            <Button onClick={savePkgUnit} disabled={saving}>
              {saving ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : <Save className="mr-1 h-4 w-4" />} 저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 적재함 등록/수정 모달 */}
      <Dialog open={loadModalOpen} onOpenChange={setLoadModalOpen}>
        <DialogContent className="max-w-2xl" style={{ maxHeight: "90vh", overflowY: "auto" }}>
          <DialogHeader>
            <DialogTitle>{loadModalMode === "create" ? "적재함 등록" : "적재함 수정"}</DialogTitle>
            <DialogDescription>품목정보에서 적재함을 선택하면 코드와 이름이 자동 연동됩니다.</DialogDescription>
          </DialogHeader>
          <div className="space-y-4">
            {loadModalMode === "create" && (
              <div className="rounded-lg border bg-muted/50 p-4">
                <Label className="mb-2 block text-xs font-semibold">품목정보 연결 (구분: 적재함)</Label>
                <div className="h-9 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm text-muted-foreground flex items-center">
                  {loadForm.loading_code ? `${loadForm.loading_name} (${loadForm.loading_code})` : "-"}
                </div>
              </div>
            )}
            <div className="grid grid-cols-2 gap-4">
              <div><Label className="text-xs">적재함코드</Label><Input value={loadForm.loading_code || ""} readOnly className="h-9 bg-muted text-xs" /></div>
              <div><Label className="text-xs">적재함명</Label><Input value={loadForm.loading_name || ""} readOnly className="h-9 bg-muted text-xs" /></div>
              <div>
                <Label className="text-xs">적재유형 <span className="text-destructive">*</span></Label>
                <Select value={loadForm.loading_type || ""} onValueChange={(v) => setLoadForm((p) => ({ ...p, loading_type: v }))}>
                  <SelectTrigger className="h-9 text-xs"><SelectValue placeholder="선택" /></SelectTrigger>
                  <SelectContent>{Object.entries(LOADING_TYPE_LABEL).map(([k, v]) => <SelectItem key={k} value={k}>{v}</SelectItem>)}</SelectContent>
                </Select>
              </div>
              <div>
                <Label className="text-xs">상태</Label>
                <Select value={loadForm.status || "ACTIVE"} onValueChange={(v) => setLoadForm((p) => ({ ...p, status: v }))}>
                  <SelectTrigger className="h-9 text-xs"><SelectValue /></SelectTrigger>
                  <SelectContent>{Object.entries(STATUS_LABEL).map(([k, v]) => <SelectItem key={k} value={k}>{v}</SelectItem>)}</SelectContent>
                </Select>
              </div>
            </div>
            <div>
              <Label className="text-xs font-semibold">규격정보</Label>
              <div className="mt-2 grid grid-cols-3 gap-3">
                <div><Label className="text-[10px]">가로(mm)</Label><Input type="number" value={loadForm.width_mm || ""} onChange={(e) => setLoadForm((p) => ({ ...p, width_mm: e.target.value }))} className="h-9 text-xs" /></div>
                <div><Label className="text-[10px]">세로(mm)</Label><Input type="number" value={loadForm.length_mm || ""} onChange={(e) => setLoadForm((p) => ({ ...p, length_mm: e.target.value }))} className="h-9 text-xs" /></div>
                <div><Label className="text-[10px]">높이(mm)</Label><Input type="number" value={loadForm.height_mm || ""} onChange={(e) => setLoadForm((p) => ({ ...p, height_mm: e.target.value }))} className="h-9 text-xs" /></div>
                <div><Label className="text-[10px]">자체중량(kg)</Label><Input type="number" value={loadForm.self_weight_kg || ""} onChange={(e) => setLoadForm((p) => ({ ...p, self_weight_kg: e.target.value }))} className="h-9 text-xs" step="0.1" /></div>
                <div><Label className="text-[10px]">최대적재중량(kg)</Label><Input type="number" value={loadForm.max_load_kg || ""} onChange={(e) => setLoadForm((p) => ({ ...p, max_load_kg: e.target.value }))} className="h-9 text-xs" step="0.1" /></div>
                <div><Label className="text-[10px]">최대단수</Label><Input type="number" value={loadForm.max_stack || ""} onChange={(e) => setLoadForm((p) => ({ ...p, max_stack: e.target.value }))} className="h-9 text-xs" /></div>
              </div>
            </div>
            <div><Label className="text-xs">비고</Label><Input value={loadForm.remarks || ""} onChange={(e) => setLoadForm((p) => ({ ...p, remarks: e.target.value }))} className="h-9 text-xs" placeholder="메모" /></div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setLoadModalOpen(false)}>취소</Button>
            <Button onClick={saveLoadingUnit} disabled={saving}>
              {saving ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : <Save className="mr-1 h-4 w-4" />} 저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 품목 추가 모달 (포장재 매칭) */}
      <Dialog open={itemMatchModalOpen} onOpenChange={setItemMatchModalOpen}>
        <DialogContent className="max-w-[900px]">
          <DialogHeader>
            <DialogTitle>품목 추가 — {selectedPkg?.pkg_name}</DialogTitle>
            <DialogDescription>포장재에 매칭할 품목을 검색하여 추가합니다.</DialogDescription>
          </DialogHeader>
          <div className="space-y-4">
            <Input
              placeholder="품목코드 / 품목명 검색 (입력 시 자동 검색)"
              value={itemMatchKeyword}
              onChange={(e) => {
                setItemMatchKeyword(e.target.value);
                const kw = e.target.value;
                clearTimeout((window as any).__itemMatchTimer);
                (window as any).__itemMatchTimer = setTimeout(async () => {
                  try {
                    const res = await getGeneralItems(kw || undefined);
                    if (res.success) setItemMatchResults(res.data);
                  } catch { /* ignore */ }
                }, 300);
              }}
              className="h-9 text-xs"
            />
            <div className="max-h-[300px] overflow-auto rounded border">
              <Table>
                <TableHeader className="sticky top-0 z-10">
                  <TableRow className="bg-muted hover:bg-muted">
                    <TableHead className="p-2 w-[30px]" />
                    <TableHead className="w-[130px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품목코드</TableHead>
                    <TableHead className="p-2 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-[80px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">재질</TableHead>
                    <TableHead className="w-[50px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">단위</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {itemMatchResults.filter(i => !pkgItems.some(pi => pi.item_number === i.item_number)).length === 0 ? (
                    <TableRow><TableCell colSpan={6} className="h-16 text-center text-[13px] text-muted-foreground">검색 결과가 없습니다</TableCell></TableRow>
                  ) : itemMatchResults.filter(i => !pkgItems.some(pi => pi.item_number === i.item_number)).map((item) => (
                    <TableRow
                      key={item.id}
                      className={cn("cursor-pointer text-xs", itemMatchSelected?.id === item.id && "bg-primary/10")}
                      onClick={() => setItemMatchSelected(item)}
                    >
                      <TableCell className="p-2 text-center">{itemMatchSelected?.id === item.id ? "✓" : ""}</TableCell>
                      <TableCell className="p-2 font-medium">{item.item_number}</TableCell>
                      <TableCell className="p-2">{item.item_name}</TableCell>
                      <TableCell className="p-2">{item.spec || "-"}</TableCell>
                      <TableCell className="p-2">{resolveCat("material", item.material) || "-"}</TableCell>
                      <TableCell className="p-2">{resolveCat("inventory_unit", item.inventory_unit) || "EA"}</TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>
            <div className="flex items-end gap-4">
              <div className="flex-1">
                <Label className="text-xs">선택된 품목</Label>
                <Input
                  value={itemMatchSelected ? `${itemMatchSelected.item_name} (${itemMatchSelected.item_number})` : ""}
                  readOnly className="h-9 bg-muted text-xs"
                />
              </div>
              <div className="w-[120px]">
                <Label htmlFor="pkg-item-match-qty" className="text-xs">포장수량(EA) <span className="text-destructive">*</span></Label>
                <Input
                  id="pkg-item-match-qty" type="number" value={itemMatchQty}
                  onChange={(e) => setItemMatchQty(Number(e.target.value) || 0)}
                  min={1} className="h-9 text-xs"
                />
              </div>
            </div>
          </div>
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setItemMatchModalOpen(false)}>취소</Button>
            <Button type="button" data-action-type="custom" onClick={saveItemMatch} disabled={saving || !itemMatchSelected}>
              {saving ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : null} 추가
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 포장단위 추가 모달 (적재함 구성) */}
      <Dialog open={pkgMatchModalOpen} onOpenChange={setPkgMatchModalOpen}>
        <DialogContent className="max-w-[800px]">
          <DialogHeader>
            <DialogTitle>포장단위 추가 — {selectedLoading?.loading_name}</DialogTitle>
            <DialogDescription>적재함에 적재할 포장단위를 선택합니다.</DialogDescription>
          </DialogHeader>
          <div className="space-y-4">
            <Input
              placeholder="포장코드 / 포장명 검색"
              value={pkgMatchSearchKw}
              onChange={(e) => setPkgMatchSearchKw(e.target.value)}
              className="h-9 text-xs"
            />
            <div className="max-h-[300px] overflow-auto rounded border">
              <Table>
                <TableHeader className="sticky top-0 z-10">
                  <TableRow className="bg-muted hover:bg-muted">
                    <TableHead className="p-2 w-[30px]" />
                    <TableHead className="w-[120px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">포장코드</TableHead>
                    <TableHead className="p-2 text-[11px] font-bold uppercase tracking-wide text-muted-foreground">포장명</TableHead>
                    <TableHead className="w-[70px] 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">크기(mm)</TableHead>
                    <TableHead className="w-[80px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">최대중량</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {(() => {
                    const kw = pkgMatchSearchKw.toLowerCase();
                    const filtered = pkgUnits.filter(p =>
                      p.status === "ACTIVE"
                      && !loadingPkgs.some(lp => lp.pkg_code === p.pkg_code)
                      && (!kw || p.pkg_code?.toLowerCase().includes(kw) || p.pkg_name?.toLowerCase().includes(kw))
                    );
                    return filtered.length === 0 ? (
                      <TableRow><TableCell colSpan={6} className="h-16 text-center text-[13px] text-muted-foreground">추가 가능한 포장단위가 없습니다</TableCell></TableRow>
                    ) : filtered.map((p) => (
                      <TableRow
                        key={p.id}
                        className={cn("cursor-pointer text-xs", pkgMatchSelected?.id === p.id && "bg-primary/10")}
                        onClick={() => setPkgMatchSelected(p)}
                      >
                        <TableCell className="p-2 text-center">{pkgMatchSelected?.id === p.id ? "✓" : ""}</TableCell>
                        <TableCell className="p-2 font-medium">{p.pkg_code}</TableCell>
                        <TableCell className="p-2">{p.pkg_name}</TableCell>
                        <TableCell className="p-2">{PKG_TYPE_LABEL[p.pkg_type] || p.pkg_type}</TableCell>
                        <TableCell className="p-2 text-[10px]">{fmtSize(p.width_mm, p.length_mm, p.height_mm)}</TableCell>
                        <TableCell className="p-2 text-right">{Number(p.max_load_kg || 0) > 0 ? `${p.max_load_kg}kg` : "-"}</TableCell>
                      </TableRow>
                    ));
                  })()}
                </TableBody>
              </Table>
            </div>
            <div className="flex items-end gap-4">
              <div className="w-[150px]">
                <Label htmlFor="loading-pkg-match-qty" className="text-xs">최대적재수량 <span className="text-destructive">*</span></Label>
                <Input
                  id="loading-pkg-match-qty" type="number" value={pkgMatchQty}
                  onChange={(e) => setPkgMatchQty(Number(e.target.value) || 0)}
                  min={1} className="h-9 text-xs"
                />
              </div>
              <div className="flex-1">
                <Label className="text-xs">적재방향</Label>
                <Input
                  value={pkgMatchMethod}
                  onChange={(e) => setPkgMatchMethod(e.target.value)}
                  placeholder="수직/수평/혼합"
                  className="h-9 text-xs"
                />
              </div>
            </div>
          </div>
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setPkgMatchModalOpen(false)}>취소</Button>
            <Button type="button" data-action-type="custom" onClick={savePkgMatch} disabled={saving || !pkgMatchSelected}>
              {saving ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : null} 추가
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {ConfirmDialogComponent}

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