"use client";

/**
 * 창고정보관리 — 하드코딩 페이지 (Type B 마스터-디테일)
 *
 * 좌측: 창고 목록 (warehouse_info)
 * 우측: 선택 창고의 로케이션 목록 (warehouse_location)
 *
 * ★ 하위 위치가 있으면 창고 삭제 불가
 */

import React, { useState, useEffect, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
  Plus,
  Trash2,
  Loader2,
  Download,
  MapPin,
  Building2,
  Settings2,
  Layers,
  Info,
  Eye,
} 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 { useTableSettings } from "@/hooks/useTableSettings";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";
import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable";
import { exportToExcel } from "@/lib/utils/excelExport";
import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule";

const WAREHOUSE_TABLE = "warehouse_info";

const WAREHOUSE_COLUMNS = [
  { key: "warehouse_code", label: "창고코드" },
  { key: "warehouse_name", label: "창고명" },
  { key: "warehouse_type", label: "유형" },
  { key: "manager_name", label: "관리자" },
  { key: "status", label: "상태" },
];
const LOCATION_TABLE = "warehouse_location";

const getStatusVariant = (
  status: string
): "default" | "secondary" | "outline" | "destructive" => {
  switch (status) {
    case "사용":
    case "사용중":
      return "default";
    case "미사용":
      return "secondary";
    case "폐쇄":
      return "destructive";
    default:
      return "outline";
  }
};

const getTypeVariant = (
  type: string
): "default" | "secondary" | "outline" => {
  switch (type) {
    case "원자재":
    case "일반":
      return "default";
    case "완제품":
    case "보관":
      return "secondary";
    default:
      return "outline";
  }
};

