"use client";

import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "@/components/ui/dialog";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";
import {
  Search,
  Plus,
  Trash2,
  Loader2,
  Inbox,
  X,
  Save,
  ChevronRight,
  ChevronLeft,
  ChevronsLeft,
  ChevronsRight,
  Settings2,
  Filter,
  Check,
  ArrowUp,
  ArrowDown,
} from "lucide-react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { toast } from "sonner";
import { apiClient } from "@/lib/api/client";
import { useTableSettings } from "@/hooks/useTableSettings";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";
// EDataTable 제거 — 마스터-디테일 그룹 테이블로 교체
// API: /receiving/*
import {
  getReceivingList,
  createReceiving,
  updateReceiving,
  deleteReceiving,
  generateReceivingNumber,
  getReceivingWarehouses,
  getPurchaseOrderSources,
  getShipmentSources,
  getItemSources,
  type InboundItem,
  type PurchaseOrderSource,
  type ShipmentSource,
  type ItemSource,
  type WarehouseOption,
} from "@/lib/api/receiving";

const GRID_COLUMNS = [
  { key: "inbound_number", label: "입고번호" },
  { key: "inbound_type", label: "입고유형" },
  { key: "inbound_date", label: "입고일" },
  { key: "reference_number", label: "참조번호" },
  { key: "source_type", label: "데이터출처" },
  { key: "supplier_name", label: "공급처" },
  { key: "item_number", label: "품목코드" },
  { key: "item_name", label: "품목명" },
  { key: "spec", label: "규격" },
  { key: "inbound_qty", label: "입고수량" },
  { key: "unit_price", label: "단가" },
  { key: "total_amount", label: "금액" },
  { key: "warehouse_name", label: "창고" },
  { key: "inbound_status", label: "입고상태" },
  { key: "remark", label: "비고" },
];

// 총 컬럼 수: 체크박스(1) + GRID_COLUMNS(15) = 16
const TOTAL_COLS = 16;

// 헤더 필터 Popover
function HeaderFilterPopover({
  colKey, colLabel, uniqueValues, filterValues, onToggle, onClear,
}: {
  colKey: string;
  colLabel: string;
  uniqueValues: string[];
  filterValues: Set<string>;
  onToggle: (colKey: string, value: string) => void;
  onClear: (colKey: string) => void;
}) {
  const [filterSearch, setFilterSearch] = useState("");
  const hasFilter = filterValues.size > 0;
  const filteredValues = uniqueValues.filter(
    (v) => !filterSearch || v.toLowerCase().includes(filterSearch.toLowerCase())
  );

  return (
    <Popover>
      <PopoverTrigger asChild>
        <button
          onClick={(e) => e.stopPropagation()}
          className={cn(
            "hover:bg-primary/20 rounded p-0.5 transition-colors shrink-0",
            hasFilter && "text-primary bg-primary/10",
          )}
          title="필터"
        >
          <Filter className="h-3 w-3" />
        </button>
      </PopoverTrigger>
      <PopoverContent className="w-56 p-2" align="start" onClick={(e) => e.stopPropagation()}>
        <div className="space-y-2">
          <div className="flex items-center justify-between border-b pb-2">
            <span className="text-xs font-medium">필터: {colLabel}</span>
            {hasFilter && (
              <button onClick={() => onClear(colKey)} className="text-primary text-xs hover:underline">
                초기화
              </button>
            )}
          </div>
          <div className="relative">
            <Search className="absolute left-2 top-1/2 -translate-y-1/2 h-3 w-3 text-muted-foreground" />
            <Input
              value={filterSearch}
              onChange={(e) => setFilterSearch(e.target.value)}
              placeholder="검색..."
              className="h-7 text-xs pl-7"
            />
          </div>
          <div className="max-h-52 space-y-0.5 overflow-y-auto">
            {filteredValues.slice(0, 100).map((val) => {
              const isSelected = filterValues.has(val);
              return (
                <div
                  key={val}
                  className={cn(
                    "hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-xs",
                    isSelected && "bg-primary/10",
                  )}
                  onClick={() => onToggle(colKey, val)}
                >
                  <div className={cn(
                    "flex h-4 w-4 items-center justify-center rounded border shrink-0",
                    isSelected ? "bg-primary border-primary" : "border-input",
                  )}>
                    {isSelected && <Check className="text-primary-foreground h-3 w-3" />}
                  </div>
                  <span className="truncate">{val || "(빈 값)"}</span>
                </div>
              );
            })}
            {filteredValues.length > 100 && (
              <div className="text-muted-foreground px-2 py-1 text-xs">
                ...외 {filteredValues.length - 100}개
              </div>
            )}
          </div>
        </div>
      </PopoverContent>
    </Popover>
  );
}

// 입고유형 옵션
const INBOUND_TYPES = [
  { value: "구매입고", label: "구매입고" },
  { value: "외주입고", label: "외주입고" },
  { value: "사급자재입고", label: "사급자재입고" },
  { value: "반품입고", label: "반품입고" },
  { value: "기타입고", label: "기타입고" },
];

// 입고유형 카테고리 코드→라벨 매핑
const INBOUND_TYPE_CODE_MAP: Record<string, string> = {
  CAT_MLYTB8ON_A3AU: "구매입고",
  CAT_MLYTBMH6_9AB7: "외주입고",
  CAT_MLYTBSLW_5N81: "사급자재입고",
  CAT_MLYTBGEV_N23U: "반품입고",
  CAT_MLYTBYLU_0Z5T: "기타입고",
};
const resolveInboundType = (v: string) => INBOUND_TYPE_CODE_MAP[v] || v || "-";

const INBOUND_STATUS_OPTIONS = [
  { value: "대기", label: "대기" },
  { value: "입고완료", label: "입고완료" },
  { value: "부분입고", label: "부분입고" },
  { value: "입고취소", label: "입고취소" },
];

const getTypeVariant = (type: string): "default" | "secondary" | "outline" => {
  switch (type) {
    case "구매입고": return "default";
    case "반품입고": return "secondary";
    default: return "outline";
  }
};

const getStatusVariant = (status: string): "default" | "secondary" | "outline" | "destructive" => {
  switch (status) {
    case "입고완료": return "default";
    case "부분입고": return "secondary";
    case "입고취소": return "destructive";
    default: return "outline";
  }
};

// 소스 테이블 한글명 매핑
const SOURCE_TABLE_LABEL: Record<string, string> = {
  purchase_order_mng: "발주",
  shipment_instruction_detail: "출하",
  item_info: "품목",
};

// 선택된 소스 아이템 (등록 모달에서 사용)
interface SelectedSourceItem {
  key: string;
  inbound_type: string;
  reference_number: string;
  supplier_code: string;
  supplier_name: string;
  item_number: string;
  item_name: string;
  spec: string;
  material: string;
  unit: string;
  inbound_qty: number;
  unit_price: number;
  total_amount: number;
  source_table: string;
  source_id: string;
  detail_id?: string;
  header_id?: string;
}

