"use client";

/**
 * 판매품목정보 — Type B 마스터-디테일 리디자인
 *
 * 좌측: 판매품목 목록 (item_info, 판매 관련 필터)
 * 우측: 선택한 품목의 거래처 정보 (customer_item_mapping → customer_mng 조인)
 *
 * 거래처관리와 양방향 연동 (같은 customer_item_mapping 테이블)
 */

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, DialogFooter, DialogDescription } from "@/components/ui/dialog";
import { Checkbox } from "@/components/ui/checkbox";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
import { Plus, Trash2, Save, Loader2, FileSpreadsheet, Download, Pencil, Users, Search, X, Settings2 } from "lucide-react";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";
import { useAuth } from "@/hooks/useAuth";
import { toast } from "sonner";
import { useConfirmDialog } from "@/components/common/ConfirmDialog";
import { ExcelUploadModal } from "@/components/common/ExcelUploadModal";
import { exportToExcel } from "@/lib/utils/excelExport";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { useTableSettings } from "@/hooks/useTableSettings";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";
import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable";

const ITEM_TABLE = "item_info";
const MAPPING_TABLE = "customer_item_mapping";
const CUSTOMER_TABLE = "customer_mng";

// 숫자 포맷 헬퍼
const formatNum = (val: any): string => {
  if (val === null || val === undefined || val === "") return "";
  const n = Number(val);
  return isNaN(n) ? String(val) : n.toLocaleString();
};

const ITEM_GRID_COLUMNS = [
  { key: "item_number", label: "품번" },
  { key: "item_name", label: "품명" },
  { key: "size", label: "규격" },
  { key: "unit", label: "단위" },
  { key: "standard_price", label: "기준단가" },
  { key: "selling_price", label: "판매가격" },
  { key: "currency_code", label: "통화" },
  { key: "status", label: "상태" },
];