export default function WarehouseManagementPage() {
  const { user } = useAuth();
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();
  const ts = useTableSettings("c16-warehouse", WAREHOUSE_TABLE, WAREHOUSE_COLUMNS);

  // 좌측: 창고 목록
  const [warehouses, setWarehouses] = useState<any[]>([]);
  const [warehouseLoading, setWarehouseLoading] = useState(false);
  const [warehouseCount, setWarehouseCount] = useState(0);
  const [selectedWarehouseId, setSelectedWarehouseId] = useState<string | null>(null);

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

  // 우측: 로케이션 목록
  const [locations, setLocations] = useState<any[]>([]);
  const [locationLoading, setLocationLoading] = useState(false);
  const [locationCheckedIds, setLocationCheckedIds] = useState<string[]>([]);

  // 모달: 창고 등록/수정
  const [warehouseModalOpen, setWarehouseModalOpen] = useState(false);
  const [warehouseEditMode, setWarehouseEditMode] = useState(false);
  const [warehouseForm, setWarehouseForm] = useState<Record<string, any>>({});
  const [warehouseSaving, setWarehouseSaving] = useState(false);

  // 모달: 위치 등록/수정
  const [locationModalOpen, setLocationModalOpen] = useState(false);
  const [locationEditMode, setLocationEditMode] = useState(false);
  const [locationForm, setLocationForm] = useState<Record<string, any>>({});
  const [locationSaving, setLocationSaving] = useState(false);

  // 위치코드 자동 채번
  const [locNumberingRuleId, setLocNumberingRuleId] = useState<string | null>(null);
  const [locPreviewCode, setLocPreviewCode] = useState<string | null>(null);
  const [whNumberingRuleId, setWhNumberingRuleId] = useState<string | null>(null);
  const [whPreviewCode, setWhPreviewCode] = useState<string | null>(null);

  // 모달: 랙 구조 일괄 등록
  const [rackModalOpen, setRackModalOpen] = useState(false);
  const [rackFloor, setRackFloor] = useState("");
  const [rackZone, setRackZone] = useState("");
  const [rackConditions, setRackConditions] = useState<
    { id: string; startRow: number; endRow: number; levels: number }[]
  >([]);
  const [rackLocationType, setRackLocationType] = useState("");
  const [rackStatus, setRackStatus] = useState("");
  const [rackPreview, setRackPreview] = useState<any[]>([]);
  const [rackSaving, setRackSaving] = useState(false);
  // 위치명 접미사 (자동 조립: {zone}{구역접미사}-{row}{열접미사}-{level}{단접미사})
  const [rackZoneLabel, setRackZoneLabel] = useState("구역");
  const [rackRowLabel, setRackRowLabel] = useState("열");
  const [rackLevelLabel, setRackLevelLabel] = useState("단");

  // 카테고리 옵션
  const [categoryOptions, setCategoryOptions] = useState<
    Record<string, { code: string; label: string }[]>
  >({});
  const [locationCategoryOptions, setLocationCategoryOptions] = useState<
    Record<string, { code: string; label: string }[]>
  >({});

  // 카테고리 로드
  useEffect(() => {
    const load = async () => {
      const flatten = (vals: any[]): { code: string; label: string }[] => {
        const result: { code: string; label: string }[] = [];
        for (const v of vals) {
          result.push({ code: v.valueCode, label: v.valueLabel });
          if (v.children?.length) result.push(...flatten(v.children));
        }
        return result;
      };

      const whOpts: Record<string, { code: string; label: string }[]> = {};
      for (const col of ["warehouse_type", "status"]) {
        try {
          const res = await apiClient.get(
            `/table-categories/${WAREHOUSE_TABLE}/${col}/values`
          );
          if (res.data?.success) whOpts[col] = flatten(res.data.data || []);
        } catch {
          /* skip */
        }
      }
      setCategoryOptions(whOpts);

      const locOpts: Record<string, { code: string; label: string }[]> = {};
      for (const col of ["location_type", "status", "floor", "zone"]) {
        try {
          const res = await apiClient.get(
            `/table-categories/${LOCATION_TABLE}/${col}/values`
          );
          if (res.data?.success) locOpts[col] = flatten(res.data.data || []);
        } catch {
          /* skip */
        }
      }
      setLocationCategoryOptions(locOpts);
    };
    load();
  }, []);

  // 카테고리 코드→라벨 변환 헬퍼
  const resolveCategory = useCallback(
    (
      optMap: Record<string, { code: string; label: string }[]>,
      col: string,
      code: string
    ) => {
      if (!code) return "";
      return optMap[col]?.find((o) => o.code === code)?.label || code;
    },
    []
  );

  // 창고 목록 조회
  const fetchWarehouses = useCallback(async () => {
    setWarehouseLoading(true);
    try {
      const filters = searchFilters.map((f) => ({ columnName: f.columnName, operator: f.operator, value: f.value }));
      const res = await apiClient.post(
        `/table-management/tables/${WAREHOUSE_TABLE}/data`,
        {
          page: 1,
          size: 0,
          dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
          autoFilter: true,
          sort: { columnName: "warehouse_code", order: "asc" },
        }
      );
      const raw = res.data?.data?.data || res.data?.data?.rows || [];
      const data = raw.map((r: any) => ({
        ...r,
        _warehouse_type_code: r.warehouse_type,
        _status_code: r.status,
        warehouse_type: resolveCategory(categoryOptions, "warehouse_type", r.warehouse_type),
        status: resolveCategory(categoryOptions, "status", r.status),
      }));
      setWarehouses(data);
      setWarehouseCount(res.data?.data?.total || raw.length);
    } catch {
      toast.error("창고 목록을 불러오지 못했어요");
    } finally {
      setWarehouseLoading(false);
    }
  }, [categoryOptions, resolveCategory, searchFilters]);

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

  // 선택된 창고
  const selectedWarehouse = warehouses.find((w) => w.id === selectedWarehouseId);

  // 로케이션 조회
  const fetchLocations = useCallback(async () => {
    if (!selectedWarehouse?.warehouse_code) {
      setLocations([]);
      return;
    }
    setLocationLoading(true);
    try {
      const res = await apiClient.post(
        `/table-management/tables/${LOCATION_TABLE}/data`,
        {
          page: 1,
          size: 0,
          dataFilter: {
            enabled: true,
            filters: [
              {
                columnName: "warehouse_code",
                operator: "equals",
                value: selectedWarehouse.warehouse_code,
              },
            ],
          },
          autoFilter: true,
          sort: { columnName: "location_code", order: "asc" },
        }
      );
      const raw = res.data?.data?.data || res.data?.data?.rows || [];
      const data = raw.map((r: any) => ({
        ...r,
        location_type: resolveCategory(locationCategoryOptions, "location_type", r.location_type),
        status: resolveCategory(locationCategoryOptions, "status", r.status),
      }));
      setLocations(data);
    } catch {
      toast.error("위치 목록을 불러오지 못했어요");
    } finally {
      setLocationLoading(false);
    }
  }, [selectedWarehouse?.warehouse_code, locationCategoryOptions, resolveCategory]);

  useEffect(() => {
    setLocationCheckedIds([]);
    fetchLocations();
  }, [fetchLocations]);

  // 체크박스 헬퍼
  const allLocationChecked =
    locations.length > 0 && locationCheckedIds.length === locations.length;
  const someLocationChecked =
    locationCheckedIds.length > 0 && locationCheckedIds.length < locations.length;

  const toggleAllLocations = (checked: boolean) => {
    setLocationCheckedIds(checked ? locations.map((l) => l.id) : []);
  };

  const toggleLocation = (id: string, checked: boolean) => {
    setLocationCheckedIds((prev) =>
      checked ? [...prev, id] : prev.filter((i) => i !== id)
    );
  };

  // ─── 창고 CRUD ───

  const openWarehouseCreateModal = async () => {
    setWarehouseEditMode(false);
    setWarehouseForm({});
    setWhNumberingRuleId(null);
    setWhPreviewCode(null);
    setWarehouseModalOpen(true);
    try {
      const ruleRes = await apiClient.get(`/numbering-rules/by-column/warehouse_info/warehouse_code`);
      const ruleData = ruleRes.data;
      if (ruleData?.success && ruleData?.data?.ruleId) {
        const ruleId = ruleData.data.ruleId;
        setWhNumberingRuleId(ruleId);
        const previewRes = await previewNumberingCode(ruleId);
        if (previewRes.success && previewRes.data?.generatedCode) {
          setWhPreviewCode(previewRes.data.generatedCode);
        }
      }
    } catch { /* 채번 규칙 없으면 무시 */ }
  };

  const openWarehouseEditModal = (row: any) => {
    setWarehouseEditMode(true);
    setWarehouseForm({
      ...row,
      warehouse_type: row._warehouse_type_code ?? row.warehouse_type ?? "",
      status: row._status_code ?? row.status ?? "",
    });
    setWarehouseModalOpen(true);
  };

  const handleWarehouseSave = async () => {
    if (!whNumberingRuleId && !warehouseForm.warehouse_code?.trim()) {
      toast.error("창고코드를 입력해주세요");
      return;
    }
    if (!warehouseForm.warehouse_name?.trim()) {
      toast.error("창고명을 입력해주세요");
      return;
    }
    setWarehouseSaving(true);
    try {
      let finalWarehouseCode = warehouseForm.warehouse_code?.trim() || "";
      if (!warehouseEditMode && whNumberingRuleId) {
        const allocRes = await allocateNumberingCode(whNumberingRuleId);
        if (allocRes.success && allocRes.data?.generatedCode) {
          finalWarehouseCode = allocRes.data.generatedCode;
        } else {
          toast.error("채번 코드 할당에 실패했습니다.");
          setWarehouseSaving(false);
          return;
        }
      }
      const fields = {
        warehouse_code: finalWarehouseCode,
        warehouse_name: warehouseForm.warehouse_name?.trim(),
        warehouse_type: warehouseForm.warehouse_type || "",
        manager_name: warehouseForm.manager_name || "",
        contact: warehouseForm.contact || "",
        status: warehouseForm.status || "",
        memo: warehouseForm.memo || "",
      };

      // 신규 등록 시 창고코드 중복 체크
      if (!warehouseEditMode) {
        const dup = warehouses.find(w => w.warehouse_code === fields.warehouse_code);
        if (dup) {
          toast.error(`창고코드 "${fields.warehouse_code}"가 이미 존재해요`);
          setWarehouseSaving(false);
          return;
        }
      }

      if (warehouseEditMode && warehouseForm.id) {
        await apiClient.put(
          `/table-management/tables/${WAREHOUSE_TABLE}/edit`,
          {
            originalData: { id: warehouseForm.id },
            updatedData: fields,
          }
        );
        toast.success("창고 정보가 수정되었어요");
      } else {
        await apiClient.post(
          `/table-management/tables/${WAREHOUSE_TABLE}/add`,
          { id: crypto.randomUUID(), ...fields }
        );
        toast.success("창고가 등록되었어요");
      }
      setWarehouseModalOpen(false);
      fetchWarehouses();
    } catch {
      toast.error(warehouseEditMode ? "창고 수정에 실패했어요" : "창고 등록에 실패했어요");
    } finally {
      setWarehouseSaving(false);
    }
  };

  const handleWarehouseDelete = async () => {
    if (!selectedWarehouse) return;
    if (locations.length > 0) {
      toast.error("하위 위치가 있어 삭제할 수 없어요. 위치를 먼저 삭제해주세요.");
      return;
    }
    const ok = await confirm(
      `"${selectedWarehouse.warehouse_name}" 창고를 삭제할까요?`
    );
    if (!ok) return;
    try {
      await apiClient.delete(
        `/table-management/tables/${WAREHOUSE_TABLE}/delete`,
        { data: [{ id: selectedWarehouse.id }] }
      );
      toast.success("창고가 삭제되었어요");
      setSelectedWarehouseId(null);
      fetchWarehouses();
    } catch {
      toast.error("창고 삭제에 실패했어요");
    }
  };

  // ─── 위치 CRUD ───

  const openLocationCreateModal = async () => {
    setLocationEditMode(false);
    setLocationForm({ warehouse_code: selectedWarehouse?.warehouse_code || "" });
    setLocNumberingRuleId(null);
    setLocPreviewCode(null);
    setLocationModalOpen(true);
    try {
      const ruleRes = await apiClient.get(`/numbering-rules/by-column/warehouse_location/location_code`);
      const ruleData = ruleRes.data;
      if (ruleData?.success && ruleData?.data?.ruleId) {
        const ruleId = ruleData.data.ruleId;
        setLocNumberingRuleId(ruleId);
        const previewRes = await previewNumberingCode(ruleId);
        if (previewRes.success && previewRes.data?.generatedCode) {
          setLocPreviewCode(previewRes.data.generatedCode);
        }
      }
    } catch { /* 채번 규칙 없으면 무시 */ }
  };

  const openLocationEditModal = (row: any) => {
    setLocationEditMode(true);
    setLocationForm({ ...row });
    setLocationModalOpen(true);
  };

  const handleLocationSave = async () => {
    if (!locNumberingRuleId && !locationForm.location_code?.trim()) {
      toast.error("위치코드를 입력해주세요");
      return;
    }
    if (!locationForm.location_name?.trim()) {
      toast.error("위치명을 입력해주세요");
      return;
    }
    setLocationSaving(true);
    try {
      let finalLocationCode = locationForm.location_code?.trim() || "";
      if (!locationEditMode && locNumberingRuleId) {
        const allocRes = await allocateNumberingCode(locNumberingRuleId);
        if (allocRes.success && allocRes.data?.generatedCode) {
          finalLocationCode = allocRes.data.generatedCode;
        } else {
          toast.error("채번 코드 할당에 실패했습니다.");
          setLocationSaving(false);
          return;
        }
      }

      const fields = {
        warehouse_code: locationForm.warehouse_code || selectedWarehouse?.warehouse_code || "",
        location_code: finalLocationCode,
        location_name: locationForm.location_name?.trim(),
        floor: locationForm.floor || "",
        zone: locationForm.zone || "",
        row_num: locationForm.row_num || "",
        level_num: locationForm.level_num || "",
        location_type: locationForm.location_type || "",
        status: locationForm.status || "",
      };

      if (locationEditMode && locationForm.id) {
        await apiClient.put(
          `/table-management/tables/${LOCATION_TABLE}/edit`,
          {
            originalData: { id: locationForm.id },
            updatedData: fields,
          }
        );
        toast.success("위치 정보가 수정되었어요");
      } else {
        await apiClient.post(
          `/table-management/tables/${LOCATION_TABLE}/add`,
          { id: crypto.randomUUID(), ...fields }
        );
        toast.success("위치가 등록되었어요");
      }
      setLocationModalOpen(false);
      fetchLocations();
    } catch {
      toast.error(locationEditMode ? "위치 수정에 실패했어요" : "위치 등록에 실패했어요");
    } finally {
      setLocationSaving(false);
    }
  };

  const handleLocationDelete = async () => {
    if (locationCheckedIds.length === 0) {
      toast.error("삭제할 위치를 선택해주세요");
      return;
    }
    const ok = await confirm(`${locationCheckedIds.length}건의 위치를 삭제할까요?`);
    if (!ok) return;
    try {
      for (const id of locationCheckedIds) {
        await apiClient.delete(
          `/table-management/tables/${LOCATION_TABLE}/delete`,
          { data: [{ id }] }
        );
      }
      toast.success(`${locationCheckedIds.length}건의 위치가 삭제되었어요`);
      setLocationCheckedIds([]);
      fetchLocations();
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "위치 삭제에 실패했어요");
    }
  };

  // ─── 랙 구조 일괄 등록 ───

  const openRackModal = () => {
    setRackFloor("");
    setRackZone("");
    setRackConditions([]);
    setRackLocationType("");
    setRackStatus("");
    setRackPreview([]);
    setRackSaving(false);
    setRackModalOpen(true);
  };

  const addRackCondition = () => {
    const lastEnd = rackConditions.length > 0
      ? rackConditions[rackConditions.length - 1].endRow
      : 0;
    setRackConditions((prev) => [
      ...prev,
      { id: crypto.randomUUID(), startRow: lastEnd + 1, endRow: lastEnd + 1, levels: 1 },
    ]);
  };

  const updateRackCondition = (id: string, field: string, value: number) => {
    setRackConditions((prev) =>
      prev.map((c) => (c.id === id ? { ...c, [field]: value } : c))
    );
  };

  const removeRackCondition = (id: string) => {
    setRackConditions((prev) => prev.filter((c) => c.id !== id));
  };

  const generateRackPreview = () => {
    if (!rackFloor.trim() || !rackZone.trim()) {
      toast.error("층과 구역을 입력해주세요");
      return;
    }
    if (rackConditions.length === 0) {
      toast.error("조건을 1개 이상 추가해주세요");
      return;
    }
    // 조건 유효성 검사
    for (const cond of rackConditions) {
      if (cond.startRow < 1 || cond.endRow < 1 || cond.levels < 1) {
        toast.error("열 범위와 단 수는 1 이상이어야 합니다");
        return;
      }
      if (cond.endRow < cond.startRow) {
        toast.error("끝 열은 시작 열보다 크거나 같아야 합니다");
        return;
      }
    }

    const whCode = selectedWarehouse?.warehouse_code || "";
    // 카테고리 코드→라벨 변환 (셀렉트에서 코드가 저장되므로)
    const floorOpts = locationCategoryOptions["floor"] || [];
    const zoneOpts = locationCategoryOptions["zone"] || [];
    const floorLabel = floorOpts.find(o => o.code === rackFloor)?.label || rackFloor.trim();
    const zoneLabel = zoneOpts.find(o => o.code === rackZone)?.label || rackZone.trim();
    const floorCode = floorLabel.replace(/층$/, "");
    const zoneCode = zoneLabel.replace(/구역$/, "");

    // 기존 위치코드 Set (중복 체크용)
    const existingCodes = new Set(locations.map((l: any) => l.location_code));
    const seen = new Set<string>();
    const items: any[] = [];
    const duplicates: string[] = [];

    for (const cond of rackConditions) {
      for (let row = cond.startRow; row <= cond.endRow; row++) {
        for (let level = 1; level <= cond.levels; level++) {
          const rowStr = String(row).padStart(2, "0");
          const locationCode = `${whCode}-${floorCode}${zoneCode}-${rowStr}-${level}`;
          // 미리보기 내부 중복 제거
          if (seen.has(locationCode)) continue;
          seen.add(locationCode);
          // 기존 DB 데이터와 중복 체크
          if (existingCodes.has(locationCode)) {
            duplicates.push(locationCode);
            continue;
          }
          const locationName = `${zoneCode}${rackZoneLabel}-${rowStr}${rackRowLabel}-${level}${rackLevelLabel}`;
          items.push({
            location_code: locationCode,
            location_name: locationName,
            warehouse_code: whCode,
            floor: floorLabel,
            zone: zoneLabel,
            row_num: String(row),
            level_num: String(level),
            location_type: rackLocationType,
            status: rackStatus,
          });
        }
      }
    }
    if (duplicates.length > 0) {
      toast.error(`이미 등록된 위치 ${duplicates.length}건이 제외되었어요 (예: ${duplicates.slice(0, 3).join(", ")})`);
    }
    setRackPreview(items);
  };

  const handleRackBulkSave = async () => {
    if (rackPreview.length === 0) {
      toast.error("미리보기를 먼저 생성해주세요");
      return;
    }
    setRackSaving(true);
    try {
      let successCount = 0;
      for (const item of rackPreview) {
        await apiClient.post(
          `/table-management/tables/${LOCATION_TABLE}/add`,
          { id: crypto.randomUUID(), ...item }
        );
        successCount++;
      }
      toast.success(`${successCount}개의 위치가 등록되었어요`);
      setRackModalOpen(false);
      fetchLocations();
    } catch (err) {
      toast.error("일괄 등록 중 오류가 발생했어요");
    } finally {
      setRackSaving(false);
    }
  };

  // 랙 조건별 통계
  const getRackConditionCount = (cond: { startRow: number; endRow: number; levels: number }) => {
    if (cond.endRow < cond.startRow || cond.startRow < 1 || cond.levels < 1) return 0;
    return (cond.endRow - cond.startRow + 1) * cond.levels;
  };

  // 랙 미리보기 통계
  const rackStats = {
    totalLocations: rackPreview.length,
    totalRows: rackConditions.reduce((acc, c) => {
      if (c.endRow >= c.startRow && c.startRow >= 1) return acc + (c.endRow - c.startRow + 1);
      return acc;
    }, 0),
    maxLevels: rackConditions.reduce((acc, c) => Math.max(acc, c.levels || 0), 0),
  };

  // EDataTable 컬럼 정의
  const warehouseColumns: EDataTableColumn[] = ts.visibleColumns.map((col) => {
    const base: EDataTableColumn = { key: col.key, label: col.label };
    if (col.key === "warehouse_type") {
      return {
        ...base,
        render: (val: any) => (
          <Badge variant={getTypeVariant(val)} className="text-[10px]">
            {val}
          </Badge>
        ),
      };
    }
    if (col.key === "status") {
      return {
        ...base,
        render: (val: any) => (
          <Badge variant={getStatusVariant(val)} className="text-[10px]">
            {val}
          </Badge>
        ),
      };
    }
    return base;
  });

  // 엑셀 내보내기
  const handleExcelExport = () => {
    if (warehouses.length === 0) {
      toast.error("내보낼 데이터가 없어요");
      return;
    }
    exportToExcel(
      warehouses.map((r) => ({
        창고코드: r.warehouse_code,
        창고명: r.warehouse_name,
        유형: r.warehouse_type,
        관리자: r.manager_name,
        상태: r.status,
      })),
      "창고정보"
    );
  };

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

      {/* 검색 바 */}
      <DynamicSearchFilter
        tableName={WAREHOUSE_TABLE}
        filterId="c16-warehouse"
        onFilterChange={setSearchFilters}
        externalFilterConfig={ts.filterConfig}
        dataCount={warehouses.length}
        extraActions={
          <div className="flex items-center gap-2">
            <Button
              variant="outline"
              size="sm"
              className="h-8 gap-1 text-xs"
              onClick={handleExcelExport}
            >
              <Download className="h-3.5 w-3.5" />
              엑셀
            </Button>
            <Button variant="ghost" size="sm" className="h-8 px-2" onClick={() => ts.setOpen(true)} title="테이블 설정">
              <Settings2 className="h-3.5 w-3.5" />
            </Button>
          </div>
        }
      />

      {/* 마스터-디테일 패널 */}
      <ResizablePanelGroup
        direction="horizontal"
        className="flex-1 rounded-lg border bg-card"
      >
        {/* 좌측: 창고 목록 */}
        <ResizablePanel defaultSize={45} minSize={25}>
          <div className="flex flex-col h-full">
            <div className="flex items-center justify-between px-4 py-2.5 border-b bg-muted/50">
              <div className="flex items-center gap-2">
                <span className="text-[13px] font-bold">창고 목록</span>
                <Badge variant="default" className="rounded-full text-[11px]">
                  {warehouses.length}건
                </Badge>
              </div>
              <div className="flex items-center gap-1.5">
                <Button
                  size="sm"
                  className="h-7 gap-1 text-xs"
                  onClick={openWarehouseCreateModal}
                >
                  <Plus className="h-3.5 w-3.5" />
                  등록
                </Button>
                <Button
                  variant="outline"
                  size="sm"
                  className="h-7 gap-1 text-xs text-destructive hover:text-destructive"
                  onClick={handleWarehouseDelete}
                  disabled={!selectedWarehouse}
                >
                  <Trash2 className="h-3.5 w-3.5" />
                  삭제
                </Button>
              </div>
            </div>

            <EDataTable
              columns={warehouseColumns}
              data={ts.groupData(warehouses)}
              rowKey={(row) => row.id}
              loading={warehouseLoading}
              emptyMessage="등록된 창고가 없어요"
              selectedId={selectedWarehouseId}
              onSelect={(id) => setSelectedWarehouseId(id)}
              onRowDoubleClick={(row) => openWarehouseEditModal(row)}
              showRowNumber
              showPagination={false}
              draggableColumns={false}
              columnOrderKey="c16-warehouse"
            />
          </div>
        </ResizablePanel>

        <ResizableHandle withHandle />

        {/* 우측: 로케이션 */}
        <ResizablePanel defaultSize={55} minSize={30}>
          <div className="flex flex-col h-full">
            {!selectedWarehouse ? (
              <div className="flex flex-col items-center justify-center flex-1 m-5 border-2 border-dashed rounded-lg border-border">
                <Building2 className="h-12 w-12 text-muted-foreground/40 mb-4" />
                <p className="text-sm font-semibold text-muted-foreground">
                  창고를 선택해주세요
                </p>
                <p className="text-xs text-muted-foreground/70 mt-1">
                  좌측에서 창고를 선택하면 위치 정보가 표시돼요
                </p>
              </div>
            ) : (
              <>
                {/* 패널 헤더 */}
                <div className="flex items-center justify-between px-4 py-2.5 border-b bg-muted/50">
                  <div className="flex items-center gap-2">
                    <MapPin className="h-4 w-4 text-muted-foreground" />
                    <span className="text-[13px] font-bold">
                      {selectedWarehouse.warehouse_name}
                    </span>
                    <Badge
                      variant="outline"
                      className="rounded-full text-[11px] font-mono"
                    >
                      {selectedWarehouse.warehouse_code}
                    </Badge>
                    <Badge variant="secondary" className="rounded-full text-[10px]">
                      {locations.length}개 위치
                    </Badge>
                  </div>
                  <div className="flex items-center gap-1.5">
                    <Button
                      size="sm"
                      className="h-7 gap-1 text-xs"
                      onClick={openRackModal}
                    >
                      <Layers className="h-3.5 w-3.5" />
                      랙 구조 등록
                    </Button>
                    <Button
                      variant="outline"
                      size="sm"
                      className="h-7 gap-1 text-xs text-destructive hover:text-destructive"
                      onClick={handleLocationDelete}
                      disabled={locationCheckedIds.length === 0}
                    >
                      <Trash2 className="h-3.5 w-3.5" />
                      삭제
                    </Button>
                  </div>
                </div>

                {/* 로케이션 테이블 */}
                <div className="flex-1 overflow-auto">
                  {locationLoading ? (
                    <div className="flex items-center justify-center h-32">
                      <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
                    </div>
                  ) : locations.length === 0 ? (
                    <div className="flex items-center justify-center h-32 text-sm text-muted-foreground">
                      등록된 위치가 없어요
                    </div>
                  ) : (
                    <Table>
                      <TableHeader className="sticky top-0 z-10">
                        <TableRow className="bg-muted hover:bg-muted">
                          <TableHead className="w-10 text-center">
                            <Checkbox
                              checked={
                                someLocationChecked
                                  ? "indeterminate"
                                  : allLocationChecked
                              }
                              onCheckedChange={(v) =>
                                toggleAllLocations(v === true)
                              }
                              aria-label="전체 선택"
                            />
                          </TableHead>
                          <TableHead className="w-8 text-center text-[11px] font-bold uppercase tracking-wide text-muted-foreground">#</TableHead>
                          <TableHead className="w-[110px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">위치코드</TableHead>
                          <TableHead className="text-[11px] font-bold uppercase tracking-wide text-muted-foreground">위치명</TableHead>
                          <TableHead className="w-[50px] text-center text-[11px] font-bold uppercase tracking-wide text-muted-foreground">층</TableHead>
                          <TableHead className="w-[70px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">구역</TableHead>
                          <TableHead className="w-[50px] text-center text-[11px] font-bold uppercase tracking-wide text-muted-foreground">열</TableHead>
                          <TableHead className="w-[50px] text-center 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-[70px] text-[11px] font-bold uppercase tracking-wide text-muted-foreground">상태</TableHead>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {locations.map((loc, idx) => (
                          <TableRow
                            key={loc.id}
                            className={cn(
                              "cursor-pointer text-xs",
                              locationCheckedIds.includes(loc.id) && "bg-primary/5"
                            )}
                            onDoubleClick={() => openLocationEditModal(loc)}
                          >
                            <TableCell className="text-center">
                              <Checkbox
                                checked={locationCheckedIds.includes(loc.id)}
                                onCheckedChange={(v) =>
                                  toggleLocation(loc.id, v === true)
                                }
                                aria-label="행 선택"
                              />
                            </TableCell>
                            <TableCell className="text-center text-muted-foreground">
                              {idx + 1}
                            </TableCell>
                            <TableCell className="font-mono truncate max-w-[110px]">
                              {loc.location_code}
                            </TableCell>
                            <TableCell className="truncate max-w-[120px]">
                              {loc.location_name}
                            </TableCell>
                            <TableCell className="text-center">{loc.floor}</TableCell>
                            <TableCell>{loc.zone}</TableCell>
                            <TableCell className="text-center">{loc.row_num}</TableCell>
                            <TableCell className="text-center">{loc.level_num}</TableCell>
                            <TableCell>
                              <Badge
                                variant={getTypeVariant(loc.location_type)}
                                className="text-[10px]"
                              >
                                {loc.location_type}
                              </Badge>
                            </TableCell>
                            <TableCell>
                              <Badge
                                variant={getStatusVariant(loc.status)}
                                className="text-[10px]"
                              >
                                {loc.status}
                              </Badge>
                            </TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  )}
                </div>
              </>
            )}
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>

      {/* 창고 등록/수정 Dialog */}
      <Dialog open={warehouseModalOpen} onOpenChange={setWarehouseModalOpen}>
        <DialogContent className="max-w-xl">
          <DialogHeader>
            <DialogTitle>
              {warehouseEditMode ? "창고 수정" : "창고 등록"}
            </DialogTitle>
            <DialogDescription>
              {warehouseEditMode
                ? "창고 정보를 수정해주세요"
                : "새로운 창고를 등록해주세요"}
            </DialogDescription>
          </DialogHeader>

          <div className="grid grid-cols-2 gap-4 py-2">
            {/* 창고코드 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">
                창고코드 <span className="text-destructive">*</span>
              </Label>
              <Input
                value={warehouseEditMode ? (warehouseForm.warehouse_code || "") : (whPreviewCode || "")}
                onChange={(e) =>
                  setWarehouseForm((prev) => ({ ...prev, warehouse_code: e.target.value }))
                }
                placeholder={warehouseEditMode ? "" : (whNumberingRuleId ? "채번 조회 중..." : "자동 생성돼요")}
                disabled={warehouseEditMode}
                readOnly={!warehouseEditMode && !!whNumberingRuleId}
              />
            </div>
            {/* 창고명 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">
                창고명 <span className="text-destructive">*</span>
              </Label>
              <Input
                value={warehouseForm.warehouse_name || ""}
                onChange={(e) =>
                  setWarehouseForm((prev) => ({ ...prev, warehouse_name: e.target.value }))
                }
                placeholder="창고명을 입력해주세요"
              />
            </div>
            {/* 유형 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">유형</Label>
              <Select
                value={warehouseForm.warehouse_type || ""}
                onValueChange={(v) =>
                  setWarehouseForm((prev) => ({ ...prev, warehouse_type: v }))
                }
              >
                <SelectTrigger>
                  <SelectValue placeholder="유형 선택" />
                </SelectTrigger>
                <SelectContent>
                  {(categoryOptions["warehouse_type"] || []).map((o) => (
                    <SelectItem key={o.code} value={o.code}>
                      {o.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            {/* 관리자 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">관리자</Label>
              <Input
                value={warehouseForm.manager_name || ""}
                onChange={(e) =>
                  setWarehouseForm((prev) => ({ ...prev, manager_name: e.target.value }))
                }
                placeholder="관리자를 입력해주세요"
              />
            </div>
            {/* 상태 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">상태</Label>
              <Select
                value={warehouseForm.status || ""}
                onValueChange={(v) =>
                  setWarehouseForm((prev) => ({ ...prev, status: v }))
                }
              >
                <SelectTrigger>
                  <SelectValue placeholder="상태 선택" />
                </SelectTrigger>
                <SelectContent>
                  {(categoryOptions["status"] || []).map((o) => (
                    <SelectItem key={o.code} value={o.code}>
                      {o.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            {/* 연락처 (전체 너비) */}
            <div className="grid gap-1.5 col-span-2">
              <Label className="text-[11px] font-semibold text-muted-foreground">연락처</Label>
              <Input
                value={warehouseForm.contact || ""}
                onChange={(e) =>
                  setWarehouseForm((prev) => ({ ...prev, contact: e.target.value }))
                }
                placeholder="연락처를 입력해주세요"
              />
            </div>
            {/* 비고 (전체 너비) */}
            <div className="grid gap-1.5 col-span-2">
              <Label className="text-[11px] font-semibold text-muted-foreground">비고</Label>
              <Input
                value={warehouseForm.memo || ""}
                onChange={(e) =>
                  setWarehouseForm((prev) => ({ ...prev, memo: e.target.value }))
                }
                placeholder="비고를 입력해주세요"
              />
            </div>
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setWarehouseModalOpen(false)}>
              취소
            </Button>
            <Button onClick={handleWarehouseSave} disabled={warehouseSaving}>
              {warehouseSaving && (
                <Loader2 className="h-4 w-4 animate-spin mr-1" />
              )}
              {warehouseEditMode ? "수정하기" : "등록하기"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 위치 등록/수정 Dialog */}
      <Dialog open={locationModalOpen} onOpenChange={setLocationModalOpen}>
        <DialogContent className="max-w-xl">
          <DialogHeader>
            <DialogTitle>
              {locationEditMode ? "위치 수정" : "위치 등록"}
            </DialogTitle>
            <DialogDescription>
              {locationEditMode
                ? "위치 정보를 수정해주세요"
                : `${selectedWarehouse?.warehouse_name || ""} 창고에 새 위치를 등록해주세요`}
            </DialogDescription>
          </DialogHeader>

          <div className="grid grid-cols-2 gap-4 py-2">
            {/* 창고코드 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">창고코드</Label>
              <Input value={locationForm.warehouse_code || ""} disabled />
            </div>
            {/* 위치코드 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">
                위치코드 <span className="text-destructive">*</span>
              </Label>
              <Input
                value={locationEditMode ? (locationForm.location_code || "") : (locPreviewCode || "")}
                onChange={(e) =>
                  setLocationForm((prev) => ({ ...prev, location_code: e.target.value }))
                }
                placeholder={locationEditMode ? "" : (locNumberingRuleId ? "채번 조회 중..." : "자동 생성돼요")}
                disabled={locationEditMode}
                readOnly={!locationEditMode && !!locNumberingRuleId}
              />
            </div>
            {/* 위치명 */}
            <div className="grid gap-1.5 col-span-2">
              <Label className="text-[11px] font-semibold text-muted-foreground">
                위치명 <span className="text-destructive">*</span>
              </Label>
              <Input
                value={locationForm.location_name || ""}
                onChange={(e) =>
                  setLocationForm((prev) => ({ ...prev, location_name: e.target.value }))
                }
                placeholder="위치명을 입력해주세요"
              />
            </div>
            {/* 층 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">층</Label>
              <Input
                value={locationForm.floor || ""}
                onChange={(e) =>
                  setLocationForm((prev) => ({ ...prev, floor: e.target.value }))
                }
                placeholder="층을 입력해주세요"
              />
            </div>
            {/* 구역 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">구역</Label>
              <Input
                value={locationForm.zone || ""}
                onChange={(e) =>
                  setLocationForm((prev) => ({ ...prev, zone: e.target.value }))
                }
                placeholder="구역을 입력해주세요"
              />
            </div>
            {/* 열 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">열</Label>
              <Input
                value={locationForm.row_num || ""}
                onChange={(e) =>
                  setLocationForm((prev) => ({ ...prev, row_num: e.target.value }))
                }
                placeholder="열을 입력해주세요"
              />
            </div>
            {/* 단 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">단</Label>
              <Input
                value={locationForm.level_num || ""}
                onChange={(e) =>
                  setLocationForm((prev) => ({ ...prev, level_num: e.target.value }))
                }
                placeholder="단을 입력해주세요"
              />
            </div>
            {/* 위치유형 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">위치유형</Label>
              <Select
                value={locationForm.location_type || ""}
                onValueChange={(v) =>
                  setLocationForm((prev) => ({ ...prev, location_type: v }))
                }
              >
                <SelectTrigger>
                  <SelectValue placeholder="위치유형 선택" />
                </SelectTrigger>
                <SelectContent>
                  {(locationCategoryOptions["location_type"] || []).map((o) => (
                    <SelectItem key={o.code} value={o.code}>
                      {o.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            {/* 상태 */}
            <div className="grid gap-1.5">
              <Label className="text-[11px] font-semibold text-muted-foreground">상태</Label>
              <Select
                value={locationForm.status || ""}
                onValueChange={(v) =>
                  setLocationForm((prev) => ({ ...prev, status: v }))
                }
              >
                <SelectTrigger>
                  <SelectValue placeholder="상태 선택" />
                </SelectTrigger>
                <SelectContent>
                  {(locationCategoryOptions["status"] || []).map((o) => (
                    <SelectItem key={o.code} value={o.code}>
                      {o.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setLocationModalOpen(false)}>
              취소
            </Button>
            <Button onClick={handleLocationSave} disabled={locationSaving}>
              {locationSaving && (
                <Loader2 className="h-4 w-4 animate-spin mr-1" />
              )}
              {locationEditMode ? "수정하기" : "등록하기"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 랙 구조 일괄 등록 Dialog */}
      <Dialog open={rackModalOpen} onOpenChange={setRackModalOpen}>
        <DialogContent className="max-w-[95vw] sm:max-w-3xl p-0 !gap-0" style={{ maxHeight: "90vh", display: "flex", flexDirection: "column", overflow: "hidden" }}>
          <div className="px-6 pt-6 pb-3 shrink-0">
            <DialogTitle className="flex items-center gap-2">
              <Layers className="h-5 w-5" />
              랙 구조 일괄 등록
            </DialogTitle>
            <DialogDescription className="mt-1">
              {selectedWarehouse?.warehouse_name} ({selectedWarehouse?.warehouse_code}) 창고에 랙 구조를 일괄 등록합니다
            </DialogDescription>
          </div>

          <div className="flex-1 overflow-y-auto min-h-0">
            <div className="space-y-6 px-6 py-4">
              {/* 기본 정보 */}
              <div>
                <h3 className="text-sm font-bold mb-3 flex items-center gap-1.5">
                  📍 기본 정보
                </h3>
                <div className="grid grid-cols-3 gap-4">
                  <div className="grid gap-1.5">
                    <Label className="text-[11px] font-semibold text-muted-foreground">
                      창고 <span className="text-destructive">*</span>
                    </Label>
                    <Input
                      value={`${selectedWarehouse?.warehouse_name || ""} (${selectedWarehouse?.warehouse_code || ""})`}
                      disabled
                    />
                  </div>
                  <div className="grid gap-1.5">
                    <Label className="text-[11px] font-semibold text-muted-foreground">
                      층 <span className="text-destructive">*</span>
                    </Label>
                    {(locationCategoryOptions["floor"] || []).length > 0 ? (
                      <Select value={rackFloor} onValueChange={setRackFloor}>
                        <SelectTrigger>
                          <SelectValue placeholder="층 선택" />
                        </SelectTrigger>
                        <SelectContent>
                          {(locationCategoryOptions["floor"] || []).map((o) => (
                            <SelectItem key={o.code} value={o.code}>
                              {o.label}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    ) : (
                      <Input
                        value={rackFloor}
                        onChange={(e) => setRackFloor(e.target.value)}
                        placeholder="예: B1, 1F, 2F"
                      />
                    )}
                  </div>
                  <div className="grid gap-1.5">
                    <Label className="text-[11px] font-semibold text-muted-foreground">
                      구역 <span className="text-destructive">*</span>
                    </Label>
                    {(locationCategoryOptions["zone"] || []).length > 0 ? (
                      <Select value={rackZone} onValueChange={setRackZone}>
                        <SelectTrigger>
                          <SelectValue placeholder="구역 선택" />
                        </SelectTrigger>
                        <SelectContent>
                          {(locationCategoryOptions["zone"] || []).map((o) => (
                            <SelectItem key={o.code} value={o.code}>
                              {o.label}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    ) : (
                      <Input
                        value={rackZone}
                        onChange={(e) => setRackZone(e.target.value)}
                        placeholder="예: A, B, C"
                      />
                    )}
                  </div>
                </div>
              </div>

              {/* 랙 라인 구조 설정 */}
              <div>
                <h3 className="text-sm font-bold mb-3 flex items-center gap-1.5">
                  📊 랙 라인 구조 설정
                </h3>

                {/* 안내 박스 */}
                <div className="rounded-lg bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 p-3 mb-3">
                  <div className="flex items-start gap-2">
                    <Info className="h-4 w-4 text-blue-600 dark:text-blue-400 mt-0.5 shrink-0" />
                    <div className="text-xs text-blue-700 dark:text-blue-300 space-y-0.5">
                      <p>1. 조건 추가 버튼을 클릭하여 랙 라인 조건을 생성하세요</p>
                      <p>2. 각 조건마다 열 범위와 단 수를 입력하세요</p>
                      <p>3. 예시: 조건1(1~3열, 3단), 조건2(4~6열, 5단)</p>
                    </div>
                  </div>
                </div>

                <div className="flex items-center justify-between mb-3">
                  <span className="text-xs text-muted-foreground">
                    {rackConditions.length}개 조건
                  </span>
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-7 gap-1 text-xs"
                    onClick={addRackCondition}
                  >
                    <Plus className="h-3.5 w-3.5" />
                    조건 추가
                  </Button>
                </div>

                {rackConditions.length === 0 ? (
                  <div className="flex flex-col items-center justify-center py-8 border-2 border-dashed rounded-lg border-border">
                    <Layers className="h-8 w-8 text-muted-foreground/40 mb-2" />
                    <p className="text-sm text-muted-foreground mb-2">
                      조건을 추가하여 랙 구조를 설정하세요
                    </p>
                    <Button
                      variant="outline"
                      size="sm"
                      className="h-7 gap-1 text-xs"
                      onClick={addRackCondition}
                    >
                      <Plus className="h-3.5 w-3.5" />
                      첫 번째 조건 추가
                    </Button>
                  </div>
                ) : (
                  <div className="space-y-2">
                    {rackConditions.map((cond, idx) => (
                      <div
                        key={cond.id}
                        className="flex items-center gap-3 rounded-lg border p-3 bg-card"
                      >
                        <span className="text-xs font-bold text-muted-foreground w-10 shrink-0">
                          조건{idx + 1}
                        </span>
                        <div className="flex items-center gap-1.5 flex-1">
                          <Input
                            type="number"
                            min={1}
                            className="h-8 w-20 text-center text-xs"
                            value={cond.startRow || ""}
                            onChange={(e) =>
                              updateRackCondition(cond.id, "startRow", Number(e.target.value) || 0)
                            }
                            placeholder="시작"
                          />
                          <span className="text-xs text-muted-foreground">~</span>
                          <Input
                            type="number"
                            min={1}
                            className="h-8 w-20 text-center text-xs"
                            value={cond.endRow || ""}
                            onChange={(e) =>
                              updateRackCondition(cond.id, "endRow", Number(e.target.value) || 0)
                            }
                            placeholder="끝"
                          />
                          <span className="text-xs text-muted-foreground">열,</span>
                          <Input
                            type="number"
                            min={1}
                            className="h-8 w-16 text-center text-xs"
                            value={cond.levels || ""}
                            onChange={(e) =>
                              updateRackCondition(cond.id, "levels", Number(e.target.value) || 0)
                            }
                            placeholder="단"
                          />
                          <span className="text-xs text-muted-foreground">단</span>
                        </div>
                        {getRackConditionCount(cond) > 0 && (
                          <Badge variant="secondary" className="text-[10px] shrink-0">
                            {cond.startRow}열 ~ {cond.endRow}열 × {cond.levels}단 = {getRackConditionCount(cond)}개
                          </Badge>
                        )}
                        <Button
                          variant="ghost"
                          size="sm"
                          className="h-7 w-7 p-0 text-destructive hover:text-destructive shrink-0"
                          onClick={() => removeRackCondition(cond.id)}
                        >
                          <Trash2 className="h-3.5 w-3.5" />
                        </Button>
                      </div>
                    ))}
                  </div>
                )}
              </div>

              {/* 공통 설정 */}
              <div>
                <h3 className="text-sm font-bold mb-3 flex items-center gap-1.5">
                  ⚙️ 공통 설정
                </h3>
                <div className="grid grid-cols-2 gap-4">
                  <div className="grid gap-1.5">
                    <Label className="text-[11px] font-semibold text-muted-foreground">
                      위치 유형
                    </Label>
                    <Select value={rackLocationType} onValueChange={setRackLocationType}>
                      <SelectTrigger>
                        <SelectValue placeholder="위치유형 선택" />
                      </SelectTrigger>
                      <SelectContent>
                        {(locationCategoryOptions["location_type"] || []).map((o) => (
                          <SelectItem key={o.code} value={o.code}>
                            {o.label}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                  <div className="grid gap-1.5">
                    <Label className="text-[11px] font-semibold text-muted-foreground">
                      사용 여부
                    </Label>
                    <Select value={rackStatus} onValueChange={setRackStatus}>
                      <SelectTrigger>
                        <SelectValue placeholder="상태 선택" />
                      </SelectTrigger>
                      <SelectContent>
                        {(locationCategoryOptions["status"] || []).map((o) => (
                          <SelectItem key={o.code} value={o.code}>
                            {o.label}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                </div>
              </div>

              {/* 위치명 형식 — 구역/열/단 뒤에 붙일 표현만 자유 입력 */}
              <div className="rounded-lg border p-3 bg-muted/30 space-y-2">
                <Label className="text-xs font-semibold">위치명 형식</Label>
                <div className="flex items-center gap-1 text-xs flex-wrap">
                  <span className="font-mono text-muted-foreground">A</span>
                  <Input
                    value={rackZoneLabel}
                    onChange={(e) => setRackZoneLabel(e.target.value)}
                    placeholder="구역"
                    className="h-8 w-20 text-xs"
                  />
                  <span className="font-mono text-muted-foreground">- 01</span>
                  <Input
                    value={rackRowLabel}
                    onChange={(e) => setRackRowLabel(e.target.value)}
                    placeholder="열"
                    className="h-8 w-20 text-xs"
                  />
                  <span className="font-mono text-muted-foreground">- 1</span>
                  <Input
                    value={rackLevelLabel}
                    onChange={(e) => setRackLevelLabel(e.target.value)}
                    placeholder="단"
                    className="h-8 w-20 text-xs"
                  />
                </div>
                <p className="text-[11px] text-muted-foreground">
                  예시: <span className="font-mono font-semibold">A{rackZoneLabel}-01{rackRowLabel}-1{rackLevelLabel}</span>
                  {" "}— 구역/열/단 번호는 자동 계산되고, 뒤에 붙는 명칭만 수정할 수 있습니다.
                </p>
              </div>

              {/* 등록 미리보기 */}
              <div>
                <div className="flex items-center justify-between mb-3">
                  <h3 className="text-sm font-bold flex items-center gap-1.5">
                    👁️ 등록 미리보기
                  </h3>
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-7 gap-1 text-xs"
                    onClick={generateRackPreview}
                  >
                    <Eye className="h-3.5 w-3.5" />
                    미리보기 생성
                  </Button>
                </div>

                {rackPreview.length > 0 && (
                  <>
                    {/* 통계 카드 */}
                    <div className="grid grid-cols-3 gap-3 mb-3">
                      <div className="rounded-lg border bg-muted/50 p-3 text-center">
                        <p className="text-[11px] text-muted-foreground">총 위치</p>
                        <p className="text-lg font-bold">{rackStats.totalLocations}개</p>
                      </div>
                      <div className="rounded-lg border bg-muted/50 p-3 text-center">
                        <p className="text-[11px] text-muted-foreground">열 수</p>
                        <p className="text-lg font-bold">{rackStats.totalRows}개</p>
                      </div>
                      <div className="rounded-lg border bg-muted/50 p-3 text-center">
                        <p className="text-[11px] text-muted-foreground">최대 단</p>
                        <p className="text-lg font-bold">{rackStats.maxLevels}</p>
                      </div>
                    </div>

                    {/* 미리보기 테이블 */}
                    <div className="rounded-lg border overflow-hidden max-h-[300px] overflow-y-auto">
                      <Table>
                        <TableHeader className="sticky top-0 z-10">
                          <TableRow className="bg-muted hover:bg-muted">
                            <TableHead className="w-10 text-center text-[11px] font-bold text-muted-foreground">No</TableHead>
                            <TableHead className="text-[11px] font-bold text-muted-foreground">위치코드</TableHead>
                            <TableHead className="text-[11px] font-bold text-muted-foreground">위치명</TableHead>
                            <TableHead className="w-14 text-center text-[11px] font-bold text-muted-foreground">층</TableHead>
                            <TableHead className="w-14 text-center text-[11px] font-bold text-muted-foreground">구역</TableHead>
                            <TableHead className="w-12 text-center text-[11px] font-bold text-muted-foreground">열</TableHead>
                            <TableHead className="w-12 text-center text-[11px] font-bold text-muted-foreground">단</TableHead>
                            <TableHead className="w-16 text-[11px] font-bold text-muted-foreground">유형</TableHead>
                            <TableHead className="w-16 text-[11px] font-bold text-muted-foreground">비고</TableHead>
                          </TableRow>
                        </TableHeader>
                        <TableBody>
                          {rackPreview.map((item, idx) => (
                            <TableRow key={idx} className="text-xs">
                              <TableCell className="text-center text-muted-foreground">
                                {idx + 1}
                              </TableCell>
                              <TableCell className="font-mono">{item.location_code}</TableCell>
                              <TableCell>{item.location_name}</TableCell>
                              <TableCell className="text-center">{item.floor}</TableCell>
                              <TableCell className="text-center">{item.zone}</TableCell>
                              <TableCell className="text-center">{item.row_num}</TableCell>
                              <TableCell className="text-center">{item.level_num}</TableCell>
                              <TableCell>
                                {resolveCategory(locationCategoryOptions, "location_type", item.location_type) || "-"}
                              </TableCell>
                              <TableCell>-</TableCell>
                            </TableRow>
                          ))}
                        </TableBody>
                      </Table>
                    </div>
                  </>
                )}

                {rackPreview.length === 0 && (
                  <div className="flex flex-col items-center justify-center py-6 border-2 border-dashed rounded-lg border-border text-sm text-muted-foreground">
                    위의 설정을 완료한 뒤 미리보기 생성 버튼을 클릭하세요
                  </div>
                )}
              </div>
            </div>
          </div>

          <div className="flex justify-end gap-2 px-6 py-4 border-t shrink-0 bg-background">
            <Button variant="outline" onClick={() => setRackModalOpen(false)}>
              취소
            </Button>
            <Button
              onClick={handleRackBulkSave}
              disabled={rackSaving || rackPreview.length === 0}
            >
              {rackSaving && <Loader2 className="h-4 w-4 animate-spin mr-1" />}
              일괄 등록 ({rackPreview.length}건)
            </Button>
          </div>
        </DialogContent>
      </Dialog>

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