export default function ReceivingPage() {
  const ts = useTableSettings("c16-receiving", "inbound_mng", GRID_COLUMNS);

  // 목록 데이터
  const [data, setData] = useState<InboundItem[]>([]);
  const [loading, setLoading] = useState(false);
  const [checkedIds, setCheckedIds] = useState<string[]>([]);

  // 페이지네이션
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(20);
  const [pageSizeInput, setPageSizeInput] = useState("20");

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

  // 헤더 필터 & 정렬
  const [headerFilters, setHeaderFilters] = useState<Record<string, Set<string>>>({});
  const [sortState, setSortState] = useState<{ key: string; direction: "asc" | "desc" } | null>(null);

  // 등록 모달
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [modalInboundType, setModalInboundType] = useState("구매입고");
  const [modalInboundNo, setModalInboundNo] = useState("");
  const [modalInboundDate, setModalInboundDate] = useState("");
  const [modalWarehouse, setModalWarehouse] = useState("");
  const [modalLocation, setModalLocation] = useState("");
  const [modalInspector, setModalInspector] = useState("");
  const [modalManager, setModalManager] = useState("");
  const [modalMemo, setModalMemo] = useState("");
  const [selectedItems, setSelectedItems] = useState<SelectedSourceItem[]>([]);
  const [saving, setSaving] = useState(false);

  // 수정 모드
  const [editMode, setEditMode] = useState(false);
  const [editItemIds, setEditItemIds] = useState<string[]>([]);

  // 소스 데이터
  const [sourceKeyword, setSourceKeyword] = useState("");
  const [sourceLoading, setSourceLoading] = useState(false);
  const [purchaseOrders, setPurchaseOrders] = useState<PurchaseOrderSource[]>([]);
  const [shipments, setShipments] = useState<ShipmentSource[]>([]);
  const [items, setItems] = useState<ItemSource[]>([]);
  const [warehouses, setWarehouses] = useState<WarehouseOption[]>([]);

  // 소스 데이터 페이징
  const [sourcePage, setSourcePage] = useState(1);
  const [sourcePageSize, setSourcePageSize] = useState(20);
  const [sourceTotalCount, setSourceTotalCount] = useState(0);

  // 구매관리 division 코드 (라벨 기준 조회)
  const [purchaseDivisionCode, setPurchaseDivisionCode] = useState<string>("");
  // 카테고리 코드→라벨 매핑 (재질, 단위)
  const [catMap, setCatMap] = useState<Record<string, Record<string, string>>>({});

  // 구매관리 division 코드 + 재질/단위 카테고리 로드
  useEffect(() => {
    const flatten = (arr: any[]): { code: string; label: string }[] => {
      const result: { code: string; label: string }[] = [];
      for (const v of arr) {
        result.push({ code: v.valueCode || v.value_code || v.code, label: v.valueLabel || v.value_label || v.label });
        if (v.children?.length) result.push(...flatten(v.children));
      }
      return result;
    };
    // division 카테고리에서 "구매관리" 라벨의 코드 조회
    apiClient.get("/table-categories/item_info/division/values").then((res) => {
      const vals = res.data?.data || [];
      const found = vals.find((v: any) => (v.valueLabel || v.value_label || v.label) === "구매관리");
      if (found) setPurchaseDivisionCode(found.value_code || found.code);
    }).catch(() => {});
    // 재질, 단위 카테고리
    const map: Record<string, Record<string, string>> = {};
    Promise.all(
      ["material", "inventory_unit"].map(async (col) => {
        try {
          const res = await apiClient.get(`/table-categories/item_info/${col}/values?filterCompanyCode=COMPANY_16`);
          const items = flatten(res.data?.data || []);
          map[col] = {};
          for (const item of items) map[col][item.code] = item.label;
        } catch { /* skip */ }
      })
    ).then(() => setCatMap(map));
  }, []);

  // 카테고리 코드→라벨 변환
  const resolveCat = useCallback((col: string, code: string) => {
    if (!code) return "";
    return catMap[col]?.[code] || code;
  }, [catMap]);

  // 목록 조회
  const fetchList = useCallback(async () => {
    setLoading(true);
    try {
      const params: Record<string, string | undefined> = {};
      for (const f of searchFilters) {
        if (!f.value) continue;
        if (f.columnName === "inbound_type") params.inbound_type = f.value;
        else if (f.columnName === "inbound_status") params.inbound_status = f.value;
        else if (f.columnName === "inbound_date" && f.operator === "between") {
          const [from, to] = f.value.split("~").map((s) => s.trim());
          if (from) params.date_from = from;
          if (to) params.date_to = to;
        } else {
          params.search_keyword = f.value;
        }
      }
      const res = await getReceivingList(params);
      if (res.success) setData(res.data);
    } catch {
      // 에러 무시
    } finally {
      setLoading(false);
    }
  }, [searchFilters]);

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

  // 창고 목록 로드
  useEffect(() => {
    (async () => {
      try {
        const res = await getReceivingWarehouses();
        if (res.success) setWarehouses(res.data);
      } catch {
        // ignore
      }
    })();
  }, []);

  // 플랫 행 생성 (입고유형 코드→라벨 변환, source_table→한글 등)
  const flatRows = useMemo(() => {
    return data.map((row) => ({
      ...row,
      inbound_type: resolveInboundType((row as any).detail_inbound_type || row.inbound_type),
      source_type: row.source_table ? (SOURCE_TABLE_LABEL[row.source_table] || row.source_table) : (row as any).source_type || "",
    }));
  }, [data]);

  // 컬럼별 고유값 (헤더 필터용)
  const columnUniqueValues = useMemo(() => {
    const result: Record<string, string[]> = {};
    for (const col of GRID_COLUMNS) {
      const values = new Set<string>();
      flatRows.forEach((row) => {
        const val = (row as any)[col.key];
        if (val !== null && val !== undefined && val !== "") values.add(String(val));
      });
      result[col.key] = Array.from(values).sort();
    }
    return result;
  }, [flatRows]);

  // 필터 + 정렬 적용된 플랫 데이터
  const filteredRows = useMemo(() => {
    let rows = [...flatRows];

    // 1차: 헤더 필터 적용
    for (const [colKey, values] of Object.entries(headerFilters)) {
      if (values.size === 0) continue;
      rows = rows.filter((row) => {
        const cellVal = (row as any)[colKey] != null ? String((row as any)[colKey]) : "";
        return values.has(cellVal);
      });
    }

    // 2차: 정렬
    if (sortState) {
      const { key, direction } = sortState;
      rows.sort((a, b) => {
        const av = (a as any)[key] ?? "";
        const bv = (b as any)[key] ?? "";
        const na = Number(av); const nb = Number(bv);
        if (!isNaN(na) && !isNaN(nb)) return direction === "asc" ? na - nb : nb - na;
        return direction === "asc" ? String(av).localeCompare(String(bv)) : String(bv).localeCompare(String(av));
      });
    }

    return rows;
  }, [flatRows, headerFilters, sortState]);

  // 페이지네이션 계산
  const totalPages = Math.max(1, Math.ceil(filteredRows.length / pageSize));
  const safePage = Math.min(Math.max(1, currentPage), totalPages);
  const paginatedRows = useMemo(() => {
    const start = (safePage - 1) * pageSize;
    return filteredRows.slice(start, start + pageSize);
  }, [filteredRows, safePage, pageSize]);

  const applyPageSize = () => {
    const n = parseInt(pageSizeInput, 10);
    if (!isNaN(n) && n >= 1) { setPageSize(n); setCurrentPage(1); }
    else setPageSizeInput(String(pageSize));
  };

  const getPageNumbers = (): (number | "...")[] => {
    const pages: (number | "...")[] = [];
    if (totalPages <= 7) {
      for (let i = 1; i <= totalPages; i++) pages.push(i);
    } else {
      pages.push(1);
      if (safePage > 3) pages.push("...");
      for (let i = Math.max(2, safePage - 1); i <= Math.min(totalPages - 1, safePage + 1); i++) pages.push(i);
      if (safePage < totalPages - 2) pages.push("...");
      pages.push(totalPages);
    }
    return pages;
  };

  // 필터 변경 시 첫 페이지로 이동
  useEffect(() => { setCurrentPage(1); }, [headerFilters, sortState, filteredRows.length]);

  // 헤더 필터 토글/초기화
  const toggleHeaderFilter = (colKey: string, value: string) => {
    setHeaderFilters((prev) => {
      const next = { ...prev };
      const set = new Set(next[colKey] || []);
      if (set.has(value)) set.delete(value); else set.add(value);
      if (set.size === 0) delete next[colKey]; else next[colKey] = set;
      return next;
    });
  };

  const clearHeaderFilter = (colKey: string) => {
    setHeaderFilters((prev) => {
      const next = { ...prev };
      delete next[colKey];
      return next;
    });
  };

  const handleSort = (key: string) => {
    setSortState((prev) =>
      prev?.key === key
        ? prev.direction === "asc" ? { key, direction: "desc" } : null
        : { key, direction: "asc" }
    );
  };

  // 삭제
  const handleDelete = async () => {
    if (checkedIds.length === 0) return;
    if (!confirm(`선택한 ${checkedIds.length}건을 삭제하시겠습니까?`)) return;
    for (const id of checkedIds) {
      await deleteReceiving(id);
    }
    setCheckedIds([]);
    fetchList();
  };

  // --- 등록 모달 ---

  // 소스 데이터 로드 함수
  const loadSourceData = useCallback(
    async (type: string, keyword?: string, pageOverride?: number) => {
      setSourceLoading(true);
      try {
        const params = {
          keyword: keyword || undefined,
          page: pageOverride ?? sourcePage,
          pageSize: sourcePageSize,
        };
        if (type === "구매입고") {
          const res = await getPurchaseOrderSources(params);
          if (res.success) {
            setPurchaseOrders(res.data);
            setSourceTotalCount(res.totalCount || 0);
          }
        } else if (type === "반품입고") {
          const res = await getShipmentSources(params);
          if (res.success) {
            setShipments(res.data);
            setSourceTotalCount(res.totalCount || 0);
          }
        } else {
          const res = await getItemSources({ ...params, division: purchaseDivisionCode || undefined });
          if (res.success) {
            setItems(res.data);
            setSourceTotalCount(res.totalCount || 0);
          }
        }
      } catch {
        // ignore
      } finally {
        setSourceLoading(false);
      }
    },
    [sourcePage, sourcePageSize]
  );

  const openRegisterModal = async () => {
    const defaultType = "구매입고";
    setEditMode(false);
    setEditItemIds([]);
    setModalInboundType(defaultType);
    setModalInboundDate(new Date().toISOString().split("T")[0]);
    setModalWarehouse("");
    setModalLocation("");
    setModalInspector("");
    setModalManager("");
    setModalMemo("");
    setSelectedItems([]);
    setSourceKeyword("");
    setPurchaseOrders([]);
    setShipments([]);
    setItems([]);
    setSourcePage(1);
    setSourceTotalCount(0);
    setIsModalOpen(true);

    // 입고번호 생성 + 발주 데이터 동시 로드
    try {
      const [numRes] = await Promise.all([
        generateReceivingNumber(),
        loadSourceData(defaultType, undefined, 1),
      ]);
      if (numRes.success) setModalInboundNo(numRes.data);
    } catch {
      setModalInboundNo("");
    }
  };

  // 수정 모달 열기
  const openEditModal = (row: InboundItem) => {
    const inNo = row.inbound_number;
    const grouped = data.filter((d) => d.inbound_number === inNo);
    const first = grouped[0] || row;

    setEditMode(true);
    setEditItemIds(grouped.map((g, idx) => (g as any).detail_id || `${g.id}__${idx}`));
    setModalInboundNo(inNo);
    setModalInboundType(first.inbound_type || "구매입고");
    setModalInboundDate(first.inbound_date ? String(first.inbound_date).slice(0, 10) : "");
    setModalWarehouse(first.warehouse_code || "");
    setModalLocation(first.location_code || "");
    setModalInspector((first as any).inspector || "");
    setModalManager((first as any).manager || "");
    setModalMemo(first.memo || "");
    setSelectedItems(
      grouped.map((g, idx) => ({
        key: (g as any).detail_id || `${g.id}__${idx}`,
        detail_id: (g as any).detail_id || undefined,
        header_id: g.id,
        inbound_type: (g as any).detail_inbound_type || g.inbound_type || "",
        reference_number: g.reference_number || "",
        supplier_code: (g as any).supplier_code || "",
        supplier_name: g.supplier_name || "",
        item_number: g.item_number || "",
        item_name: g.item_name || "",
        spec: g.spec || "",
        material: (g as any).material || "",
        unit: (g as any).unit || "",
        inbound_qty: Number(g.inbound_qty) || 0,
        unit_price: Number(g.unit_price) || 0,
        total_amount: Number(g.total_amount) || 0,
        source_table: (g as any).source_table || "",
        source_id: (g as any).source_id || "",
      }))
    );
    setSourceKeyword("");
    setPurchaseOrders([]);
    setShipments([]);
    setItems([]);
    setSourcePage(1);
    setSourceTotalCount(0);
    setIsModalOpen(true);
    loadSourceData(first.inbound_type || "구매입고", undefined, 1);
  };

  // 검색 버튼 클릭 시
  const searchSourceData = useCallback(async () => {
    setSourcePage(1);
    await loadSourceData(modalInboundType, sourceKeyword || undefined, 1);
  }, [modalInboundType, sourceKeyword, loadSourceData]);

  // 입고유형 변경 시 소스 데이터 자동 리로드
  const handleInboundTypeChange = useCallback(
    (type: string) => {
      setModalInboundType(type);
      setSourceKeyword("");
      setPurchaseOrders([]);
      setShipments([]);
      setItems([]);
      // 선택 품목은 유지 (여러 유형 혼합 가능)
      setSourcePage(1);
      setSourceTotalCount(0);
      loadSourceData(type, undefined, 1);
    },
    [loadSourceData]
  );

  // 발주 품목 추가
  const addPurchaseOrder = (po: PurchaseOrderSource) => {
    const key = `po-${po.id}`;
    if (selectedItems.some((s) => s.key === key)) return;
    setSelectedItems((prev) => [
      ...prev,
      {
        key,
        inbound_type: modalInboundType,
        reference_number: po.purchase_no,
        supplier_code: po.supplier_code,
        supplier_name: po.supplier_name,
        item_number: po.item_code,
        item_name: po.item_name,
        spec: po.spec || "",
        material: po.material || "",
        unit: "EA",
        inbound_qty: po.remain_qty,
        unit_price: po.unit_price,
        total_amount: po.remain_qty * po.unit_price,
        source_table: po.source_table || "purchase_order_mng",
        source_id: po.id,
      },
    ]);
  };

  // 출하 품목 추가
  const addShipment = (sh: ShipmentSource) => {
    const key = `sh-${sh.detail_id}`;
    if (selectedItems.some((s) => s.key === key)) return;
    setSelectedItems((prev) => [
      ...prev,
      {
        key,
        inbound_type: modalInboundType,
        reference_number: sh.instruction_no,
        supplier_code: "",
        supplier_name: sh.partner_id,
        item_number: sh.item_code,
        item_name: sh.item_name,
        spec: sh.spec || "",
        material: sh.material || "",
        unit: "EA",
        inbound_qty: sh.ship_qty,
        unit_price: 0,
        total_amount: 0,
        source_table: "shipment_instruction_detail",
        source_id: String(sh.detail_id),
      },
    ]);
  };

  // 품목 추가 (현재 선택된 입고유형 사용)
  const addItem = (item: ItemSource) => {
    const key = `item-${item.id}-${modalInboundType}`;
    if (selectedItems.some((s) => s.key === key)) return;
    setSelectedItems((prev) => [
      ...prev,
      {
        key,
        inbound_type: modalInboundType,
        reference_number: item.item_number,
        supplier_code: "",
        supplier_name: "",
        item_number: item.item_number,
        item_name: item.item_name,
        spec: item.spec || "",
        material: item.material || "",
        unit: item.inventory_unit || "EA",
        inbound_qty: 0,
        unit_price: item.standard_price,
        total_amount: 0,
        source_table: "item_info",
        source_id: item.id,
      },
    ]);
  };

  // 선택 품목 수량 변경
  const updateItemQty = (key: string, qty: number) => {
    setSelectedItems((prev) =>
      prev.map((item) =>
        item.key === key
          ? { ...item, inbound_qty: qty, total_amount: qty * item.unit_price }
          : item
      )
    );
  };

  // 선택 품목 단가 변경
  const updateItemPrice = (key: string, price: number) => {
    setSelectedItems((prev) =>
      prev.map((item) =>
        item.key === key
          ? { ...item, unit_price: price, total_amount: item.inbound_qty * price }
          : item
      )
    );
  };

  // 선택 품목 삭제
  const removeItem = (key: string) => {
    setSelectedItems((prev) => prev.filter((item) => item.key !== key));
  };

  // 저장
  const handleSave = async () => {
    if (selectedItems.length === 0) {
      alert("입고할 품목을 선택해주세요.");
      return;
    }
    if (!modalInboundDate) {
      alert("입고일을 입력해주세요.");
      return;
    }

    const zeroQtyItems = selectedItems.filter((i) => !i.inbound_qty || i.inbound_qty <= 0);
    if (zeroQtyItems.length > 0) {
      alert("입고수량이 0인 품목이 있습니다. 수량을 입력해주세요.");
      return;
    }

    if (!modalWarehouse) {
      toast.error("창고를 선택해주세요.");
      return;
    }
    setSaving(true);
    try {
      if (editMode) {
        // 기존 item 수정 + 삭제된 item 삭제 + 새 item 추가
        const currentKeys = new Set(selectedItems.map((i) => i.key));
        const toDelete = editItemIds.filter((id) => !currentKeys.has(id));
        const toUpdate = selectedItems.filter((i) => editItemIds.includes(i.key));
        const toCreate = selectedItems.filter((i) => !editItemIds.includes(i.key));

        await Promise.all([
          ...toDelete.map((id) => deleteReceiving(id)),
          ...toUpdate.map((item) =>
            updateReceiving(item.header_id || item.key, {
              inbound_date: modalInboundDate,
              inbound_qty: item.inbound_qty,
              unit_price: item.unit_price,
              total_amount: item.total_amount,
              warehouse_code: modalWarehouse || undefined,
              location_code: modalLocation || undefined,
              memo: modalMemo || undefined,
              detail_id: item.detail_id,
            } as any)
          ),
          ...(toCreate.length > 0
            ? [createReceiving({
                inbound_number: modalInboundNo,
                inbound_date: modalInboundDate,
                warehouse_code: modalWarehouse,
                location_code: modalLocation || undefined,
                inspector: modalInspector || undefined,
                manager: modalManager || undefined,
                memo: modalMemo || undefined,
                items: toCreate.map((item) => ({
                  inbound_type: item.inbound_type,
                  reference_number: item.reference_number,
                  supplier_code: item.supplier_code,
                  supplier_name: item.supplier_name,
                  item_number: item.item_number,
                  item_name: item.item_name,
                  spec: item.spec,
                  material: item.material,
                  unit: item.unit,
                  inbound_qty: item.inbound_qty,
                  unit_price: item.unit_price,
                  total_amount: item.total_amount,
                  source_table: item.source_table,
                  source_id: item.source_id,
                  inbound_status: "입고완료",
                  inspection_status: "대기",
                })),
              })]
            : []),
        ]);
        toast.success("입고 정보를 수정했어요");
        setIsModalOpen(false);
        fetchList();
      } else {
        const res = await createReceiving({
          inbound_number: modalInboundNo,
          inbound_date: modalInboundDate,
          warehouse_code: modalWarehouse,
          location_code: modalLocation || undefined,
          inspector: modalInspector || undefined,
          manager: modalManager || undefined,
          memo: modalMemo || undefined,
          items: selectedItems.map((item) => ({
            inbound_type: item.inbound_type,
            reference_number: item.reference_number,
            supplier_code: item.supplier_code,
            supplier_name: item.supplier_name,
            item_number: item.item_number,
            item_name: item.item_name,
            spec: item.spec,
            material: item.material,
            unit: item.unit,
            inbound_qty: item.inbound_qty,
            unit_price: item.unit_price,
            total_amount: item.total_amount,
            source_table: item.source_table,
            source_id: item.source_id,
            inbound_status: "입고완료",
            inspection_status: "대기",
          })),
        });

        if (res.success) {
          toast.success(res.message || "입고 등록 완료");
          setIsModalOpen(false);
          fetchList();
        }
      }
    } catch (err: any) {
      const msg = err?.response?.data?.message || (editMode ? "수정에 실패했어요" : "입고 등록 중 오류가 발생했습니다.");
      toast.error(msg);
    } finally {
      setSaving(false);
    }
  };

  // 합계 계산
  const totalSummary = useMemo(() => {
    return {
      count: selectedItems.length,
      qty: selectedItems.reduce((sum, i) => sum + (i.inbound_qty || 0), 0),
      amount: selectedItems.reduce((sum, i) => sum + (i.total_amount || 0), 0),
    };
  }, [selectedItems]);

  return (
    <div className="flex h-full flex-col gap-3 p-3">
      {/* 브레드크럼 */}
      <div className="flex items-center gap-1.5 text-xs text-muted-foreground shrink-0">
        <span>물류관리</span>
        <span className="text-muted-foreground/50">/</span>
        <span className="text-foreground font-medium">입고관리</span>
      </div>

      {/* 검색 영역 */}
      <DynamicSearchFilter
        tableName="inbound_mng"
        filterId="c16-receiving"
        onFilterChange={setSearchFilters}
        externalFilterConfig={ts.filterConfig}
        dataCount={data.length}
        extraActions={
          <div className="flex items-center gap-2">
            <Button size="sm" onClick={openRegisterModal} className="h-9">
              <Plus className="mr-1 h-4 w-4" />
              입고 등록
            </Button>
            <div className="h-4 w-px bg-border" />
            <Button
              size="sm"
              variant="outline"
              onClick={handleDelete}
              disabled={checkedIds.length === 0}
              className="h-9 text-destructive border-destructive/20 bg-destructive/5 hover:bg-destructive/10"
            >
              <Trash2 className="mr-1 h-4 w-4" />
              삭제 ({checkedIds.length})
            </Button>
          </div>
        }
      />

      {/* 입고 목록 테이블 (플랫 리스트) */}
      <div className="flex-1 overflow-hidden rounded-lg border border-border bg-card flex flex-col">
        <div className="flex items-center justify-between border-b bg-muted/50 px-4 py-2.5 shrink-0">
          <div className="flex items-center gap-2">
            <h3 className="text-[13px] font-bold">입고 목록</h3>
            <span className="text-[11px] font-semibold text-primary bg-primary/10 border border-primary/15 px-2 py-0.5 rounded-full font-mono">
              {filteredRows.length}건
            </span>
          </div>
          <Button variant="ghost" size="sm" onClick={() => ts.setOpen(true)} title="테이블 설정">
            <Settings2 className="h-4 w-4" />
          </Button>
        </div>

        <div className="flex-1 overflow-auto">
          <Table noWrapper style={{ minWidth: "1500px" }}>
            <colgroup>
              <col style={{ width: "40px" }} />
              <col style={{ width: "140px" }} />
              <col style={{ width: "100px" }} />
              <col style={{ width: "100px" }} />
              <col style={{ width: "120px" }} />
              <col style={{ width: "90px" }} />
              <col style={{ width: "110px" }} />
              <col style={{ width: "100px" }} />
              <col style={{ width: "140px" }} />
              <col style={{ width: "90px" }} />
              <col style={{ width: "80px" }} />
              <col style={{ width: "80px" }} />
              <col style={{ width: "100px" }} />
              <col style={{ width: "100px" }} />
              <col style={{ width: "90px" }} />
              <col style={{ width: "120px" }} />
            </colgroup>
            <TableHeader className="sticky top-0 z-10">
              <TableRow className="bg-muted hover:bg-muted">
                <TableHead
                  className="text-center cursor-pointer"
                  onClick={() => {
                    const allFilteredIds = filteredRows.map((r) => r.id);
                    const allChecked = allFilteredIds.length > 0 && allFilteredIds.every((id) => checkedIds.includes(id));
                    setCheckedIds(allChecked ? [] : allFilteredIds);
                  }}
                >
                  <Checkbox
                    checked={(() => {
                      const allFilteredIds = filteredRows.map((r) => r.id);
                      return allFilteredIds.length > 0 && allFilteredIds.every((id) => checkedIds.includes(id));
                    })()}
                    onCheckedChange={() => {}}
                  />
                </TableHead>
                {GRID_COLUMNS.map((col) => {
                  const isRight = ["inbound_qty", "unit_price", "total_amount"].includes(col.key);
                  return (
                    <TableHead key={col.key} className={cn("text-[11px] font-bold uppercase tracking-wide text-muted-foreground select-none", isRight && "text-right")}>
                      <div className={cn("inline-flex items-center gap-1", isRight && "justify-end w-full")}>
                        <div className="flex items-center gap-1 cursor-pointer min-w-0" onClick={() => handleSort(col.key)}>
                          <span className="truncate">{col.label}</span>
                          {sortState?.key === col.key && (
                            sortState.direction === "asc"
                              ? <ArrowUp className="h-3 w-3 text-primary shrink-0" />
                              : <ArrowDown className="h-3 w-3 text-primary shrink-0" />
                          )}
                        </div>
                        {(columnUniqueValues[col.key] || []).length > 0 && (
                          <HeaderFilterPopover
                            colKey={col.key} colLabel={col.label}
                            uniqueValues={columnUniqueValues[col.key] || []}
                            filterValues={headerFilters[col.key] || new Set<string>()}
                            onToggle={toggleHeaderFilter} onClear={clearHeaderFilter}
                          />
                        )}
                      </div>
                    </TableHead>
                  );
                })}
              </TableRow>
            </TableHeader>
            <TableBody>
              {loading ? (
                <TableRow>
                  <TableCell colSpan={TOTAL_COLS} className="py-16 text-center">
                    <Loader2 className="mx-auto h-6 w-6 animate-spin text-primary" />
                  </TableCell>
                </TableRow>
              ) : filteredRows.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={TOTAL_COLS} className="py-16 text-center">
                    <div className="flex flex-col items-center gap-2 text-muted-foreground">
                      <Inbox className="h-8 w-8 opacity-30" />
                      <span className="text-sm">등록된 입고 내역이 없어요</span>
                    </div>
                  </TableCell>
                </TableRow>
              ) : (
                paginatedRows.map((row, idx) => {
                  const isChecked = checkedIds.includes(row.id);
                  return (
                    <TableRow
                      key={`${row.id}-${idx}`}
                      className={cn(
                        "cursor-pointer border-l-[3px] border-l-transparent transition-all",
                        isChecked ? "border-l-primary bg-primary/5" : "hover:bg-accent/50"
                      )}
                      onClick={() => {
                        setCheckedIds((prev) =>
                          prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
                        );
                      }}
                      onDoubleClick={() => openEditModal(row as any)}
                    >
                      <TableCell
                        className="text-center cursor-pointer"
                        onClick={(e) => {
                          e.stopPropagation();
                          setCheckedIds((prev) =>
                            prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
                          );
                        }}
                      >
                        <Checkbox checked={isChecked} onCheckedChange={() => {}} />
                      </TableCell>
                      <TableCell className="font-mono whitespace-nowrap text-[13px]">{row.inbound_number || ""}</TableCell>
                      <TableCell className="text-[13px]">
                        <Badge variant={getTypeVariant(row.inbound_type)} className="text-[11px]">
                          {row.inbound_type || "-"}
                        </Badge>
                      </TableCell>
                      <TableCell className="whitespace-nowrap text-[13px]">
                        {row.inbound_date ? new Date(row.inbound_date).toLocaleDateString("ko-KR") : ""}
                      </TableCell>
                      <TableCell className="text-[13px] truncate max-w-[120px]"><span className="block truncate">{row.reference_number || ""}</span></TableCell>
                      <TableCell className="text-[13px]">{row.source_type || ""}</TableCell>
                      <TableCell className="text-[13px] truncate max-w-[110px]"><span className="block truncate">{row.supplier_name || ""}</span></TableCell>
                      <TableCell className="font-mono text-[13px]">{row.item_number || ""}</TableCell>
                      <TableCell className="text-[13px] max-w-[140px]"><span className="block truncate" title={row.item_name || ""}>{row.item_name || ""}</span></TableCell>
                      <TableCell className="text-[13px] text-muted-foreground">{row.spec || ""}</TableCell>
                      <TableCell className="text-right font-mono text-[13px]">{row.inbound_qty ? Number(row.inbound_qty).toLocaleString() : ""}</TableCell>
                      <TableCell className="text-right font-mono text-[13px]">{row.unit_price ? Number(row.unit_price).toLocaleString() : ""}</TableCell>
                      <TableCell className="text-right font-mono text-[13px] font-semibold">{row.total_amount ? Number(row.total_amount).toLocaleString() : ""}</TableCell>
                      <TableCell className="text-[13px] truncate max-w-[100px]"><span className="block truncate">{row.warehouse_name || (row as any).warehouse_code || ""}</span></TableCell>
                      <TableCell className="text-[13px]">
                        <Badge variant={getStatusVariant(row.inbound_status)} className="text-[11px]">
                          {row.inbound_status || "-"}
                        </Badge>
                      </TableCell>
                      <TableCell className="text-muted-foreground"><span className="block truncate max-w-[120px]">{row.remark || row.memo || ""}</span></TableCell>
                    </TableRow>
                  );
                })
              )}
            </TableBody>
          </Table>
        </div>

        {/* 페이지네이션 */}
        <div className="flex items-center justify-between border-t px-4 py-2.5 text-xs text-muted-foreground shrink-0">
          <div className="flex items-center gap-3">
            <div className="flex items-center gap-1">
              <span>전체</span>
              <span className="font-medium text-foreground">{filteredRows.length.toLocaleString()}</span>
              <span>건</span>
            </div>
            <div className="flex items-center gap-1.5">
              <Input
                type="number"
                min={1}
                value={pageSizeInput}
                onChange={(e) => setPageSizeInput(e.target.value)}
                onBlur={applyPageSize}
                onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); applyPageSize(); } }}
                className="h-7 w-16 text-center text-xs"
              />
              <span>건씩 보기</span>
            </div>
          </div>
          <div className="flex items-center gap-0.5">
            <button onClick={() => setCurrentPage(1)} disabled={safePage === 1}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
              <ChevronsLeft className="h-3.5 w-3.5" />
            </button>
            <button onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} disabled={safePage === 1}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
              <ChevronLeft className="h-3.5 w-3.5" />
            </button>
            {getPageNumbers().map((page, idx) =>
              page === "..." ? (
                <span key={`dot-${idx}`} className="h-7 w-7 flex items-center justify-center text-muted-foreground">...</span>
              ) : (
                <button key={page} onClick={() => setCurrentPage(page as number)}
                  className={cn("h-7 w-7 flex items-center justify-center rounded text-xs",
                    page === safePage ? "bg-primary text-primary-foreground font-medium" : "hover:bg-muted")}>
                  {page}
                </button>
              )
            )}
            <button onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} disabled={safePage === totalPages}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
              <ChevronRight className="h-3.5 w-3.5" />
            </button>
            <button onClick={() => setCurrentPage(totalPages)} disabled={safePage === totalPages}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
              <ChevronsRight className="h-3.5 w-3.5" />
            </button>
          </div>
          <div className="flex items-center gap-1.5">
            <Input
              type="number"
              min={1}
              max={totalPages}
              placeholder={String(safePage)}
              className="h-7 w-14 text-center text-xs"
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  const val = parseInt((e.target as HTMLInputElement).value, 10);
                  if (!isNaN(val) && val >= 1 && val <= totalPages) {
                    setCurrentPage(val);
                    (e.target as HTMLInputElement).value = "";
                    (e.target as HTMLInputElement).blur();
                  }
                }
              }}
              onBlur={(e) => {
                const val = parseInt(e.target.value, 10);
                if (!isNaN(val) && val >= 1 && val <= totalPages) {
                  setCurrentPage(val);
                }
                e.target.value = "";
              }}
            />
            <span>/ {totalPages} 페이지</span>
          </div>
        </div>
      </div>

      {/* 입고 등록 모달 */}
      <Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
        <DialogContent className="sm:max-w-[1600px] w-[95vw] h-[90vh] p-0 flex flex-col overflow-hidden">
          <DialogHeader className="shrink-0 px-6 pt-4 pb-2 border-b">
            <DialogTitle>{editMode ? "입고 수정" : "입고 등록"}</DialogTitle>
            <DialogDescription>
              {editMode ? "입고 정보를 수정해 주세요." : "입고유형을 선택하고, 좌측에서 근거 데이터를 검색하여 추가해 주세요."}
            </DialogDescription>
          </DialogHeader>
          <div className="flex-1 overflow-hidden flex flex-col">

          {/* 입고유형 선택 */}
          <div className="flex items-center gap-4 border-b bg-muted/30 px-6 py-2.5">
            <Label className="text-[11px] font-semibold text-muted-foreground uppercase tracking-wide">입고유형</Label>
            <Select value={modalInboundType} onValueChange={handleInboundTypeChange}>
              <SelectTrigger className="h-9 w-[160px] text-sm">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {INBOUND_TYPES.map((t) => (
                  <SelectItem key={t.value} value={t.value}>
                    {t.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <span className="text-muted-foreground ml-auto text-xs italic">
              {modalInboundType === "구매입고"
                ? "발주 데이터에서 입고 처리합니다."
                : modalInboundType === "반품입고"
                  ? "출하 데이터에서 반품 입고 처리합니다."
                  : "품목 데이터를 직접 선택하여 입고 처리합니다."}
            </span>
          </div>

          {/* 메인 콘텐츠: 좌측 소스 데이터 / 우측 선택 품목 */}
          <div className="flex-1 overflow-hidden">
            <ResizablePanelGroup direction="horizontal">
              {/* 좌측: 근거 데이터 검색 */}
              <ResizablePanel defaultSize={60} minSize={35}>
                <div className="flex h-full flex-col">
                  {/* 소스 검색 바 */}
                  <div className="flex items-center gap-2 border-b px-4 py-2.5">
                    <Input
                      placeholder={
                        modalInboundType === "구매입고"
                          ? "발주번호 / 품목명 / 공급처"
                          : modalInboundType === "반품입고"
                            ? "출하번호 / 품목명"
                            : "품목번호 / 품목명"
                      }
                      value={sourceKeyword}
                      onChange={(e) => setSourceKeyword(e.target.value)}
                      onKeyDown={(e) => e.key === "Enter" && searchSourceData()}
                      className="h-9 flex-1 text-xs"
                    />
                    <Button size="sm" onClick={searchSourceData} className="h-9">
                      <Search className="mr-1 h-3 w-3" />
                      검색
                    </Button>
                  </div>

                  {/* 소스 데이터 테이블 */}
                  <div className="flex-1 overflow-auto">
                    <div className="flex items-center gap-2 px-4 py-2.5 bg-muted/50 border-b">
                      <h4 className="text-[13px] font-bold">
                        {modalInboundType === "구매입고"
                          ? "미입고 발주 목록"
                          : modalInboundType === "반품입고"
                            ? "출하 목록"
                            : "품목 목록"}
                      </h4>
                      <span className="text-[11px] font-semibold text-primary bg-primary/10 border border-primary/15 px-2 py-0.5 rounded-full font-mono">
                        {sourceTotalCount}건
                      </span>
                    </div>

                    {sourceLoading ? (
                      <div className="flex h-40 items-center justify-center">
                        <Loader2 className="h-5 w-5 animate-spin" />
                      </div>
                    ) : modalInboundType === "구매입고" ? (
                      <SourcePurchaseOrderTable
                        data={purchaseOrders}
                        onAdd={addPurchaseOrder}
                        selectedKeys={selectedItems.map((s) => s.key)}
                      />
                    ) : modalInboundType === "반품입고" ? (
                      <SourceShipmentTable
                        data={shipments}
                        onAdd={addShipment}
                        selectedKeys={selectedItems.map((s) => s.key)}
                      />
                    ) : (
                      <SourceItemTable
                        data={items}
                        onAdd={addItem}
                        selectedKeys={selectedItems.map((s) => s.key)}
                        resolveCat={resolveCat}
                      />
                    )}
                  </div>

                  {/* 페이징 */}
                  {sourceTotalCount > 0 && (
                    <div className="flex shrink-0 items-center justify-between border-t bg-muted/30 px-4 py-2">
                      <div className="flex items-center gap-2">
                        <span className="text-muted-foreground text-[11px]">표시:</span>
                        <Input
                          type="number"
                          min={1}
                          max={500}
                          value={sourcePageSize}
                          onChange={(e) => {
                            const v = parseInt(e.target.value, 10);
                            if (v > 0) {
                              setSourcePageSize(v);
                              setSourcePage(1);
                              loadSourceData(modalInboundType, sourceKeyword || undefined, 1);
                            }
                          }}
                          className="h-7 w-[60px] text-center text-[11px]"
                        />
                        <span className="text-muted-foreground text-[11px]">
                          총 {sourceTotalCount}건
                        </span>
                      </div>
                      <div className="flex items-center gap-1">
                        <Button variant="outline" size="icon" className="h-7 w-7" disabled={sourcePage <= 1}
                          onClick={() => { setSourcePage(1); loadSourceData(modalInboundType, sourceKeyword || undefined, 1); }}>
                          <ChevronsLeft className="h-3.5 w-3.5" />
                        </Button>
                        <Button variant="outline" size="icon" className="h-7 w-7" disabled={sourcePage <= 1}
                          onClick={() => { const p = sourcePage - 1; setSourcePage(p); loadSourceData(modalInboundType, sourceKeyword || undefined, p); }}>
                          <ChevronLeft className="h-3.5 w-3.5" />
                        </Button>
                        <span className="px-2 text-xs font-medium">{sourcePage} / {Math.max(1, Math.ceil(sourceTotalCount / sourcePageSize))}</span>
                        <Button variant="outline" size="icon" className="h-7 w-7" disabled={sourcePage >= Math.ceil(sourceTotalCount / sourcePageSize)}
                          onClick={() => { const p = sourcePage + 1; setSourcePage(p); loadSourceData(modalInboundType, sourceKeyword || undefined, p); }}>
                          <ChevronRight className="h-3.5 w-3.5" />
                        </Button>
                        <Button variant="outline" size="icon" className="h-7 w-7" disabled={sourcePage >= Math.ceil(sourceTotalCount / sourcePageSize)}
                          onClick={() => { const p = Math.ceil(sourceTotalCount / sourcePageSize); setSourcePage(p); loadSourceData(modalInboundType, sourceKeyword || undefined, p); }}>
                          <ChevronsRight className="h-3.5 w-3.5" />
                        </Button>
                      </div>
                    </div>
                  )}
                </div>
              </ResizablePanel>

              <ResizableHandle withHandle onPointerDown={(e) => e.stopPropagation()} />

              {/* 우측: 입고 정보 + 선택 품목 */}
              <ResizablePanel defaultSize={40} minSize={25}>
                <div className="flex h-full flex-col">
                  {/* 입고 정보 입력 */}
                  <div className="space-y-3 border-b bg-muted/30 px-4 py-3">
                    <h4 className="text-[13px] font-bold text-foreground">입고 정보</h4>
                    <div className="grid grid-cols-2 gap-3">
                      <div>
                        <Label className="text-[11px] font-semibold text-muted-foreground">입고번호</Label>
                        <Input
                          value={modalInboundNo}
                          readOnly
                          className="bg-muted h-9 text-xs"
                        />
                      </div>
                      <div>
                        <Label className="text-[11px] font-semibold text-muted-foreground">
                          입고일 <span className="text-destructive">*</span>
                        </Label>
                        <Input
                          type="date"
                          value={modalInboundDate}
                          onChange={(e) => setModalInboundDate(e.target.value)}
                          className="h-9 text-xs"
                        />
                      </div>
                      <div>
                        <Label className="text-[11px] font-semibold text-muted-foreground">창고</Label>
                        <Select value={modalWarehouse} onValueChange={setModalWarehouse}>
                          <SelectTrigger className="h-9 text-xs">
                            <SelectValue placeholder="창고 선택" />
                          </SelectTrigger>
                          <SelectContent>
                            {warehouses.map((w) => (
                              <SelectItem key={w.warehouse_code} value={w.warehouse_code}>
                                {w.warehouse_name}
                              </SelectItem>
                            ))}
                          </SelectContent>
                        </Select>
                      </div>
                      <div>
                        <Label className="text-[11px] font-semibold text-muted-foreground">위치</Label>
                        <Input
                          value={modalLocation}
                          onChange={(e) => setModalLocation(e.target.value)}
                          placeholder="위치 입력"
                          className="h-9 text-xs"
                        />
                      </div>
                      <div>
                        <Label className="text-[11px] font-semibold text-muted-foreground">검수자</Label>
                        <Input
                          value={modalInspector}
                          onChange={(e) => setModalInspector(e.target.value)}
                          placeholder="검수자"
                          className="h-9 text-xs"
                        />
                      </div>
                      <div>
                        <Label className="text-[11px] font-semibold text-muted-foreground">담당자</Label>
                        <Input
                          value={modalManager}
                          onChange={(e) => setModalManager(e.target.value)}
                          placeholder="담당자"
                          className="h-9 text-xs"
                        />
                      </div>
                      <div className="col-span-2">
                        <Label className="text-[11px] font-semibold text-muted-foreground">메모</Label>
                        <Input
                          value={modalMemo}
                          onChange={(e) => setModalMemo(e.target.value)}
                          placeholder="메모"
                          className="h-9 text-xs"
                        />
                      </div>
                    </div>
                  </div>

                  {/* 선택된 품목 테이블 */}
                  <div className="flex-1 overflow-auto">
                    <div className="flex items-center gap-2 border-b bg-muted/50 px-4 py-2.5">
                      <h4 className="text-[13px] font-bold">입고 처리 품목</h4>
                      <span className="text-[11px] font-semibold text-primary bg-primary/10 border border-primary/15 px-2 py-0.5 rounded-full font-mono">
                        {selectedItems.length}건
                      </span>
                    </div>

                    {selectedItems.length === 0 ? (
                      <div className="flex h-32 flex-col items-center justify-center gap-1.5 text-muted-foreground border-2 border-dashed rounded-lg m-4">
                        <Inbox className="h-8 w-8 opacity-30" />
                        <p className="text-xs font-medium">좌측에서 품목을 선택하여 추가해 주세요</p>
                      </div>
                    ) : (
                      <Table>
                        <TableHeader className="sticky top-0 z-10">
                          <TableRow className="bg-muted hover:bg-muted">
                            <TableHead className="w-[30px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">No</TableHead>
                            <TableHead className="w-[70px] 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="p-2 text-[11px] font-bold uppercase tracking-wide text-muted-foreground">참조번호</TableHead>
                            <TableHead className="w-[80px] p-2 text-right">
                              수량
                            </TableHead>
                            <TableHead className="w-[80px] p-2 text-right">
                              단가
                            </TableHead>
                            <TableHead className="w-[90px] p-2 text-right">
                              금액
                            </TableHead>
                            <TableHead className="w-[30px] p-2" />
                          </TableRow>
                        </TableHeader>
                        <TableBody>
                          {selectedItems.map((item, idx) => (
                            <TableRow key={item.key} className="text-xs">
                              <TableCell className="p-2 text-center">
                                {idx + 1}
                              </TableCell>
                              <TableCell className="p-2">
                                <Badge variant="outline" className="text-[10px]">{item.inbound_type || modalInboundType}</Badge>
                              </TableCell>
                              <TableCell className="max-w-[180px] p-2">
                                <div className="flex flex-col">
                                  <span className="truncate font-medium" title={item.item_name}>
                                    {item.item_name}
                                  </span>
                                  <span className="text-muted-foreground truncate text-[10px]" title={`${item.item_number}${item.spec ? ` | ${item.spec}` : ""}`}>
                                    {item.item_number}
                                    {item.spec ? ` | ${item.spec}` : ""}
                                  </span>
                                </div>
                              </TableCell>
                              <TableCell className="p-2 text-[11px]">
                                {item.reference_number}
                              </TableCell>
                              <TableCell className="p-2 text-right">
                                <Input
                                  type="number"
                                  value={item.inbound_qty || ""}
                                  onChange={(e) =>
                                    updateItemQty(
                                      item.key,
                                      Number(e.target.value) || 0
                                    )
                                  }
                                  className="h-7 w-[70px] text-right text-xs"
                                  min={0}
                                />
                              </TableCell>
                              <TableCell className="p-2 text-right">
                                <Input
                                  type="number"
                                  value={item.unit_price || ""}
                                  onChange={(e) =>
                                    updateItemPrice(
                                      item.key,
                                      Number(e.target.value) || 0
                                    )
                                  }
                                  className="h-7 w-[70px] text-right text-xs"
                                  min={0}
                                />
                              </TableCell>
                              <TableCell className="p-2 text-right text-[13px] font-semibold">
                                {item.total_amount.toLocaleString()}
                              </TableCell>
                              <TableCell className="p-2 text-center">
                                <Button
                                  variant="ghost"
                                  size="icon"
                                  className="h-6 w-6"
                                  onClick={() => removeItem(item.key)}
                                >
                                  <X className="h-3 w-3" />
                                </Button>
                              </TableCell>
                            </TableRow>
                          ))}
                        </TableBody>
                      </Table>
                    )}
                  </div>
                </div>
              </ResizablePanel>
            </ResizablePanelGroup>
          </div>

          </div>
          <DialogFooter className="shrink-0 border-t px-0 py-0">
            <div className="flex w-full items-center justify-between px-6 py-2.5">
              <div className="text-muted-foreground text-xs">
                {selectedItems.length > 0 ? (
                  <span className="flex items-center gap-3">
                    <span className="font-semibold text-foreground">{totalSummary.count}건</span>
                    <span>수량 합계: <span className="font-medium text-foreground">{totalSummary.qty.toLocaleString()}</span></span>
                    <span>금액 합계: <span className="font-medium text-foreground">{totalSummary.amount.toLocaleString()}원</span></span>
                  </span>
                ) : (
                  "품목을 추가해 주세요"
                )}
              </div>
              <div className="flex gap-2">
                <Button
                  variant="outline"
                  onClick={() => setIsModalOpen(false)}
                  className="h-9 text-sm"
                >
                  취소
                </Button>
                <Button
                  onClick={handleSave}
                  disabled={saving || selectedItems.length === 0}
                  className="h-9 text-sm"
                >
                  {saving ? (
                    <Loader2 className="mr-1 h-4 w-4 animate-spin" />
                  ) : (
                    <Save className="mr-1 h-4 w-4" />
                  )}
                  저장
                </Button>
              </div>
            </div>
          </DialogFooter>
        </DialogContent>
      </Dialog>

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

// --- 소스 데이터 테이블 컴포넌트들 ---

function SourcePurchaseOrderTable({
  data,
  onAdd,
  selectedKeys,
}: {
  data: PurchaseOrderSource[];
  onAdd: (po: PurchaseOrderSource) => void;
  selectedKeys: string[];
}) {
  if (data.length === 0) {
    return (
      <div className="flex h-32 flex-col items-center justify-center gap-1.5 text-muted-foreground border-2 border-dashed rounded-lg m-4">
        <Inbox className="h-8 w-8 opacity-30" />
        <p className="text-xs font-medium">검색 버튼을 눌러 발주 데이터를 조회해 주세요</p>
      </div>
    );
  }

  return (
    <Table>
      <TableHeader className="sticky top-0 z-10">
        <TableRow className="bg-muted hover:bg-muted">
          <TableHead className="w-[40px] p-2" />
          <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="p-2 text-[11px] font-bold uppercase tracking-wide text-muted-foreground">품목</TableHead>
          <TableHead className="w-[70px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">발주수량</TableHead>
          <TableHead className="w-[70px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">입고수량</TableHead>
          <TableHead className="w-[70px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">미입고</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        {data.map((po, idx) => {
          const isSelected = selectedKeys.includes(`po-${po.id}`);
          return (
            <TableRow
              key={`${po.source_table || 'po'}-${po.id}-${idx}`}
              className={cn(
                "cursor-pointer text-xs transition-colors",
                isSelected && "bg-primary/5"
              )}
              onClick={() => !isSelected && onAdd(po)}
            >
              <TableCell className="p-2 text-center">
                {isSelected ? (
                  <Badge className="bg-primary/20 text-primary text-[10px]">
                    추가됨
                  </Badge>
                ) : (
                  <ChevronRight className="text-muted-foreground h-4 w-4" />
                )}
              </TableCell>
              <TableCell className="max-w-[120px] truncate p-2 font-medium" title={po.purchase_no}>{po.purchase_no}</TableCell>
              <TableCell className="max-w-[120px] truncate p-2" title={po.supplier_name}>{po.supplier_name}</TableCell>
              <TableCell className="max-w-[200px] p-2">
                <div className="flex flex-col">
                  <span className="truncate font-medium" title={po.item_name}>{po.item_name}</span>
                  <span className="text-muted-foreground truncate text-[10px]" title={`${po.item_code}${po.spec ? ` | ${po.spec}` : ""}`}>
                    {po.item_code}
                    {po.spec ? ` | ${po.spec}` : ""}
                  </span>
                </div>
              </TableCell>
              <TableCell className="p-2 text-right">
                {Number(po.order_qty).toLocaleString()}
              </TableCell>
              <TableCell className="p-2 text-right">
                {Number(po.received_qty).toLocaleString()}
              </TableCell>
              <TableCell className="p-2 text-right font-semibold text-primary">
                {Number(po.remain_qty).toLocaleString()}
              </TableCell>
            </TableRow>
          );
        })}
      </TableBody>
    </Table>
  );
}

function SourceShipmentTable({
  data,
  onAdd,
  selectedKeys,
}: {
  data: ShipmentSource[];
  onAdd: (sh: ShipmentSource) => void;
  selectedKeys: string[];
}) {
  if (data.length === 0) {
    return (
      <div className="flex h-32 flex-col items-center justify-center gap-1.5 text-muted-foreground border-2 border-dashed rounded-lg m-4">
        <Inbox className="h-8 w-8 opacity-30" />
        <p className="text-xs font-medium">검색 버튼을 눌러 출하 데이터를 조회해 주세요</p>
      </div>
    );
  }

  return (
    <Table>
      <TableHeader className="sticky top-0 z-10">
        <TableRow className="bg-muted hover:bg-muted">
          <TableHead className="w-[40px] p-2" />
          <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="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-[70px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">출하수량</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        {data.map((sh) => {
          const isSelected = selectedKeys.includes(`sh-${sh.detail_id}`);
          return (
            <TableRow
              key={sh.detail_id}
              className={cn(
                "cursor-pointer text-xs transition-colors",
                isSelected && "bg-primary/5"
              )}
              onClick={() => !isSelected && onAdd(sh)}
            >
              <TableCell className="p-2 text-center">
                {isSelected ? (
                  <Badge className="bg-primary/20 text-primary text-[10px]">
                    추가됨
                  </Badge>
                ) : (
                  <ChevronRight className="text-muted-foreground h-4 w-4" />
                )}
              </TableCell>
              <TableCell className="max-w-[130px] truncate p-2 font-medium" title={sh.instruction_no}>{sh.instruction_no}</TableCell>
              <TableCell className="p-2">
                {sh.instruction_date
                  ? new Date(sh.instruction_date).toLocaleDateString("ko-KR")
                  : "-"}
              </TableCell>
              <TableCell className="max-w-[100px] truncate p-2" title={sh.partner_id}>{sh.partner_id}</TableCell>
              <TableCell className="max-w-[200px] p-2">
                <div className="flex flex-col">
                  <span className="truncate font-medium" title={sh.item_name}>{sh.item_name}</span>
                  <span className="text-muted-foreground truncate text-[10px]" title={`${sh.item_code}${sh.spec ? ` | ${sh.spec}` : ""}`}>
                    {sh.item_code}
                    {sh.spec ? ` | ${sh.spec}` : ""}
                  </span>
                </div>
              </TableCell>
              <TableCell className="p-2 text-right font-semibold">
                {Number(sh.ship_qty).toLocaleString()}
              </TableCell>
            </TableRow>
          );
        })}
      </TableBody>
    </Table>
  );
}

function SourceItemTable({
  data,
  onAdd,
  selectedKeys,
  resolveCat,
}: {
  data: ItemSource[];
  onAdd: (item: ItemSource) => void;
  selectedKeys: string[];
  resolveCat: (col: string, code: string) => string;
}) {
  if (data.length === 0) {
    return (
      <div className="flex h-32 flex-col items-center justify-center gap-1.5 text-muted-foreground border-2 border-dashed rounded-lg m-4">
        <Inbox className="h-8 w-8 opacity-30" />
        <p className="text-xs font-medium">검색 버튼을 눌러 품목 데이터를 조회해 주세요</p>
      </div>
    );
  }

  return (
    <Table>
      <TableHeader className="sticky top-0 z-10">
        <TableRow className="bg-muted hover:bg-muted">
          <TableHead className="w-[40px] p-2" />
          <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-[80px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">재질</TableHead>
          <TableHead className="w-[60px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">단위</TableHead>
          <TableHead className="w-[80px] text-right text-[11px] font-bold uppercase tracking-wide text-muted-foreground">기준가</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        {data.map((item) => {
          const isSelected = selectedKeys.includes(`item-${item.id}`);
          return (
            <TableRow
              key={item.id}
              className={cn(
                "cursor-pointer text-xs transition-colors",
                isSelected && "bg-primary/5"
              )}
              onClick={() => !isSelected && onAdd(item)}
            >
              <TableCell className="p-2 text-center">
                {isSelected ? (
                  <Badge className="bg-primary/20 text-primary text-[10px]">
                    추가됨
                  </Badge>
                ) : (
                  <ChevronRight className="text-muted-foreground h-4 w-4" />
                )}
              </TableCell>
              <TableCell className="max-w-[250px] p-2">
                <div className="flex flex-col">
                  <span className="truncate font-medium" title={item.item_name}>{item.item_name}</span>
                  <span className="text-muted-foreground truncate text-[10px]" title={item.item_number}>
                    {item.item_number}
                  </span>
                </div>
              </TableCell>
              <TableCell className="max-w-[100px] truncate p-2" title={item.spec || "-"}>{item.spec || "-"}</TableCell>
              <TableCell className="max-w-[100px] truncate p-2" title={resolveCat("material", item.material) || "-"}>{resolveCat("material", item.material) || "-"}</TableCell>
              <TableCell className="p-2">{resolveCat("inventory_unit", item.unit) || "-"}</TableCell>
              <TableCell className="p-2 text-right">
                {Number(item.standard_price).toLocaleString()}
              </TableCell>
            </TableRow>
          );
        })}
      </TableBody>
    </Table>
  );
}