export default function SalesItemPage() {
  const { user } = useAuth();
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();
  const ts = useTableSettings("c16-sales-item", ITEM_TABLE, ITEM_GRID_COLUMNS);

  // 좌측: 품목
  const [items, setItems] = useState<any[]>([]);
  const [itemLoading, setItemLoading] = useState(false);
  const [itemCount, setItemCount] = useState(0);
  const [selectedItemId, setSelectedItemId] = useState<string | null>(null);

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

  // 우측: 거래처
  const [customerItems, setCustomerItems] = useState<any[]>([]);
  const [customerLoading, setCustomerLoading] = useState(false);
  const [customerCheckedIds, setCustomerCheckedIds] = useState<string[]>([]);

  // 카테고리
  const [categoryOptions, setCategoryOptions] = useState<Record<string, { code: string; label: string; isDefault?: boolean }[]>>({});
  const [priceCategoryOptions, setPriceCategoryOptions] = useState<Record<string, { code: string; label: string }[]>>({});

  // 거래처 추가 모달
  const [custSelectOpen, setCustSelectOpen] = useState(false);
  const [custSearchKeyword, setCustSearchKeyword] = useState("");
  const [custSearchResults, setCustSearchResults] = useState<any[]>([]);
  const [custSearchLoading, setCustSearchLoading] = useState(false);
  const [custCheckedIds, setCustCheckedIds] = useState<Set<string>>(new Set());

  // 품목 수정 모달
  const [editItemOpen, setEditItemOpen] = useState(false);
  const [editItemForm, setEditItemForm] = useState<Record<string, any>>({});
  const [saving, setSaving] = useState(false);

  // 엑셀
  const [excelUploadOpen, setExcelUploadOpen] = useState(false);


  // 거래처 상세 입력 모달 (거래처 품번/품명 + 단가)
  const [custDetailOpen, setCustDetailOpen] = useState(false);
  const [selectedCustsForDetail, setSelectedCustsForDetail] = useState<any[]>([]);
  const [custMappings, setCustMappings] = useState<Record<string, Array<{ _id: string; customer_item_code: string; customer_item_name: string }>>>({});
  const [custPrices, setCustPrices] = useState<Record<string, Array<{
    _id: string; start_date: string; end_date: string; currency_code: string;
    base_price_type: string; base_price: string; discount_type: string;
    discount_value: string; rounding_type: string; rounding_unit_value: string;
    calculated_price: string;
  }>>>({});
  const [editCustData, setEditCustData] = useState<any>(null);


  // 카테고리 로드
  useEffect(() => {
    const load = async () => {
      const optMap: Record<string, { code: string; label: string; isDefault?: boolean }[]> = {};
      const flatten = (vals: any[]): { code: string; label: string; isDefault?: boolean }[] => {
        const result: { code: string; label: string; isDefault?: boolean }[] = [];
        for (const v of vals) {
          result.push({ code: v.valueCode, label: v.valueLabel, isDefault: v.isDefault });
          if (v.children?.length) result.push(...flatten(v.children));
        }
        return result;
      };
      for (const col of ["unit", "material", "division", "type", "status", "inventory_unit", "currency_code", "user_type01", "user_type02"]) {
        try {
          const res = await apiClient.get(`/table-categories/${ITEM_TABLE}/${col}/values`);
          if (res.data?.success) optMap[col] = flatten(res.data.data || []);
        } catch { /* skip */ }
      }
      setCategoryOptions(optMap);

      // 단가 카테고리
      const priceOpts: Record<string, { code: string; label: string }[]> = {};
      for (const col of ["base_price_type", "currency_code", "discount_type", "rounding_type", "rounding_unit_value"]) {
        try {
          const res = await apiClient.get(`/table-categories/customer_item_prices/${col}/values`);
          if (res.data?.success) priceOpts[col] = flatten(res.data.data || []);
        } catch { /* skip */ }
      }
      setPriceCategoryOptions(priceOpts);
    };
    load();
  }, []);

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

  // 좌측: 품목 조회
  const fetchItems = useCallback(async () => {
    setItemLoading(true);
    try {
      const filters: { columnName: string; operator: string; value: any }[] = [];

      // 판매품목/영업관리 division 필터 (다중값 컬럼이므로 contains로 매칭)
      filters.push({ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" });

      // DynamicSearchFilter에서 전달된 필터 추가
      for (const f of searchFilters) {
        filters.push({ columnName: f.columnName, operator: f.operator, value: f.value });
      }

      const res = await apiClient.post(`/table-management/tables/${ITEM_TABLE}/data`, {
        page: 1, size: 500,
        dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
        autoFilter: true,
      });
      const raw = res.data?.data?.data || res.data?.data?.rows || [];
      const CATS = ["unit", "material", "division", "type", "status", "inventory_unit", "currency_code", "user_type01", "user_type02"];
      const data = raw.map((r: any) => {
        const converted = { ...r };
        for (const col of CATS) {
          if (converted[col]) converted[col] = resolve(col, converted[col]);
        }
        return converted;
      });
      setItems(data);
      setItemCount(res.data?.data?.total || raw.length);
    } catch (err) {
      console.error("품목 조회 실패:", err);
      toast.error("품목 목록을 불러오는데 실패했습니다.");
    } finally {
      setItemLoading(false);
    }
  }, [searchFilters, categoryOptions]); // eslint-disable-line react-hooks/exhaustive-deps

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

  // 선택된 품목
  const selectedItem = items.find((i) => i.id === selectedItemId);

  // 우측: 거래처 목록 조회
  useEffect(() => {
    if (!selectedItem?.item_number) { setCustomerItems([]); setCustomerCheckedIds([]); return; }
    setCustomerCheckedIds([]);
    const itemKey = selectedItem.item_number;
    const fetchCustomerItems = async () => {
      setCustomerLoading(true);
      try {
        // 1. customer_item_mapping에서 해당 품목의 매핑 조회
        const mapRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/data`, {
          page: 1, size: 500,
          dataFilter: { enabled: true, filters: [{ columnName: "item_id", operator: "equals", value: itemKey }] },
          autoFilter: true,
        });
        const mappings = mapRes.data?.data?.data || mapRes.data?.data?.rows || [];

        // 2. customer_id → customer_mng 조인 (거래처명)
        const custIds = [...new Set(mappings.map((m: any) => m.customer_id).filter(Boolean))];
        let custMap: Record<string, any> = {};
        if (custIds.length > 0) {
          try {
            const custRes = await apiClient.post(`/table-management/tables/${CUSTOMER_TABLE}/data`, {
              page: 1, size: custIds.length + 10,
              dataFilter: { enabled: true, filters: [{ columnName: "customer_code", operator: "in", value: custIds }] },
              autoFilter: true,
            });
            for (const c of (custRes.data?.data?.data || custRes.data?.data?.rows || [])) {
              custMap[c.customer_code] = c;
            }
          } catch { /* skip */ }
        }

        // 3. customer_item_prices 조회 (단가 정보)
        let allPrices: any[] = [];
        if (mappings.length > 0) {
          try {
            const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
              page: 1, size: 500,
              dataFilter: { enabled: true, filters: [
                { columnName: "item_id", operator: "equals", value: itemKey },
              ]},
              autoFilter: true,
            });
            allPrices = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
          } catch { /* skip */ }
        }

        // 4. 거래처별 중복 제거 + 오늘 날짜 기준 단가 매칭
        const priceResolve = (col: string, code: string) => {
          if (!code) return "";
          return priceCategoryOptions[col]?.find((o: any) => o.code === code)?.label || code;
        };
        const today = new Date().toISOString().split("T")[0];
        const seenCustIds = new Set<string>();
        const sortedMappings = [...mappings].sort((a: any, b: any) => (a.customer_id || "").localeCompare(b.customer_id || ""));

        setCustomerItems(sortedMappings.map((m: any) => {
          const custKey = m.customer_id || "";
          const isFirstOfGroup = !seenCustIds.has(custKey);
          if (custKey) seenCustIds.add(custKey);

          const custPriceList = allPrices.filter((p: any) => p.customer_id === custKey);
          const todayPrice = custPriceList.find((p: any) =>
            (!p.start_date || p.start_date <= today) && (!p.end_date || p.end_date >= today)
          ) || custPriceList[0] || {};

          return {
            ...m,
            customer_code: isFirstOfGroup ? custKey : "",
            customer_name: isFirstOfGroup ? (custMap[custKey]?.customer_name || "") : "",
            customer_item_code: m.customer_item_code || "",
            customer_item_name: m.customer_item_name || "",
            base_price: todayPrice.base_price || "",
            calculated_price: todayPrice.calculated_price || todayPrice.unit_price || "",
            currency_code: priceResolve("currency_code", todayPrice.currency_code || ""),
          };
        }));
      } catch (err) {
        console.error("거래처 조회 실패:", err);
      } finally {
        setCustomerLoading(false);
      }
    };
    fetchCustomerItems();
  }, [selectedItem?.item_number, priceCategoryOptions]); // eslint-disable-line react-hooks/exhaustive-deps

  // 거래처 검색
  const searchCustomers = async () => {
    setCustSearchLoading(true);
    try {
      const filters: any[] = [];
      if (custSearchKeyword) filters.push({ columnName: "customer_name", operator: "contains", value: custSearchKeyword });
      const res = await apiClient.post(`/table-management/tables/${CUSTOMER_TABLE}/data`, {
        page: 1, size: 50,
        dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
        autoFilter: true,
      });
      const all = res.data?.data?.data || res.data?.data?.rows || [];
      // 이미 등록된 거래처 제외
      const existing = new Set(customerItems.map((c: any) => c.customer_id || c.customer_code));
      setCustSearchResults(all.filter((c: any) => !existing.has(c.customer_code)));
    } catch { /* skip */ } finally { setCustSearchLoading(false); }
  };

  // 거래처 선택 → 상세 모달로 이동
  const goToCustDetail = () => {
    const selected = custSearchResults.filter((c) => custCheckedIds.has(c.id));
    if (selected.length === 0) { toast.error("거래처를 선택해주세요."); return; }
    setSelectedCustsForDetail(selected);
    const mappings: typeof custMappings = {};
    const prices: typeof custPrices = {};
    for (const cust of selected) {
      const key = cust.customer_code || cust.id;
      mappings[key] = [];
      prices[key] = [{
        _id: `p_${Date.now()}_${Math.random()}`,
        start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
        base_price_type: "CAT_MLAMFGFT_4RZW", base_price: selectedItem?.standard_price || selectedItem?.selling_price || "",
        discount_type: "", discount_value: "", rounding_type: "", rounding_unit_value: "",
        calculated_price: selectedItem?.standard_price || selectedItem?.selling_price || "",
      }];
    }
    setCustMappings(mappings);
    setCustPrices(prices);
    setCustSelectOpen(false);
    setCustDetailOpen(true);
  };

  const addMappingRow = (custKey: string) => {
    setCustMappings((prev) => ({
      ...prev,
      [custKey]: [...(prev[custKey] || []), { _id: `m_${Date.now()}_${Math.random()}`, customer_item_code: "", customer_item_name: "" }],
    }));
  };

  const removeMappingRow = (custKey: string, rowId: string) => {
    setCustMappings((prev) => ({
      ...prev,
      [custKey]: (prev[custKey] || []).filter((r) => r._id !== rowId),
    }));
  };

  const updateMappingRow = (custKey: string, rowId: string, field: string, value: string) => {
    setCustMappings((prev) => ({
      ...prev,
      [custKey]: (prev[custKey] || []).map((r) => r._id === rowId ? { ...r, [field]: value } : r),
    }));
  };

  const addPriceRow = (custKey: string) => {
    setCustPrices((prev) => ({
      ...prev,
      [custKey]: [...(prev[custKey] || []), {
        _id: `p_${Date.now()}_${Math.random()}`,
        start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
        base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "",
        discount_type: "", discount_value: "", rounding_type: "", rounding_unit_value: "",
        calculated_price: "",
      }],
    }));
  };

  const removePriceRow = (custKey: string, rowId: string) => {
    setCustPrices((prev) => ({
      ...prev,
      [custKey]: (prev[custKey] || []).filter((r) => r._id !== rowId),
    }));
  };

  const updatePriceRow = (custKey: string, rowId: string, field: string, value: string) => {
    setCustPrices((prev) => ({
      ...prev,
      [custKey]: (prev[custKey] || []).map((r) => {
        if (r._id !== rowId) return r;
        const updated = { ...r, [field]: value };
        if (["base_price", "discount_type", "discount_value"].includes(field)) {
          const bp = Number(updated.base_price) || 0;
          const dv = Number(updated.discount_value) || 0;
          const dt = updated.discount_type;
          let calc = bp;
          if (dt === "CAT_MLAMBEC8_URQA") calc = bp * (1 - dv / 100);
          else if (dt === "CAT_MLAMBLFM_JTLO") calc = bp - dv;
          updated.calculated_price = String(Math.round(calc));
        }
        return updated;
      }),
    }));
  };

  const openEditCust = async (row: any) => {
    const custKey = row.customer_code || row.customer_id;

    // customer_mng에서 거래처 정보 조회
    let custInfo: any = { customer_code: custKey, customer_name: row.customer_name || "" };
    try {
      const res = await apiClient.post(`/table-management/tables/customer_mng/data`, {
        page: 1, size: 1,
        dataFilter: { enabled: true, filters: [{ columnName: "customer_code", operator: "equals", value: custKey }] },
        autoFilter: true,
      });
      const found = (res.data?.data?.data || res.data?.data?.rows || [])[0];
      if (found) custInfo = found;
    } catch { /* skip */ }

    const mappingRows = [{
      _id: `m_existing_${row.id}`,
      customer_item_code: row.customer_item_code || "",
      customer_item_name: row.customer_item_name || "",
    }].filter((m) => m.customer_item_code || m.customer_item_name);

    const priceRows = [{
      _id: `p_existing_${row.id}`,
      start_date: row.start_date || "",
      end_date: row.end_date || "",
      currency_code: row.currency_code || "CAT_MLAMDKVN_PZJI",
      base_price_type: row.base_price_type || "CAT_MLAMFGFT_4RZW",
      base_price: row.base_price ? String(row.base_price) : "",
      discount_type: row.discount_type || "",
      discount_value: row.discount_value ? String(row.discount_value) : "",
      rounding_type: row.rounding_type || "",
      rounding_unit_value: row.rounding_unit_value || "",
      calculated_price: row.calculated_price ? String(row.calculated_price) : "",
    }].filter((p) => p.base_price || p.start_date);

    if (priceRows.length === 0) {
      priceRows.push({
        _id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
        base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
        rounding_type: "", rounding_unit_value: "", calculated_price: "",
      });
    }

    setSelectedCustsForDetail([custInfo]);
    setCustMappings({ [custKey]: mappingRows });
    setCustPrices({ [custKey]: priceRows });
    setEditCustData(row);
    setCustDetailOpen(true);
  };

  const handleCustDetailSave = async () => {
    if (!selectedItem) return;
    const isEditingExisting = !!editCustData;
    setSaving(true);
    try {
      for (const cust of selectedCustsForDetail) {
        const custKey = cust.customer_code || cust.id;
        const mappingRows = custMappings[custKey] || [];

        if (isEditingExisting && editCustData?.id) {
          await apiClient.put(`/table-management/tables/${MAPPING_TABLE}/edit`, {
            originalData: { id: editCustData.id },
            updatedData: {
              customer_item_code: mappingRows[0]?.customer_item_code || "",
              customer_item_name: mappingRows[0]?.customer_item_name || "",
            },
          });

          // 기존 prices 삭제 후 재등록
          try {
            const existingPrices = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
              page: 1, size: 100,
              dataFilter: { enabled: true, filters: [
                { columnName: "mapping_id", operator: "equals", value: editCustData.id },
              ]}, autoFilter: true,
            });
            const existing = existingPrices.data?.data?.data || existingPrices.data?.data?.rows || [];
            if (existing.length > 0) {
              await apiClient.delete(`/table-management/tables/customer_item_prices/delete`, {
                data: existing.map((p: any) => ({ id: p.id })),
              });
            }
          } catch { /* skip */ }

          const priceRows = (custPrices[custKey] || []).filter((p) =>
            (p.base_price && Number(p.base_price) > 0) || p.start_date
          );
          for (const price of priceRows) {
            await apiClient.post(`/table-management/tables/customer_item_prices/add`, {
              id: crypto.randomUUID(),
              mapping_id: editCustData.id,
              customer_id: custKey,
              item_id: selectedItem.item_number,
              start_date: price.start_date || null, end_date: price.end_date || null,
              currency_code: price.currency_code || null, base_price_type: price.base_price_type || null,
              base_price: price.base_price ? Number(price.base_price) : null,
              discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null,
              rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null,
              calculated_price: price.calculated_price ? Number(price.calculated_price) : null,
            });
          }
        } else {
          // 신규 등록
          const mappingRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, {
            id: crypto.randomUUID(),
            customer_id: custKey, item_id: selectedItem.item_number,
            customer_item_code: mappingRows[0]?.customer_item_code || "",
            customer_item_name: mappingRows[0]?.customer_item_name || "",
          });
          const mappingId = mappingRes.data?.data?.id || null;

          for (let mi = 1; mi < mappingRows.length; mi++) {
            await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, {
              id: crypto.randomUUID(),
              customer_id: custKey, item_id: selectedItem.item_number,
              customer_item_code: mappingRows[mi].customer_item_code || "",
              customer_item_name: mappingRows[mi].customer_item_name || "",
            });
          }

          const priceRows = (custPrices[custKey] || []).filter((p) =>
            (p.base_price && Number(p.base_price) > 0) || p.start_date
          );
          for (const price of priceRows) {
            await apiClient.post(`/table-management/tables/customer_item_prices/add`, {
              id: crypto.randomUUID(),
              mapping_id: mappingId || "", customer_id: custKey, item_id: selectedItem.item_number,
              start_date: price.start_date || null, end_date: price.end_date || null,
              currency_code: price.currency_code || null, base_price_type: price.base_price_type || null,
              base_price: price.base_price ? Number(price.base_price) : null,
              discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null,
              rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null,
              calculated_price: price.calculated_price ? Number(price.calculated_price) : null,
            });
          }
        }
      }
      toast.success(isEditingExisting ? "수정되었습니다." : `${selectedCustsForDetail.length}개 거래처가 추가되었습니다.`);
      setCustDetailOpen(false);
      setEditCustData(null);
      setCustCheckedIds(new Set());
      // 우측 새로고침
      const sid = selectedItemId;
      setSelectedItemId(null);
      setTimeout(() => setSelectedItemId(sid), 50);
    } catch (err: any) {
      toast.error(err.response?.data?.message || "저장에 실패했습니다.");
    } finally {
      setSaving(false);
    }
  };

  // 품목 수정
  const openEditItem = () => {
    if (!selectedItem) return;
    setEditItemForm({ ...selectedItem });
    setEditItemOpen(true);
  };

  const handleEditSave = async () => {
    if (!editItemForm.id) return;
    setSaving(true);
    try {
      await apiClient.put(`/table-management/tables/${ITEM_TABLE}/edit`, {
        originalData: { id: editItemForm.id },
        updatedData: {
          selling_price: editItemForm.selling_price || null,
          standard_price: editItemForm.standard_price || null,
          currency_code: editItemForm.currency_code || null,
        },
      });
      toast.success("수정되었습니다.");
      setEditItemOpen(false);
      fetchItems();
    } catch (err: any) {
      toast.error(err.response?.data?.message || "수정에 실패했습니다.");
    } finally {
      setSaving(false);
    }
  };

  // 우측: 거래처 매핑 삭제
  const handleCustomerMappingDelete = async () => {
    if (customerCheckedIds.length === 0) return;
    const ok = await confirm(`선택한 ${customerCheckedIds.length}개 거래처 매핑을 삭제하시겠습니까?`, {
      description: "관련된 단가 정보도 함께 삭제됩니다.",
      variant: "destructive", confirmText: "삭제",
    });
    if (!ok) return;
    try {
      // 관련 단가 삭제
      for (const mappingId of customerCheckedIds) {
        try {
          const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
            page: 1, size: 500,
            dataFilter: { enabled: true, filters: [{ columnName: "mapping_id", operator: "equals", value: mappingId }] },
            autoFilter: true,
          });
          const prices = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
          if (prices.length > 0) {
            await apiClient.delete(`/table-management/tables/customer_item_prices/delete`, {
              data: prices.map((p: any) => ({ id: p.id })),
            });
          }
        } catch { /* skip */ }
      }
      // 매핑 삭제
      await apiClient.delete(`/table-management/tables/${MAPPING_TABLE}/delete`, {
        data: customerCheckedIds.map((id) => ({ id })),
      });
      toast.success(`${customerCheckedIds.length}개 거래처 매핑이 삭제되었습니다.`);
      setCustomerCheckedIds([]);
      const sid = selectedItemId;
      setSelectedItemId(null);
      setTimeout(() => setSelectedItemId(sid), 50);
    } catch {
      toast.error("삭제에 실패했습니다.");
    }
  };

  // 엑셀 다운로드
  const handleExcelDownload = async () => {
    if (items.length === 0) return;
    const data = items.map((i) => ({
      품번: i.item_number, 품명: i.item_name, 규격: i.size, 단위: i.unit,
      기준단가: i.standard_price, 판매가격: i.selling_price, 통화: i.currency_code, 상태: i.status,
    }));
    await exportToExcel(data, "판매품목정보.xlsx", "판매품목");
    toast.success("다운로드 완료");
  };

  // EDataTable 컬럼 정의 (판매품목)
  const itemColumns: EDataTableColumn[] = [
    { key: "item_number", label: "품번", width: "w-[110px]" },
    { key: "item_name", label: "품명", minWidth: "min-w-[130px]" },
    { key: "size", label: "규격", width: "w-[80px]" },
    { key: "unit", label: "단위", width: "w-[60px]" },
    { key: "standard_price", label: "기준단가", width: "w-[90px]", align: "right", formatNumber: true },
    { key: "selling_price", label: "판매가격", width: "w-[90px]", align: "right", formatNumber: true },
    { key: "currency_code", label: "통화", width: "w-[50px]" },
    { key: "status", label: "상태", width: "w-[60px]" },
  ];

  return (
    <div className="flex h-full flex-col gap-3 p-3">

      {/* 검색 필터 (DynamicSearchFilter) */}
      <DynamicSearchFilter
        tableName={ITEM_TABLE}
        filterId="c16-sales-item"
        onFilterChange={setSearchFilters}
        dataCount={items.length}
        externalFilterConfig={ts.filterConfig}
        extraActions={
          <div className="flex gap-1.5">
            <Button variant="outline" size="sm" className="h-8" onClick={() => setExcelUploadOpen(true)}>
              <FileSpreadsheet className="w-3.5 h-3.5" />
              엑셀 업로드
            </Button>
            <Button variant="outline" size="sm" className="h-8" onClick={handleExcelDownload}>
              <Download className="w-3.5 h-3.5" />
              엑셀 다운로드
            </Button>
          </div>
        }
      />

      {/* ── 마스터-디테일 분할 패널 ── */}
      <div className="flex-1 overflow-hidden border rounded-lg bg-background">
        <ResizablePanelGroup direction="horizontal">

          {/* 좌측: 판매품목 목록 (마스터) */}
          <ResizablePanel defaultSize={55} minSize={30}>
            <div className="flex flex-col h-full bg-muted">
              {/* 패널 헤더 */}
              <div className="flex items-center justify-between px-4 py-2.5 border-b bg-muted shrink-0">
                <div className="flex items-center gap-2">
                  <span className="text-[13px] font-bold text-foreground">판매품목 목록</span>
                  <span className="text-[11px] font-semibold text-primary bg-primary/10 px-2 py-0.5 rounded-full">
                    {itemCount}건
                  </span>
                </div>
                <Button variant="ghost" size="sm" className="h-7 w-7 p-0" onClick={() => ts.setOpen(true)}>
                  <Settings2 className="w-3.5 h-3.5" />
                </Button>
              </div>
              {/* 테이블 영역 */}
              <EDataTable
                columns={itemColumns}
                data={ts.groupData(items)}
                rowKey={(row) => row.id}
                loading={itemLoading}
                emptyMessage="등록된 판매품목이 없어요"
                selectedId={selectedItemId}
                onSelect={(id) => setSelectedItemId(id)}
                onRowDoubleClick={() => openEditItem()}
                showRowNumber
                showPagination={false}
                draggableColumns={false}
                columnOrderKey="c16-sales-item"
              />
            </div>
          </ResizablePanel>

          <ResizableHandle withHandle />

          {/* 우측: 거래처 정보 (디테일) */}
          <ResizablePanel defaultSize={45} minSize={25}>
            <div className="flex flex-col h-full bg-muted">
              {!selectedItemId ? (
                /* 빈 상태 */
                <div className="flex-1 flex items-center justify-center m-5">
                  <div className="flex flex-col items-center gap-4 border-2 border-dashed border-border rounded-lg p-10 text-center">
                    <Users className="w-12 h-12 text-muted-foreground/40" />
                    <div>
                      <div className="text-sm font-semibold text-muted-foreground">품목을 선택해주세요</div>
                      <div className="text-xs text-muted-foreground mt-1">좌측에서 품목을 선택하면 거래처 정보가 표시돼요</div>
                    </div>
                  </div>
                </div>
              ) : (
                <>
                  {/* 선택 품목 상세 헤더 */}
                  <div className="flex items-center justify-between px-4 py-2.5 border-b bg-muted shrink-0">
                    <div className="flex items-center gap-2 min-w-0">
                      <span className="text-[13px] font-bold text-foreground truncate">{selectedItem?.item_name || "-"}</span>
                      <span className="text-[11px] font-mono text-muted-foreground bg-muted-foreground/10 px-2 py-0.5 rounded-full shrink-0">
                        {selectedItem?.item_number || ""}
                      </span>
                    </div>
                    <Button variant="outline" size="sm" className="h-8 shrink-0" onClick={openEditItem}>
                      <Pencil className="w-3.5 h-3.5" />
                      수정
                    </Button>
                  </div>

                  {/* 거래처별 단가 서브헤더 */}
                  <div className="flex items-center justify-between px-4 py-2 border-b bg-muted shrink-0">
                    <div className="flex items-center gap-2">
                      <span className="text-xs font-semibold text-muted-foreground">거래처별 단가</span>
                      <span className="text-[11px] font-semibold text-primary bg-primary/10 px-1.5 py-0.5 rounded-full">
                        {customerItems.length}건
                      </span>
                    </div>
                    <div className="flex gap-1.5">
                      <Button
                        variant="default"
                        size="sm"
                        className="h-7 text-xs"
                        onClick={() => { setCustCheckedIds(new Set()); setCustSelectOpen(true); searchCustomers(); }}
                      >
                        <Plus className="w-3.5 h-3.5" />
                        거래처 추가
                      </Button>
                      <Button
                        variant="ghost"
                        size="sm"
                        className="h-7 text-xs text-destructive hover:text-destructive hover:bg-destructive/10"
                        disabled={customerCheckedIds.length === 0}
                        onClick={handleCustomerMappingDelete}
                      >
                        <Trash2 className="w-3.5 h-3.5" />
                        삭제
                      </Button>
                    </div>
                  </div>

                  {/* 거래처 테이블 */}
                  <div className="flex-1 overflow-auto">
                    {customerLoading ? (
                      <div className="flex items-center justify-center h-full">
                        <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />
                      </div>
                    ) : customerItems.length === 0 ? (
                      <div className="flex items-center justify-center h-full text-sm text-muted-foreground">
                        등록된 거래처가 없어요
                      </div>
                    ) : (
                      <Table noWrapper>
                        <TableHeader className="sticky top-0 z-10">
                          <TableRow className="bg-muted hover:bg-muted">
                            <TableHead className="sticky top-0 z-10 bg-card w-[36px] text-center">
                              <Checkbox
                                checked={customerItems.length > 0 && customerCheckedIds.length === customerItems.length}
                                onCheckedChange={(checked) => {
                                  if (checked === true) setCustomerCheckedIds(customerItems.map((c) => c.id));
                                  else setCustomerCheckedIds([]);
                                }}
                              />
                            </TableHead>
                            <TableHead className="sticky top-0 z-10 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[110px]">거래처코드</TableHead>
                            <TableHead className="sticky top-0 z-10 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground min-w-[120px]">거래처명</TableHead>
                            <TableHead className="sticky top-0 z-10 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[100px]">거래처품번</TableHead>
                            <TableHead className="sticky top-0 z-10 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[100px]">거래처품명</TableHead>
                            <TableHead className="sticky top-0 z-10 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[80px] text-right">기준가</TableHead>
                            <TableHead className="sticky top-0 z-10 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[80px] text-right">단가</TableHead>
                            <TableHead className="sticky top-0 z-10 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[50px]">통화</TableHead>
                          </TableRow>
                        </TableHeader>
                        <TableBody>
                          {customerItems.map((row) => (
                            <TableRow
                              key={row.id}
                              className={cn(
                                "cursor-pointer transition-all",
                                customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
                              )}
                              onDoubleClick={() => openEditCust(row)}
                            >
                              <TableCell className="text-center">
                                <Checkbox
                                  checked={customerCheckedIds.includes(row.id)}
                                  onCheckedChange={(checked) => {
                                    if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
                                    else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
                                  }}
                                />
                              </TableCell>
                              <TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
                              <TableCell className="text-sm text-foreground">{row.customer_name}</TableCell>
                              <TableCell className="text-[13px] text-muted-foreground">{row.customer_item_code}</TableCell>
                              <TableCell className="text-[13px] text-muted-foreground">{row.customer_item_name}</TableCell>
                              <TableCell className="text-[13px] text-right font-mono text-muted-foreground">{formatNum(row.base_price)}</TableCell>
                              <TableCell className="text-[13px] text-right font-mono text-foreground font-semibold">{formatNum(row.calculated_price)}</TableCell>
                              <TableCell className="text-[13px] text-muted-foreground">{row.currency_code}</TableCell>
                            </TableRow>
                          ))}
                        </TableBody>
                      </Table>
                    )}
                  </div>
                </>
              )}
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>

      {/* ── 품목 수정 모달 ── */}
      <Dialog open={editItemOpen} onOpenChange={setEditItemOpen}>
        <DialogContent className="max-w-2xl">
          <DialogHeader>
            <DialogTitle>판매품목 수정</DialogTitle>
            <DialogDescription>
              {editItemForm.item_number || ""} — {editItemForm.item_name || ""}
            </DialogDescription>
          </DialogHeader>
          <div className="grid grid-cols-2 gap-4 py-4">
            {/* 품목 기본정보 (읽기 전용) */}
            {[
              { key: "item_number", label: "품목코드" },
              { key: "item_name", label: "품명" },
              { key: "size", label: "규격" },
              { key: "unit", label: "단위" },
              { key: "material", label: "재질" },
              { key: "status", label: "상태" },
            ].map((f) => (
              <div key={f.key} className="space-y-1.5">
                <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">{f.label}</Label>
                <Input value={editItemForm[f.key] || ""} className="h-9 bg-muted/50" disabled />
              </div>
            ))}

            <div className="col-span-2 border-t my-1" />

            {/* 판매 설정 (수정 가능) */}
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">판매가격</Label>
              <Input
                value={editItemForm.selling_price || ""}
                onChange={(e) => setEditItemForm((p) => ({ ...p, selling_price: e.target.value }))}
                placeholder="판매가격을 입력해주세요"
                className="h-9"
              />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">기준단가</Label>
              <Input
                value={editItemForm.standard_price || ""}
                onChange={(e) => setEditItemForm((p) => ({ ...p, standard_price: e.target.value }))}
                placeholder="기준단가를 입력해주세요"
                className="h-9"
              />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">통화</Label>
              <Select
                value={editItemForm.currency_code || ""}
                onValueChange={(v) => setEditItemForm((p) => ({ ...p, currency_code: v }))}
              >
                <SelectTrigger className="h-9">
                  <SelectValue placeholder="통화를 선택해주세요" />
                </SelectTrigger>
                <SelectContent>
                  {(categoryOptions["currency_code"] || []).map((o) => (
                    <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setEditItemOpen(false)}>취소</Button>
            <Button onClick={handleEditSave} disabled={saving}>
              {saving ? <Loader2 className="w-4 h-4 animate-spin" /> : <Save className="w-4 h-4" />}
              저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ── 거래처 검색 및 추가 모달 ── */}
      <Dialog open={custSelectOpen} onOpenChange={setCustSelectOpen}>
        <DialogContent className="max-w-2xl">
          <DialogHeader>
            <DialogTitle>거래처 검색 및 추가</DialogTitle>
            <DialogDescription>품목에 추가할 거래처를 선택해주세요.</DialogDescription>
          </DialogHeader>
          <div className="space-y-3 py-2">
            {/* 검색바 */}
            <div className="flex gap-2">
              <Input
                placeholder="거래처명으로 검색해주세요"
                value={custSearchKeyword}
                onChange={(e) => setCustSearchKeyword(e.target.value)}
                onKeyDown={(e) => e.key === "Enter" && searchCustomers()}
                className="h-9 flex-1"
              />
              <Button size="sm" onClick={searchCustomers} disabled={custSearchLoading} className="h-9">
                {custSearchLoading ? <Loader2 className="w-4 h-4 animate-spin" /> : <><Search className="w-4 h-4" /> 조회</>}
              </Button>
            </div>
            {/* 검색 결과 테이블 */}
            <div className="overflow-auto max-h-[350px] border rounded-lg">
              <Table noWrapper>
                <TableHeader className="sticky top-0 z-10">
                  <TableRow className="bg-muted hover:bg-muted">
                    <TableHead className="sticky top-0 bg-card w-[40px] text-center">
                      <Checkbox
                        checked={custSearchResults.length > 0 && custCheckedIds.size === custSearchResults.length}
                        onCheckedChange={(checked) => {
                          if (checked === true) setCustCheckedIds(new Set(custSearchResults.map((c) => c.id)));
                          else setCustCheckedIds(new Set());
                        }}
                      />
                    </TableHead>
                    <TableHead className="sticky top-0 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[110px]">거래처코드</TableHead>
                    <TableHead className="sticky top-0 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground min-w-[130px]">거래처명</TableHead>
                    <TableHead className="sticky top-0 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[80px]">거래유형</TableHead>
                    <TableHead className="sticky top-0 bg-card text-[11px] font-bold uppercase tracking-wide text-muted-foreground w-[80px]">담당자</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {custSearchResults.length === 0 ? (
                    <TableRow>
                      <TableCell colSpan={5} className="text-center text-muted-foreground py-8 text-sm">
                        검색 결과가 없어요
                      </TableCell>
                    </TableRow>
                  ) : custSearchResults.map((c) => (
                    <TableRow
                      key={c.id}
                      className={cn("cursor-pointer", custCheckedIds.has(c.id) && "bg-primary/[0.08]")}
                      onClick={() => setCustCheckedIds((prev) => {
                        const next = new Set(prev);
                        if (next.has(c.id)) next.delete(c.id); else next.add(c.id);
                        return next;
                      })}
                    >
                      <TableCell className="text-center">
                        <Checkbox
                          checked={custCheckedIds.has(c.id)}
                          onCheckedChange={(checked) => {
                            setCustCheckedIds((prev) => {
                              const next = new Set(prev);
                              if (checked === true) next.add(c.id); else next.delete(c.id);
                              return next;
                            });
                          }}
                        />
                      </TableCell>
                      <TableCell className="text-[13px] font-mono text-muted-foreground">{c.customer_code}</TableCell>
                      <TableCell className="text-sm font-medium text-foreground">{c.customer_name}</TableCell>
                      <TableCell className="text-[13px] text-muted-foreground">{c.division}</TableCell>
                      <TableCell className="text-[13px] text-muted-foreground">{c.contact_person}</TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>
          </div>
          <DialogFooter>
            <div className="flex items-center gap-2 w-full justify-between">
              <span className="text-sm text-muted-foreground">{custCheckedIds.size}개 선택됨</span>
              <div className="flex gap-2">
                <Button variant="outline" onClick={() => setCustSelectOpen(false)}>취소</Button>
                <Button onClick={goToCustDetail} disabled={custCheckedIds.size === 0}>
                  <Plus className="w-4 h-4" />
                  {custCheckedIds.size}개 다음
                </Button>
              </div>
            </div>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ── 거래처 상세 입력/수정 모달 ── */}
      <Dialog open={custDetailOpen} onOpenChange={setCustDetailOpen}>
        <DialogContent className="max-w-[1100px] max-h-[90vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>
              거래처 상세정보 {editCustData ? "수정" : "입력"} — {selectedItem?.item_name || ""}
            </DialogTitle>
            <DialogDescription>
              {editCustData ? "거래처 품번/품명과 기간별 단가를 수정해주세요." : "선택한 거래처의 품번/품명과 기간별 단가를 설정해주세요."}
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-6 py-2">
            {selectedCustsForDetail.map((cust, idx) => {
              const custKey = cust.customer_code || cust.id;
              const mappingRows = custMappings[custKey] || [];
              const prices = custPrices[custKey] || [];

              return (
                <div key={custKey} className="border rounded-lg overflow-hidden">
                  {/* 거래처 헤더 */}
                  <div className="flex items-center gap-2.5 px-4 py-3 bg-muted border-b">
                    <span className="text-[13px] font-bold text-foreground">{idx + 1}. {cust.customer_name || custKey}</span>
                    <span className="text-[11px] font-mono text-muted-foreground bg-muted-foreground/10 px-2 py-0.5 rounded-full">
                      {custKey}
                    </span>
                  </div>

                  <div className="flex gap-4 p-4 bg-card">
                    {/* 좌: 거래처 품번/품명 */}
                    <div className="flex-1 border rounded-lg p-4 bg-muted/50">
                      <div className="flex items-center justify-between mb-3">
                        <span className="text-sm font-semibold text-foreground">거래처 품번/품명 관리</span>
                        <Button variant="outline" size="sm" className="h-7 text-xs" onClick={() => addMappingRow(custKey)}>
                          <Plus className="h-3 w-3" />
                          품번 추가
                        </Button>
                      </div>
                      <div className="space-y-2">
                        {mappingRows.length === 0 ? (
                          <div className="text-xs text-muted-foreground py-2">입력된 거래처 품번이 없어요</div>
                        ) : mappingRows.map((mRow, mIdx) => (
                          <div key={mRow._id} className="flex gap-2 items-center">
                            <span className="text-xs text-muted-foreground w-4 shrink-0">{mIdx + 1}</span>
                            <Input
                              value={mRow.customer_item_code}
                              onChange={(e) => updateMappingRow(custKey, mRow._id, "customer_item_code", e.target.value)}
                              placeholder="거래처 품번"
                              className="h-8 text-sm flex-1"
                            />
                            <Input
                              value={mRow.customer_item_name}
                              onChange={(e) => updateMappingRow(custKey, mRow._id, "customer_item_name", e.target.value)}
                              placeholder="거래처 품명"
                              className="h-8 text-sm flex-1"
                            />
                            <Button
                              variant="ghost" size="sm"
                              className="h-7 w-7 p-0 text-destructive shrink-0"
                              onClick={() => removeMappingRow(custKey, mRow._id)}
                            >
                              <X className="h-3 w-3" />
                            </Button>
                          </div>
                        ))}
                      </div>
                    </div>

                    {/* 우: 기간별 단가 */}
                    <div className="flex-1 border rounded-lg p-4 bg-muted/30">
                      <div className="flex items-center justify-between mb-3">
                        <span className="text-sm font-semibold text-foreground">기간별 단가 설정</span>
                        <Button variant="outline" size="sm" className="h-7 text-xs" onClick={() => addPriceRow(custKey)}>
                          <Plus className="h-3 w-3" />
                          단가 추가
                        </Button>
                      </div>
                      <div className="space-y-3">
                        {prices.map((price, pIdx) => (
                          <div key={price._id} className="border rounded-lg p-3 bg-background space-y-2">
                            <div className="flex items-center justify-between">
                              <span className="text-xs font-medium text-muted-foreground">단가 {pIdx + 1}</span>
                              {prices.length > 1 && (
                                <Button
                                  variant="ghost" size="sm"
                                  className="h-6 w-6 p-0 text-destructive"
                                  onClick={() => removePriceRow(custKey, price._id)}
                                >
                                  <X className="h-3 w-3" />
                                </Button>
                              )}
                            </div>
                            {/* 기간 + 통화 */}
                            <div className="flex gap-2 items-center">
                              <Input
                                type="date"
                                value={price.start_date}
                                onChange={(e) => updatePriceRow(custKey, price._id, "start_date", e.target.value)}
                                className="h-8 text-xs flex-1"
                              />
                              <span className="text-xs text-muted-foreground">~</span>
                              <Input
                                type="date"
                                value={price.end_date}
                                onChange={(e) => updatePriceRow(custKey, price._id, "end_date", e.target.value)}
                                className="h-8 text-xs flex-1"
                              />
                              <div className="w-[80px]">
                                <Select
                                  value={price.currency_code}
                                  onValueChange={(v) => updatePriceRow(custKey, price._id, "currency_code", v)}
                                >
                                  <SelectTrigger className="h-8 text-xs">
                                    <SelectValue placeholder="통화" />
                                  </SelectTrigger>
                                  <SelectContent>
                                    {(priceCategoryOptions["currency_code"] || []).map((o) => (
                                      <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                                    ))}
                                  </SelectContent>
                                </Select>
                              </div>
                            </div>
                            {/* 기준가 + 할인 + 반올림 */}
                            <div className="flex gap-2 items-center">
                              <div className="w-[90px]">
                                <Select
                                  value={price.base_price_type}
                                  onValueChange={(v) => updatePriceRow(custKey, price._id, "base_price_type", v)}
                                >
                                  <SelectTrigger className="h-8 text-xs">
                                    <SelectValue placeholder="기준" />
                                  </SelectTrigger>
                                  <SelectContent>
                                    {(priceCategoryOptions["base_price_type"] || []).map((o) => (
                                      <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                                    ))}
                                  </SelectContent>
                                </Select>
                              </div>
                              <Input
                                value={price.base_price}
                                onChange={(e) => updatePriceRow(custKey, price._id, "base_price", e.target.value)}
                                className="h-8 text-xs text-right flex-1"
                                placeholder="기준가"
                              />
                              <div className="w-[90px]">
                                <Select
                                  value={price.discount_type}
                                  onValueChange={(v) => updatePriceRow(custKey, price._id, "discount_type", v)}
                                >
                                  <SelectTrigger className="h-8 text-xs">
                                    <SelectValue placeholder="할인" />
                                  </SelectTrigger>
                                  <SelectContent>
                                    <SelectItem value="none">할인없음</SelectItem>
                                    {(priceCategoryOptions["discount_type"] || []).map((o) => (
                                      <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                                    ))}
                                  </SelectContent>
                                </Select>
                              </div>
                              <Input
                                value={price.discount_value}
                                onChange={(e) => updatePriceRow(custKey, price._id, "discount_value", e.target.value)}
                                className="h-8 text-xs text-right w-[60px]"
                                placeholder="0"
                              />
                              <div className="w-[90px]">
                                <Select
                                  value={price.rounding_unit_value}
                                  onValueChange={(v) => updatePriceRow(custKey, price._id, "rounding_unit_value", v)}
                                >
                                  <SelectTrigger className="h-8 text-xs">
                                    <SelectValue placeholder="반올림" />
                                  </SelectTrigger>
                                  <SelectContent>
                                    {(priceCategoryOptions["rounding_unit_value"] || []).map((o) => (
                                      <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                                    ))}
                                  </SelectContent>
                                </Select>
                              </div>
                            </div>
                            {/* 계산 단가 */}
                            <div className="flex items-center justify-end gap-2 pt-1 border-t">
                              <span className="text-xs text-muted-foreground">계산 단가:</span>
                              <span className="font-bold text-sm text-foreground">
                                {price.calculated_price ? Number(price.calculated_price).toLocaleString() : "-"}
                              </span>
                            </div>
                          </div>
                        ))}
                      </div>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>

          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => {
                setCustDetailOpen(false);
                if (!editCustData) setCustSelectOpen(true);
                setEditCustData(null);
              }}
            >
              {editCustData ? "취소" : "← 이전"}
            </Button>
            <Button onClick={handleCustDetailSave} disabled={saving}>
              {saving ? <Loader2 className="w-4 h-4 animate-spin" /> : <Save className="w-4 h-4" />}
              저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

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

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

      {ConfirmDialogComponent}
    </div>
  );
}
