"use client";

import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
  DialogDescription,
} from "@/components/ui/dialog";
import { Checkbox } from "@/components/ui/checkbox";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";
import {
  ChevronRight,
  ChevronDown,
  Plus,
  Trash2,
  Search,
  Loader2,
  Inbox,
  Upload,
  Download,
  GitBranch,
  History,
  CheckCircle2,
  RotateCcw,
  X,
  FileText,
  Play,
  Copy,
  Settings2,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";
import { useAuth } from "@/hooks/useAuth";
import { toast } from "sonner";
import { useConfirmDialog } from "@/components/common/ConfirmDialog";
import { useTableSettings } from "@/hooks/useTableSettings";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { exportToExcel } from "@/lib/utils/excelExport";

// ─── 상수 ───────────────────────────────────────
const BOM_TABLE = "bom";
const BOM_DETAIL_TABLE = "bom_detail";

const BOM_COLUMNS = [
  { key: "item_code", label: "품목코드" },
  { key: "item_name", label: "품명" },
  { key: "bom_type", label: "BOM 유형" },
  { key: "version", label: "버전" },
  { key: "effective_date", label: "유효시작일" },
  { key: "status", label: "상태" },
];


const STATUS_MAP: Record<string, { label: string; className: string }> = {
  active: { label: "활성", className: "bg-success/10 text-success" },
  draft: { label: "초안", className: "bg-warning/10 text-warning" },
  expired: { label: "만료", className: "bg-destructive/10 text-destructive" },
  inactive: { label: "비활성", className: "bg-muted text-muted-foreground" },
};

const VERSION_STATUS_MAP: Record<string, { label: string; className: string }> = {
  active: { label: "사용중", className: "bg-success/10 text-success" },
  developing: { label: "개발중", className: "bg-warning/10 text-warning" },
  inactive: { label: "비활성", className: "bg-muted text-muted-foreground" },
};

const BOM_TYPE_OPTIONS = [
  { code: "production", label: "생산 BOM" },
  { code: "design", label: "설계 BOM" },
  { code: "cost", label: "원가 BOM" },
];

// ─── 인터페이스 ─────────────────────────────────
interface BomRow {
  id: string;
  item_id?: string;
  item_code?: string;
  item_name?: string;
  bom_type?: string;
  version?: string;
  base_qty?: string;
  unit?: string;
  status?: string;
  effective_date?: string;
  expiry_date?: string;
  remark?: string;
  current_version_id?: string;
  [key: string]: any;
}

interface BomDetail {
  id: string;
  bom_id: string;
  version_id?: string;
  parent_detail_id?: string | null;
  child_item_id?: string;
  item_number?: string;
  item_name?: string;
  item_type?: string;
  quantity?: string;
  unit?: string;
  process_type?: string;
  loss_rate?: string;
  remark?: string;
  level?: string;
  seq_no?: string;
  [key: string]: any;
}

interface BomVersion {
  id: string;
  bom_id: string;
  version_name: string;
  revision?: number;
  status: string;
  created_by?: string;
  created_date?: string;
  detail_count?: number;
}

interface BomHistoryEntry {
  id: string;
  bom_id: string;
  revision?: string;
  version?: string;
  change_type: string;
  change_description?: string;
  changed_by?: string;
  changed_date?: string;
}

interface TreeNode extends BomDetail {
  children: TreeNode[];
  expanded?: boolean;
}

// ─── 트리 구성 헬퍼 ─────────────────────────────
function buildTree(details: BomDetail[]): TreeNode[] {
  const nodeMap = new Map<string, TreeNode>();
  const roots: TreeNode[] = [];

  for (const d of details) {
    nodeMap.set(d.id, { ...d, children: [], expanded: true });
  }

  for (const d of details) {
    const node = nodeMap.get(d.id)!;
    if (d.parent_detail_id && nodeMap.has(d.parent_detail_id)) {
      nodeMap.get(d.parent_detail_id)!.children.push(node);
    } else {
      roots.push(node);
    }
  }

  return roots;
}

function flattenTree(nodes: TreeNode[], level = 0): (TreeNode & { _level: number })[] {
  const result: (TreeNode & { _level: number })[] = [];
  for (const node of nodes) {
    result.push({ ...node, _level: level });
    if (node.expanded && node.children.length > 0) {
      result.push(...flattenTree(node.children, level + 1));
    }
  }
  return result;
}

// ─── 타입 뱃지 색상 ────────────────────────────
function getItemTypeBadge(type?: string) {
  switch (type) {
    case "원자재":
    case "raw":
      return { label: "원자재", className: "bg-success/10 text-success border-success/20" };
    case "반제품":
    case "semi":
      return { label: "반제품", className: "bg-warning/10 text-warning border-warning/20" };
    case "완제품":
    case "finished":
      return { label: "완제품", className: "bg-primary/10 text-primary border-primary/20" };
    default:
      return { label: type || "-", className: "bg-muted text-muted-foreground" };
  }
}

// ─── 메인 컴포넌트 ──────────────────────────────
export default function BomManagementPage() {
  const { user } = useAuth();
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();
  const ts = useTableSettings("c16-bom", BOM_TABLE, BOM_COLUMNS);

  // BOM 목록 상태
  const [bomList, setBomList] = useState<BomRow[]>([]);
  const [loading, setLoading] = useState(false);
  const [totalCount, setTotalCount] = useState(0);
  const [searchKeyword, setSearchKeyword] = useState("");
  const [searchType, setSearchType] = useState("all");
  const [searchStatus, setSearchStatus] = useState("all");
  const [selectedBomId, setSelectedBomId] = useState<string | null>(null);
  const [checkedIds, setCheckedIds] = useState<string[]>([]);

  // 상세 데이터
  const [bomHeader, setBomHeader] = useState<BomRow | null>(null);
  const [bomDetails, setBomDetails] = useState<BomDetail[]>([]);
  const [treeNodes, setTreeNodes] = useState<TreeNode[]>([]);
  const [detailLoading, setDetailLoading] = useState(false);

  // 트리 토글
  const [treeDirection, setTreeDirection] = useState<"forward" | "reverse">("forward");
  const [treeBasis, setTreeBasis] = useState<"material" | "process">("material");

  // 버전 관리
  const [versions, setVersions] = useState<BomVersion[]>([]);
  const [currentVersionId, setCurrentVersionId] = useState<string | null>(null);
  const [versionLoading, setVersionLoading] = useState(false);
  const [newVersionName, setNewVersionName] = useState("");
  const [showNewVersionDialog, setShowNewVersionDialog] = useState(false);

  // 이력 관리
  const [historyList, setHistoryList] = useState<BomHistoryEntry[]>([]);
  const [historyLoading, setHistoryLoading] = useState(false);
  const [showHistoryDialog, setShowHistoryDialog] = useState(false);
  const [newHistory, setNewHistory] = useState({ change_type: "", change_description: "" });

  // 등록 모달
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [isEditMode, setIsEditMode] = useState(false);
  const [saving, setSaving] = useState(false);
  const [masterForm, setMasterForm] = useState<Record<string, any>>({
    item_id: "",
    item_code: "",
    item_name: "",
    bom_type: "",
    base_qty: "1",
    unit: "",
    version: "1.0",
    status: "draft",
    effective_date: "",
    expiry_date: "",
    remark: "",
  });
  const [modalDetailRows, setModalDetailRows] = useState<any[]>([]);

  // 품목 검색 모달
  const [showItemSearchModal, setShowItemSearchModal] = useState(false);
  const [itemSearchKeyword, setItemSearchKeyword] = useState("");
  const [itemSearchResults, setItemSearchResults] = useState<any[]>([]);
  const [itemSearchLoading, setItemSearchLoading] = useState(false);
  const [itemSearchTarget, setItemSearchTarget] = useState<"master" | "detail">("master");

  // 엑셀 업로드
  const [showExcelUpload, setShowExcelUpload] = useState(false);
  const [excelFile, setExcelFile] = useState<File | null>(null);
  const [excelUploading, setExcelUploading] = useState(false);

  // 우측 탭
  const [rightTab, setRightTab] = useState<"tree" | "version" | "history">("tree");

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

  // ─── 데이터 로드 ──────────────────────────────
  const fetchBomList = useCallback(async () => {
    setLoading(true);
    try {
      const filters: any[] = [];
      if (searchKeyword.trim()) {
        filters.push({ columnName: "item_name", operator: "contains", value: searchKeyword.trim() });
      }
      if (searchType !== "all") {
        filters.push({ columnName: "bom_type", operator: "equals", value: searchType });
      }
      if (searchStatus !== "all") {
        filters.push({ columnName: "status", operator: "equals", value: searchStatus });
      }

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

      const rows = res.data?.data?.data || res.data?.data?.rows || [];
      setBomList(rows);
      setTotalCount(rows.length);
    } catch (err: any) {
      toast.error("BOM 목록 조회에 실패했어요");
    } finally {
      setLoading(false);
    }
  }, [searchKeyword, searchType, searchStatus]);

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

  // 카테고리 옵션 로드
  useEffect(() => {
    const loadCategories = async () => {
      try {
        const columns = ["bom_type", "status"];
        const results: Record<string, { code: string; label: string }[]> = {};

        for (const col of columns) {
          try {
            const res = await apiClient.get(`/table-categories/${BOM_TABLE}/${col}/values`);
            if (res.data?.data?.length > 0) {
              const flatten = (items: any[]): { code: string; label: string }[] => {
                const result: { code: string; label: string }[] = [];
                for (const item of items) {
                  result.push({ code: item.value || item.code, label: item.label || item.value });
                  if (item.children?.length) {
                    result.push(...flatten(item.children));
                  }
                }
                return result;
              };
              results[col] = flatten(res.data.data);
            }
          } catch {}
        }

        setCategoryOptions(results);
      } catch {}
    };
    loadCategories();
  }, []);

  // ─── BOM 상세 로드 ────────────────────────────
  const fetchBomDetail = useCallback(async (bomId: string) => {
    setDetailLoading(true);
    try {
      // 헤더 조회
      const headerRes = await apiClient.get(`/bom/${bomId}/header`);
      const header = headerRes.data?.data || headerRes.data;
      setBomHeader(header);
      setCurrentVersionId(header?.current_version_id || null);

      // 디테일 조회 (현재 버전)
      const versionId = header?.current_version_id;
      const detailFilters: any[] = [{ columnName: "bom_id", operator: "equals", value: bomId }];
      if (versionId) {
        detailFilters.push({ columnName: "version_id", operator: "equals", value: versionId });
      }

      const detailRes = await apiClient.post(`/table-management/tables/${BOM_DETAIL_TABLE}/data`, {
        page: 1,
        size: 1000,
        dataFilter: { enabled: true, filters: detailFilters },
        sort: { columnName: "parent_detail_id", order: "asc" },
      });

      let details = detailRes.data?.data?.data || detailRes.data?.data?.rows || [];

      // item_info 조인을 위해 child_item_id 수집
      const itemIds = [...new Set(details.map((d: any) => d.child_item_id).filter(Boolean))];
      if (itemIds.length > 0) {
        try {
          const itemRes = await apiClient.post(`/table-management/tables/item_info/data`, {
            page: 1,
            size: 1000,
            dataFilter: {
              enabled: true,
              filters: [{ columnName: "id", operator: "in", value: itemIds.join(",") }],
            },
          });
          const items = itemRes.data?.data?.data || itemRes.data?.data?.rows || [];
          const itemMap = new Map(items.map((i: any) => [i.id, i]));

          details = details.map((d: any) => {
            const item = itemMap.get(d.child_item_id) as any;
            return {
              ...d,
              item_number: item?.item_number || "",
              item_name: item?.item_name || "",
              item_type: item?.division || "",
              unit: d.unit || item?.unit || "",
            };
          });
        } catch {}
      }

      setBomDetails(details);
      const tree = buildTree(details);
      setTreeNodes(tree);
    } catch (err: any) {
      toast.error("BOM 상세 조회에 실패했어요");
    } finally {
      setDetailLoading(false);
    }
  }, []);

  // 버전 목록 로드
  const fetchVersions = useCallback(async (bomId: string) => {
    setVersionLoading(true);
    try {
      const res = await apiClient.get(`/bom/${bomId}/versions`);
      const data = res.data?.data || res.data;
      setVersions(data?.versions || []);
      setCurrentVersionId(data?.currentVersionId || null);
    } catch (err: any) {
      toast.error("버전 목록 조회에 실패했어요");
    } finally {
      setVersionLoading(false);
    }
  }, []);

  // 이력 목록 로드
  const fetchHistory = useCallback(async (bomId: string) => {
    setHistoryLoading(true);
    try {
      const res = await apiClient.get(`/bom/${bomId}/history`);
      setHistoryList(res.data?.data || []);
    } catch (err: any) {
      toast.error("이력 조회에 실패했어요");
    } finally {
      setHistoryLoading(false);
    }
  }, []);

  // BOM 선택 시 상세 로드
  useEffect(() => {
    if (selectedBomId) {
      fetchBomDetail(selectedBomId);
      if (rightTab === "version") fetchVersions(selectedBomId);
      if (rightTab === "history") fetchHistory(selectedBomId);
    } else {
      setBomHeader(null);
      setBomDetails([]);
      setTreeNodes([]);
      setVersions([]);
      setHistoryList([]);
    }
  }, [selectedBomId, fetchBomDetail, fetchVersions, fetchHistory, rightTab]);

  // ─── 트리 토글 핸들러 ─────────────────────────
  const toggleTreeNode = useCallback((nodeId: string) => {
    const toggle = (nodes: TreeNode[]): TreeNode[] =>
      nodes.map((n) =>
        n.id === nodeId
          ? { ...n, expanded: !n.expanded }
          : { ...n, children: toggle(n.children) }
      );
    setTreeNodes((prev) => toggle(prev));
  }, []);

  const flatTree = useMemo(() => flattenTree(treeNodes), [treeNodes]);

  // ─── BOM 삭제 ────────────────────────────────
  const handleDeleteBom = async () => {
    if (checkedIds.length === 0) {
      toast.error("삭제할 BOM을 선택해주세요");
      return;
    }
    const ok = await confirm(`선택한 ${checkedIds.length}건의 BOM을 삭제할까요?`);
    if (!ok) return;
    try {
      await apiClient.delete(`/table-management/tables/${BOM_TABLE}/delete`, {
        data: checkedIds.map((id) => ({ id })),
      });
      toast.success("BOM이 삭제되었어요");
      setCheckedIds([]);
      setSelectedBomId(null);
      fetchBomList();
    } catch {
      toast.error("BOM 삭제에 실패했어요");
    }
  };

  // ─── BOM 등록/수정 ───────────────────────────
  const openCreateModal = () => {
    setIsEditMode(false);
    setMasterForm({
      item_id: "",
      item_code: "",
      item_name: "",
      bom_type: "",
      base_qty: "1",
      unit: "",
      version: "1.0",
      status: "draft",
      effective_date: "",
      expiry_date: "",
      remark: "",
    });
    setModalDetailRows([]);
    setIsModalOpen(true);
  };

  const openEditModal = () => {
    if (!bomHeader) return;
    setIsEditMode(true);
    setMasterForm({
      id: bomHeader.id,
      item_id: bomHeader.item_id || "",
      item_code: bomHeader.item_code || bomHeader.item_number || "",
      item_name: bomHeader.item_name || "",
      bom_type: bomHeader.bom_type || "",
      base_qty: bomHeader.base_qty || "1",
      unit: bomHeader.unit || "",
      version: bomHeader.version || "1.0",
      status: bomHeader.status || "draft",
      effective_date: bomHeader.effective_date || "",
      expiry_date: bomHeader.expiry_date || "",
      remark: bomHeader.remark || "",
    });

    setModalDetailRows(
      bomDetails.map((d, i) => ({
        _idx: i,
        child_item_id: d.child_item_id || "",
        item_number: d.item_number || "",
        item_name: d.item_name || "",
        quantity: d.quantity || "1",
        unit: d.unit || "",
        process_type: d.process_type || "",
        loss_rate: d.loss_rate || "0",
        remark: d.remark || "",
      }))
    );
    setIsModalOpen(true);
  };

  const handleSaveBom = async () => {
    if (!masterForm.item_id) {
      toast.error("품목을 선택해주세요");
      return;
    }
    if (!masterForm.bom_type) {
      toast.error("BOM 유형을 선택해주세요");
      return;
    }

    setSaving(true);
    try {
      const bomFields: Record<string, any> = {
        item_id: masterForm.item_id,
        item_code: masterForm.item_code,
        item_name: masterForm.item_name,
        bom_type: masterForm.bom_type,
        base_qty: masterForm.base_qty || "1",
        unit: masterForm.unit || "",
        version: masterForm.version || "1.0",
        status: masterForm.status || "draft",
        effective_date: masterForm.effective_date || null,
        expiry_date: masterForm.expiry_date || null,
        remark: masterForm.remark || "",
        writer: user?.userId || "",
        company_code: user?.company_code || "",
      };

      let bomId: string;

      if (isEditMode && masterForm.id) {
        await apiClient.put(`/table-management/tables/${BOM_TABLE}/edit`, {
          originalData: { id: masterForm.id },
          updatedData: bomFields,
        });
        bomId = masterForm.id;
      } else {
        const res = await apiClient.post(`/table-management/tables/${BOM_TABLE}/add`, { id: crypto.randomUUID(), ...bomFields });
        bomId = res.data?.data?.id || res.data?.id;
      }

      // 초기 버전 생성 (신규 BOM)
      if (!isEditMode && bomId) {
        try {
          await apiClient.post(`/bom/${bomId}/initialize-version`, {});
        } catch {}
      }

      // 디테일 저장: 기존 삭제 후 재등록
      if (isEditMode && masterForm.id) {
        const existingDetails = bomDetails.filter((d) => d.bom_id === bomId);
        if (existingDetails.length > 0) {
          await apiClient.delete(`/table-management/tables/${BOM_DETAIL_TABLE}/delete`, {
            data: existingDetails.map((d) => ({ id: d.id })),
          });
        }
      }

      // 현재 버전 ID 가져오기
      let versionId = currentVersionId;
      if (!versionId && bomId) {
        try {
          const verRes = await apiClient.get(`/bom/${bomId}/versions`);
          const verData = verRes.data?.data || verRes.data;
          versionId = verData?.currentVersionId || null;
        } catch {}
      }

      for (let i = 0; i < modalDetailRows.length; i++) {
        const row = modalDetailRows[i];
        if (!row.child_item_id) continue;
        await apiClient.post(`/table-management/tables/${BOM_DETAIL_TABLE}/add`, {
          id: crypto.randomUUID(),
          bom_id: bomId,
          version_id: versionId || null,
          parent_detail_id: null,
          child_item_id: row.child_item_id,
          quantity: row.quantity || "1",
          unit: row.unit || "",
          process_type: row.process_type || "",
          loss_rate: row.loss_rate || "0",
          remark: row.remark || "",
          level: "0",
          seq_no: String(i + 1),
          writer: user?.userId || "",
          company_code: user?.company_code || "",
        });
      }

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

  // ─── 품목 검색 ───────────────────────────────
  const searchItems = async () => {
    if (!itemSearchKeyword.trim()) return;
    setItemSearchLoading(true);
    try {
      const res = await apiClient.post(`/table-management/tables/item_info/data`, {
        page: 1,
        size: 50,
        dataFilter: {
          enabled: true,
          filters: [
            {
              columnName: "item_number",
              operator: "contains",
              value: itemSearchKeyword.trim(),
            },
          ],
        },
      });
      const rows = res.data?.data?.data || res.data?.data?.rows || [];

      // 품명으로도 검색
      if (rows.length === 0) {
        const res2 = await apiClient.post(`/table-management/tables/item_info/data`, {
          page: 1,
          size: 50,
          dataFilter: {
            enabled: true,
            filters: [
              {
                columnName: "item_name",
                operator: "contains",
                value: itemSearchKeyword.trim(),
              },
            ],
          },
        });
        setItemSearchResults(res2.data?.data?.data || res2.data?.data?.rows || []);
      } else {
        setItemSearchResults(rows);
      }
    } catch {
      toast.error("품목 검색에 실패했어요");
    } finally {
      setItemSearchLoading(false);
    }
  };

  const selectItem = (item: any) => {
    if (itemSearchTarget === "master") {
      setMasterForm((prev) => ({
        ...prev,
        item_id: item.id,
        item_code: item.item_number || "",
        item_name: item.item_name || "",
        unit: item.unit || prev.unit,
      }));
      setShowItemSearchModal(false);
    } else {
      setModalDetailRows((prev) => [
        ...prev,
        {
          _idx: prev.length,
          child_item_id: item.id,
          item_number: item.item_number || "",
          item_name: item.item_name || "",
          quantity: "1",
          unit: item.unit || "",
          process_type: "",
          loss_rate: "0",
          remark: "",
        },
      ]);
      setShowItemSearchModal(false);
    }
    setItemSearchKeyword("");
    setItemSearchResults([]);
  };

  // ─── 버전 관리 ───────────────────────────────
  const handleCreateVersion = async () => {
    if (!selectedBomId) return;
    try {
      await apiClient.post(`/bom/${selectedBomId}/versions`, {
        versionName: newVersionName.trim() || undefined,
      });
      toast.success("새 버전이 생성되었어요");
      setShowNewVersionDialog(false);
      setNewVersionName("");
      fetchVersions(selectedBomId);
      fetchBomDetail(selectedBomId);
      fetchBomList();
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "버전 생성에 실패했어요");
    }
  };

  const handleLoadVersion = async (versionId: string) => {
    if (!selectedBomId) return;
    try {
      await apiClient.post(`/bom/${selectedBomId}/versions/${versionId}/load`);
      toast.success("버전을 불러왔어요");
      fetchVersions(selectedBomId);
      fetchBomDetail(selectedBomId);
      fetchBomList();
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "버전 불러오기에 실패했어요");
    }
  };

  const handleActivateVersion = async (versionId: string) => {
    if (!selectedBomId) return;
    const ok = await confirm("이 버전을 사용 확정할까요? 기존 활성 버전은 비활성 처리돼요.");
    if (!ok) return;
    try {
      await apiClient.post(`/bom/${selectedBomId}/versions/${versionId}/activate`);
      toast.success("버전이 사용 확정되었어요");
      fetchVersions(selectedBomId);
      fetchBomDetail(selectedBomId);
      fetchBomList();
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "버전 확정에 실패했어요");
    }
  };

  const handleDeleteVersion = async (versionId: string) => {
    if (!selectedBomId) return;
    const ok = await confirm("이 버전을 삭제할까요? 관련 디테일 데이터도 함께 삭제돼요.");
    if (!ok) return;
    try {
      await apiClient.delete(`/bom/${selectedBomId}/versions/${versionId}`);
      toast.success("버전이 삭제되었어요");
      fetchVersions(selectedBomId);
      fetchBomDetail(selectedBomId);
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "버전 삭제에 실패했어요");
    }
  };

  // ─── 이력 관리 ───────────────────────────────
  const handleAddHistory = async () => {
    if (!selectedBomId) return;
    if (!newHistory.change_type) {
      toast.error("변경 유형을 입력해주세요");
      return;
    }
    try {
      await apiClient.post(`/bom/${selectedBomId}/history`, {
        change_type: newHistory.change_type,
        change_description: newHistory.change_description,
        changed_by: user?.userId || "",
      });
      toast.success("이력이 추가되었어요");
      setShowHistoryDialog(false);
      setNewHistory({ change_type: "", change_description: "" });
      fetchHistory(selectedBomId);
    } catch (err: any) {
      toast.error("이력 추가에 실패했어요");
    }
  };

  // ─── 엑셀 업로드 ────────────────────────────
  const handleExcelUpload = async () => {
    if (!excelFile) {
      toast.error("엑셀 파일을 선택해주세요");
      return;
    }
    setExcelUploading(true);
    try {
      const formData = new FormData();
      formData.append("file", excelFile);

      const endpoint = selectedBomId
        ? `/bom/${selectedBomId}/excel-upload-version`
        : `/bom/excel-upload`;

      const res = await apiClient.post(endpoint, formData, {
        headers: { "Content-Type": "multipart/form-data" },
      });

      const result = res.data?.data || res.data;
      if (result?.success) {
        toast.success(`엑셀 업로드 완료 (${result.insertedCount}건 등록)`);
        setShowExcelUpload(false);
        setExcelFile(null);
        fetchBomList();
        if (result.createdBomId) {
          setSelectedBomId(result.createdBomId);
        }
      } else {
        toast.error(result?.errors?.join("\n") || "엑셀 업로드에 실패했어요");
      }
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "엑셀 업로드에 실패했어요");
    } finally {
      setExcelUploading(false);
    }
  };

  // 엑셀 다운로드
  const handleExcelDownload = async () => {
    if (!selectedBomId) {
      toast.error("BOM을 선택해주세요");
      return;
    }
    try {
      const res = await apiClient.get(`/bom/${selectedBomId}/excel-download`);
      const data = res.data?.data || [];
      if (data.length === 0) {
        toast.error("다운로드할 데이터가 없어요");
        return;
      }
      exportToExcel(data, `BOM_${bomHeader?.item_code || selectedBomId}`);
      toast.success("엑셀 다운로드를 시작했어요");
    } catch {
      toast.error("엑셀 다운로드에 실패했어요");
    }
  };

  // ─── 상태 뱃지 렌더 ───────────────────────────
  const renderStatusBadge = (status?: string) => {
    const info = STATUS_MAP[status || ""] || { label: status || "-", className: "bg-muted text-muted-foreground" };
    return (
      <span className={cn("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[11px] font-medium", info.className)}>
        <span className="w-1.5 h-1.5 rounded-full bg-current" />
        {info.label}
      </span>
    );
  };

  // ─── 렌더링 ──────────────────────────────────
  return (
    <div className="flex flex-col h-full">
      {/* 브레드크럼 */}
      <nav className="flex items-center gap-1.5 px-5 py-3 text-xs text-muted-foreground bg-muted/50 border-b shrink-0">
        <span>생산관리</span>
        <ChevronRight className="w-3.5 h-3.5 text-muted-foreground/50" />
        <span className="font-semibold text-foreground">BOM 관리</span>
      </nav>

      {/* 검색 필터 */}
      <div className="flex items-center gap-2 px-4 py-2.5 border-b bg-muted/50 shrink-0 flex-wrap">
        <Input
          className="h-8 w-[180px] text-xs"
          placeholder="품명 검색"
          value={searchKeyword}
          onChange={(e) => setSearchKeyword(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && fetchBomList()}
        />
        <Select value={searchType} onValueChange={setSearchType}>
          <SelectTrigger className="h-8 w-[130px] text-xs">
            <SelectValue placeholder="BOM 유형" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="all">전체 유형</SelectItem>
            <SelectItem value="production">생산 BOM</SelectItem>
            <SelectItem value="design">설계 BOM</SelectItem>
            <SelectItem value="cost">원가 BOM</SelectItem>
          </SelectContent>
        </Select>
        <Select value={searchStatus} onValueChange={setSearchStatus}>
          <SelectTrigger className="h-8 w-[110px] text-xs">
            <SelectValue placeholder="상태" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="all">전체 상태</SelectItem>
            <SelectItem value="active">활성</SelectItem>
            <SelectItem value="draft">초안</SelectItem>
            <SelectItem value="expired">만료</SelectItem>
            <SelectItem value="inactive">비활성</SelectItem>
          </SelectContent>
        </Select>
        <Button size="sm" className="h-8 text-xs" onClick={fetchBomList}>
          <Search className="w-3.5 h-3.5 mr-1" />
          조회
        </Button>
        <Button
          size="sm"
          variant="outline"
          className="h-8 text-xs"
          onClick={() => { setSearchKeyword(""); setSearchType("all"); setSearchStatus("all"); }}
        >
          <RotateCcw className="w-3.5 h-3.5 mr-1" />
          초기화
        </Button>
        <div className="ml-auto flex items-center gap-2">
          <Button size="sm" variant="outline" className="h-8 text-xs" onClick={() => setShowExcelUpload(true)}>
            <Upload className="w-3.5 h-3.5 mr-1.5" />
            엑셀 업로드
          </Button>
          <Button size="sm" variant="outline" className="h-8 text-xs" onClick={handleExcelDownload} disabled={!selectedBomId}>
            <Download className="w-3.5 h-3.5 mr-1.5" />
            엑셀 다운로드
          </Button>
        </div>
      </div>

      {/* 메인 콘텐츠: 좌우 분할 */}
      <div className="flex-1 overflow-hidden rounded-lg border bg-card mx-3 mb-3">
        <ResizablePanelGroup direction="horizontal">
          {/* 좌측: BOM 목록 */}
          <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 shrink-0">
                <div className="flex items-center gap-2">
                  <h3 className="text-[13px] font-bold text-foreground">BOM 목록</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">
                    {totalCount}건
                  </span>
                  {loading && <Loader2 className="w-3.5 h-3.5 animate-spin text-muted-foreground" />}
                </div>
                <div className="flex items-center gap-1.5">
                  <Button size="sm" onClick={openCreateModal}>
                    <Plus className="w-3.5 h-3.5 mr-1" />
                    등록
                  </Button>
                  <div className="w-px h-4 bg-border mx-0.5" />
                  <Button
                    size="sm"
                    variant="outline"
                    className="text-destructive border-destructive/20 bg-destructive/5 hover:bg-destructive/10"
                    onClick={handleDeleteBom}
                    disabled={checkedIds.length === 0}
                  >
                    <Trash2 className="w-3.5 h-3.5 mr-1" />
                    삭제
                  </Button>
                  <Button variant="ghost" size="sm" onClick={() => ts.setOpen(true)} title="테이블 설정">
                    <Settings2 className="w-3.5 h-3.5" />
                  </Button>
                </div>
              </div>

              {/* BOM 목록 테이블 */}
              <div className="flex-1 overflow-auto">
                {loading ? (
                  <div className="flex items-center justify-center py-12">
                    <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />
                  </div>
                ) : bomList.length === 0 ? (
                  <div className="flex flex-col items-center justify-center py-12 text-muted-foreground gap-2">
                    <Inbox className="w-8 h-8 text-muted-foreground/40" />
                    <p className="text-xs">등록된 BOM이 없어요</p>
                  </div>
                ) : (
                  <Table>
                    <TableHeader>
                      <TableRow className="bg-muted/50">
                        <TableHead className="w-[36px] text-center">
                          <Checkbox
                            checked={checkedIds.length === bomList.length && bomList.length > 0}
                            onCheckedChange={(checked) =>
                              setCheckedIds(checked ? bomList.map((r) => r.id) : [])
                            }
                          />
                        </TableHead>
                        {ts.visibleColumns.map((col) => (
                          <TableHead key={col.key} className="text-xs">{col.label}</TableHead>
                        ))}
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {bomList.map((row) => (
                        <TableRow
                          key={row.id}
                          className={cn(
                            "cursor-pointer transition-colors",
                            selectedBomId === row.id
                              ? "bg-primary/10 border-l-2 border-l-primary"
                              : "hover:bg-muted/50"
                          )}
                          onClick={() => setSelectedBomId(row.id)}
                        >
                          <TableCell className="text-center" onClick={(e) => e.stopPropagation()}>
                            <Checkbox
                              checked={checkedIds.includes(row.id)}
                              onCheckedChange={(checked) =>
                                setCheckedIds((prev) =>
                                  checked ? [...prev, row.id] : prev.filter((id) => id !== row.id)
                                )
                              }
                            />
                          </TableCell>
                          {ts.visibleColumns.map((col) => {
                            if (col.key === "item_code") {
                              return <TableCell key={col.key} className="font-mono text-[13px]">{row.item_code || row.item_number || "-"}</TableCell>;
                            }
                            if (col.key === "bom_type") {
                              return <TableCell key={col.key} className="text-[13px]">{BOM_TYPE_OPTIONS.find((o) => o.code === row.bom_type)?.label || row.bom_type || "-"}</TableCell>;
                            }
                            if (col.key === "status") {
                              return <TableCell key={col.key}>{renderStatusBadge(row.status)}</TableCell>;
                            }
                            return <TableCell key={col.key} className="text-[13px] max-w-[160px] truncate">{row[col.key] || "-"}</TableCell>;
                          })}
                        </TableRow>
                      ))}
                    </TableBody>
                  </Table>
                )}
              </div>
            </div>
          </ResizablePanel>

          <ResizableHandle withHandle />

          {/* 우측: 상세 + 트리뷰 */}
          <ResizablePanel defaultSize={55} minSize={30}>
            {!selectedBomId ? (
              <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2">
                <Inbox className="w-10 h-10 text-muted-foreground/40" />
                <p className="text-sm">좌측에서 BOM을 선택해주세요</p>
              </div>
            ) : (
              <div className="flex flex-col h-full">
                {/* 상세 카드 */}
                <div className="border-b shrink-0">
                  <div className="flex items-center justify-between px-4 py-2.5 border-b bg-muted/50">
                    <h3 className="text-[13px] font-bold text-foreground">BOM 상세정보</h3>
                    <Button size="sm" variant="ghost" onClick={openEditModal}>
                      <FileText className="w-3.5 h-3.5 mr-1" />
                      편집
                    </Button>
                  </div>
                  {detailLoading ? (
                    <div className="flex items-center justify-center py-8">
                      <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />
                    </div>
                  ) : bomHeader ? (
                    <div className="grid grid-cols-2 text-sm">
                      <div className="flex flex-col gap-1 p-3 border-b border-r">
                        <span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">품목코드</span>
                        <span className="font-mono text-xs">{bomHeader.item_code || bomHeader.item_number || "-"}</span>
                      </div>
                      <div className="flex flex-col gap-1 p-3 border-b">
                        <span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">품명</span>
                        <span className="text-xs">{bomHeader.item_name || "-"}</span>
                      </div>
                      <div className="flex flex-col gap-1 p-3 border-b border-r">
                        <span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">BOM 유형</span>
                        <span className="text-xs">{BOM_TYPE_OPTIONS.find((o) => o.code === bomHeader.bom_type)?.label || bomHeader.bom_type || "-"}</span>
                      </div>
                      <div className="flex flex-col gap-1 p-3 border-b">
                        <span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">버전</span>
                        <span className="text-xs">{bomHeader.version || "-"}</span>
                      </div>
                      <div className="flex flex-col gap-1 p-3 border-b border-r">
                        <span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">기준수량</span>
                        <span className="text-xs">{bomHeader.base_qty || "1"} {bomHeader.unit || ""}</span>
                      </div>
                      <div className="flex flex-col gap-1 p-3 border-b">
                        <span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">상태</span>
                        {renderStatusBadge(bomHeader.status)}
                      </div>
                      <div className="flex flex-col gap-1 p-3 col-span-2">
                        <span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">메모</span>
                        <span className="text-xs text-muted-foreground">{bomHeader.remark || "-"}</span>
                      </div>
                    </div>
                  ) : null}
                </div>

                {/* 하단 탭: 트리뷰 / 버전 / 이력 */}
                <div className="flex-1 flex flex-col min-h-0 overflow-hidden">
                  <Tabs value={rightTab} onValueChange={(v) => {
                    setRightTab(v as any);
                    if (v === "version" && selectedBomId) fetchVersions(selectedBomId);
                    if (v === "history" && selectedBomId) fetchHistory(selectedBomId);
                  }}>
                    <div className="flex items-center justify-between px-4 py-2 border-b bg-muted/50 shrink-0">
                      <TabsList className="h-8">
                        <TabsTrigger value="tree" className="text-xs px-3 h-7">
                          <GitBranch className="w-3.5 h-3.5 mr-1" />
                          트리뷰
                        </TabsTrigger>
                        <TabsTrigger value="version" className="text-xs px-3 h-7">
                          <Copy className="w-3.5 h-3.5 mr-1" />
                          버전
                        </TabsTrigger>
                        <TabsTrigger value="history" className="text-xs px-3 h-7">
                          <History className="w-3.5 h-3.5 mr-1" />
                          이력
                        </TabsTrigger>
                      </TabsList>

                      {/* 트리뷰 토글 (트리뷰 탭에서만) */}
                      {rightTab === "tree" && (
                        <div className="flex items-center gap-2">
                          <div className="flex items-center gap-0.5 bg-card border rounded-md p-0.5">
                            <button
                              className={cn("px-2.5 py-1 text-[11px] font-medium rounded transition-all",
                                treeDirection === "forward" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
                              )}
                              onClick={() => setTreeDirection("forward")}
                            >
                              정전개
                            </button>
                            <button
                              className={cn("px-2.5 py-1 text-[11px] font-medium rounded transition-all",
                                treeDirection === "reverse" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
                              )}
                              onClick={() => setTreeDirection("reverse")}
                            >
                              역전개
                            </button>
                          </div>
                          <div className="w-px h-5 bg-border" />
                          <div className="flex items-center gap-0.5 bg-card border rounded-md p-0.5">
                            <button
                              className={cn("px-2.5 py-1 text-[11px] font-medium rounded transition-all",
                                treeBasis === "material" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
                              )}
                              onClick={() => setTreeBasis("material")}
                            >
                              자재기준
                            </button>
                            <button
                              className={cn("px-2.5 py-1 text-[11px] font-medium rounded transition-all",
                                treeBasis === "process" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
                              )}
                              onClick={() => setTreeBasis("process")}
                            >
                              공정기준
                            </button>
                          </div>
                        </div>
                      )}
                    </div>

                    {/* 트리뷰 탭 */}
                    <TabsContent value="tree" className="flex-1 overflow-auto p-2 m-0">
                      {flatTree.length === 0 ? (
                        <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2 py-12">
                          <Inbox className="w-8 h-8 text-muted-foreground/40" />
                          <p className="text-xs">BOM 구성 데이터가 없어요</p>
                        </div>
                      ) : (
                        <div className="space-y-0.5">
                          {flatTree.map((node) => {
                            const typeBadge = getItemTypeBadge(node.item_type);
                            const hasChildren = node.children.length > 0;
                            return (
                              <div
                                key={node.id}
                                className="flex items-center gap-1.5 py-1.5 px-2 rounded hover:bg-accent cursor-pointer transition-colors"
                                style={{ paddingLeft: `${node._level * 24 + 8}px` }}
                              >
                                {/* 토글 버튼 */}
                                {hasChildren ? (
                                  <button
                                    className="flex items-center justify-center w-[18px] h-[18px] rounded hover:bg-accent text-muted-foreground shrink-0"
                                    onClick={() => toggleTreeNode(node.id)}
                                  >
                                    {node.expanded ? (
                                      <ChevronDown className="w-3.5 h-3.5" />
                                    ) : (
                                      <ChevronRight className="w-3.5 h-3.5" />
                                    )}
                                  </button>
                                ) : (
                                  <span className="w-[18px] h-[18px] shrink-0" />
                                )}

                                {/* 타입 뱃지 */}
                                <span className={cn("text-[10px] font-semibold px-1.5 py-0.5 rounded shrink-0", typeBadge.className)}>
                                  {typeBadge.label}
                                </span>

                                {/* 품목코드 */}
                                <span className="font-mono text-[11px] text-muted-foreground whitespace-nowrap">
                                  {node.item_number || "-"}
                                </span>

                                <span className="text-muted-foreground/40 text-[10px]">|</span>

                                {/* 품명 */}
                                <span className="text-xs text-foreground whitespace-nowrap">
                                  {node.item_name || "-"}
                                </span>

                                {/* 수량 */}
                                <span className="ml-auto flex items-center gap-1 text-[11px] text-muted-foreground shrink-0 whitespace-nowrap">
                                  <strong className="font-semibold">{node.quantity || "1"}</strong>
                                  {node.unit || ""}
                                </span>

                                {/* 비고 */}
                                {node.remark && (
                                  <span className="text-[10px] text-muted-foreground/50 shrink-0">
                                    {node.remark}
                                  </span>
                                )}
                              </div>
                            );
                          })}
                        </div>
                      )}
                    </TabsContent>

                    {/* 버전 탭 */}
                    <TabsContent value="version" className="flex-1 overflow-auto m-0">
                      <div className="p-3">
                        <div className="flex items-center justify-between mb-3">
                          <span className="text-xs text-muted-foreground">
                            {versions.length}개 버전
                          </span>
                          <Button size="sm" onClick={() => setShowNewVersionDialog(true)}>
                            <Plus className="w-3.5 h-3.5 mr-1" />
                            새 버전
                          </Button>
                        </div>
                        {versionLoading ? (
                          <div className="flex items-center justify-center py-8">
                            <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />
                          </div>
                        ) : versions.length === 0 ? (
                          <div className="flex flex-col items-center justify-center py-12 text-muted-foreground gap-2">
                            <Inbox className="w-8 h-8 text-muted-foreground/40" />
                            <p className="text-xs">버전 데이터가 없어요</p>
                          </div>
                        ) : (
                          <div className="space-y-2">
                            {versions.map((ver) => {
                              const isActive = ver.id === currentVersionId;
                              const statusInfo = VERSION_STATUS_MAP[ver.status] || { label: ver.status, className: "bg-muted text-muted-foreground" };
                              return (
                                <div
                                  key={ver.id}
                                  className={cn(
                                    "flex items-center justify-between p-3 rounded-lg border transition-colors",
                                    isActive ? "border-primary/30 bg-primary/5" : "hover:bg-muted/50"
                                  )}
                                >
                                  <div className="flex items-center gap-3">
                                    <div className="flex flex-col gap-0.5">
                                      <div className="flex items-center gap-2">
                                        <span className="text-sm font-semibold">{ver.version_name}</span>
                                        <span className={cn("text-[10px] font-medium px-1.5 py-0.5 rounded-full", statusInfo.className)}>
                                          {statusInfo.label}
                                        </span>
                                        {isActive && (
                                          <Badge variant="outline" className="text-[10px] h-4 border-primary/30 text-primary">
                                            현재
                                          </Badge>
                                        )}
                                      </div>
                                      <span className="text-[11px] text-muted-foreground">
                                        {ver.detail_count || 0}개 구성품 · {ver.created_date ? new Date(ver.created_date).toLocaleDateString("ko-KR") : "-"}
                                      </span>
                                    </div>
                                  </div>
                                  <div className="flex items-center gap-1">
                                    {!isActive && (
                                      <Button size="sm" variant="ghost" className="h-7 text-xs" onClick={() => handleLoadVersion(ver.id)}>
                                        <RotateCcw className="w-3 h-3 mr-1" />
                                        불러오기
                                      </Button>
                                    )}
                                    {ver.status !== "active" && (
                                      <Button size="sm" variant="ghost" className="h-7 text-xs" onClick={() => handleActivateVersion(ver.id)}>
                                        <CheckCircle2 className="w-3 h-3 mr-1" />
                                        확정
                                      </Button>
                                    )}
                                    {ver.status !== "active" && (
                                      <Button
                                        size="sm"
                                        variant="ghost"
                                        className="h-7 text-xs text-destructive hover:text-destructive"
                                        onClick={() => handleDeleteVersion(ver.id)}
                                      >
                                        <Trash2 className="w-3 h-3" />
                                      </Button>
                                    )}
                                  </div>
                                </div>
                              );
                            })}
                          </div>
                        )}
                      </div>
                    </TabsContent>

                    {/* 이력 탭 */}
                    <TabsContent value="history" className="flex-1 overflow-auto m-0">
                      <div className="p-3">
                        <div className="flex items-center justify-between mb-3">
                          <span className="text-xs text-muted-foreground">
                            {historyList.length}건 이력
                          </span>
                          <Button size="sm" onClick={() => setShowHistoryDialog(true)}>
                            <Plus className="w-3.5 h-3.5 mr-1" />
                            이력 추가
                          </Button>
                        </div>
                        {historyLoading ? (
                          <div className="flex items-center justify-center py-8">
                            <Loader2 className="w-5 h-5 animate-spin text-muted-foreground" />
                          </div>
                        ) : historyList.length === 0 ? (
                          <div className="flex flex-col items-center justify-center py-12 text-muted-foreground gap-2">
                            <Inbox className="w-8 h-8 text-muted-foreground/40" />
                            <p className="text-xs">이력 데이터가 없어요</p>
                          </div>
                        ) : (
                          <div className="space-y-2">
                            {historyList.map((entry) => (
                              <div key={entry.id} className="p-3 rounded-lg border hover:bg-muted/50 transition-colors">
                                <div className="flex items-center justify-between mb-1">
                                  <Badge variant="outline" className="text-[10px]">
                                    {entry.change_type}
                                  </Badge>
                                  <span className="text-[10px] text-muted-foreground">
                                    {entry.changed_date ? new Date(entry.changed_date).toLocaleDateString("ko-KR") : "-"}
                                  </span>
                                </div>
                                <p className="text-xs text-muted-foreground">{entry.change_description || "-"}</p>
                                {entry.changed_by && (
                                  <span className="text-[10px] text-muted-foreground/60 mt-1 block">
                                    작성자: {entry.changed_by}
                                  </span>
                                )}
                              </div>
                            ))}
                          </div>
                        )}
                      </div>
                    </TabsContent>
                  </Tabs>
                </div>
              </div>
            )}
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>

      {/* ─── BOM 등록/수정 모달 ─────────────────── */}
      <Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
        <DialogContent className="max-w-[95vw] sm:max-w-2xl max-h-[85vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>{isEditMode ? "BOM 수정" : "BOM 등록"}</DialogTitle>
            <DialogDescription>{isEditMode ? "BOM 정보를 수정해요" : "새로운 BOM을 등록해요"}</DialogDescription>
          </DialogHeader>
        <div className="space-y-6">
          {/* 기본정보 */}
          <div className="grid grid-cols-2 gap-4">
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">
                품목 <span className="text-destructive">*</span>
              </Label>
              <div className="flex gap-2">
                <Input
                  className="h-9 flex-1"
                  value={masterForm.item_code ? `${masterForm.item_code} - ${masterForm.item_name}` : ""}
                  placeholder="품목을 검색해주세요"
                  readOnly
                  onClick={() => {
                    setItemSearchTarget("master");
                    setShowItemSearchModal(true);
                  }}
                />
                <Button
                  size="sm"
                  variant="outline"
                  className="h-9 px-3"
                  onClick={() => {
                    setItemSearchTarget("master");
                    setShowItemSearchModal(true);
                  }}
                >
                  <Search className="w-3.5 h-3.5" />
                </Button>
              </div>
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">
                BOM 유형 <span className="text-destructive">*</span>
              </Label>
              <Select value={masterForm.bom_type || ""} onValueChange={(v) => setMasterForm((prev) => ({ ...prev, bom_type: v }))}>
                <SelectTrigger className="h-9"><SelectValue placeholder="선택" /></SelectTrigger>
                <SelectContent>
                  {BOM_TYPE_OPTIONS.map((o) => (
                    <SelectItem key={o.code} value={o.code}>{o.label}</SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">기준수량</Label>
              <Input
                className="h-9"
                type="number"
                value={masterForm.base_qty}
                onChange={(e) => setMasterForm((prev) => ({ ...prev, base_qty: e.target.value }))}
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">단위</Label>
              <Input
                className="h-9"
                value={masterForm.unit}
                onChange={(e) => setMasterForm((prev) => ({ ...prev, unit: e.target.value }))}
                placeholder="EA"
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">
                버전 <span className="text-destructive">*</span>
              </Label>
              <Input
                className="h-9"
                value={masterForm.version}
                onChange={(e) => setMasterForm((prev) => ({ ...prev, version: e.target.value }))}
                placeholder="1.0"
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">상태</Label>
              <Select value={masterForm.status || "draft"} onValueChange={(v) => setMasterForm((prev) => ({ ...prev, status: v }))}>
                <SelectTrigger className="h-9"><SelectValue placeholder="선택" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value="draft">초안</SelectItem>
                  <SelectItem value="active">활성</SelectItem>
                </SelectContent>
              </Select>
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">
                유효 시작일 <span className="text-destructive">*</span>
              </Label>
              <Input
                type="date"
                className="h-9"
                value={masterForm.effective_date || ""}
                onChange={(e) => setMasterForm((prev) => ({ ...prev, effective_date: e.target.value }))}
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">유효 종료일</Label>
              <Input
                type="date"
                className="h-9"
                value={masterForm.expiry_date || ""}
                onChange={(e) => setMasterForm((prev) => ({ ...prev, expiry_date: e.target.value }))}
              />
            </div>
            <div className="flex flex-col gap-1.5 col-span-2">
              <Label className="text-xs font-medium">메모</Label>
              <Textarea
                className="min-h-[60px] resize-none"
                value={masterForm.remark}
                onChange={(e) => setMasterForm((prev) => ({ ...prev, remark: e.target.value }))}
                placeholder="메모를 입력해주세요"
              />
            </div>
          </div>

          {/* BOM 구성품목 */}
          <div>
            <div className="flex items-center justify-between mb-2">
              <h4 className="text-sm font-semibold">BOM 구성품목</h4>
              <Button
                size="sm"
                variant="outline"
                onClick={() => {
                  setItemSearchTarget("detail");
                  setShowItemSearchModal(true);
                }}
              >
                <Plus className="w-3.5 h-3.5 mr-1" />
                품목 추가
              </Button>
            </div>
            <div className="border rounded-lg overflow-hidden">
              <Table>
                <TableHeader>
                  <TableRow className="bg-muted/50">
                    <TableHead className="w-[40px] text-center">#</TableHead>
                    <TableHead className="w-[120px]">품목코드</TableHead>
                    <TableHead>품명</TableHead>
                    <TableHead className="w-[80px]">수량</TableHead>
                    <TableHead className="w-[70px]">단위</TableHead>
                    <TableHead className="w-[100px]">공정유형</TableHead>
                    <TableHead className="w-[80px]">손실율(%)</TableHead>
                    <TableHead className="w-[40px]" />
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {modalDetailRows.length === 0 ? (
                    <TableRow>
                      <TableCell colSpan={8} className="text-center py-8 text-muted-foreground text-[13px]">
                        구성품목을 추가해주세요
                      </TableCell>
                    </TableRow>
                  ) : (
                    modalDetailRows.map((row, idx) => (
                      <TableRow key={idx}>
                        <TableCell className="text-center text-muted-foreground text-[13px]">{idx + 1}</TableCell>
                        <TableCell className="font-mono text-[13px]">{row.item_number}</TableCell>
                        <TableCell className="text-[13px]">{row.item_name}</TableCell>
                        <TableCell>
                          <Input
                            className="h-7 w-[70px] text-xs"
                            type="number"
                            value={row.quantity}
                            onChange={(e) => {
                              const newRows = [...modalDetailRows];
                              newRows[idx].quantity = e.target.value;
                              setModalDetailRows(newRows);
                            }}
                          />
                        </TableCell>
                        <TableCell className="text-[13px]">{row.unit}</TableCell>
                        <TableCell>
                          <Input
                            className="h-7 w-[90px] text-xs"
                            value={row.process_type}
                            onChange={(e) => {
                              const newRows = [...modalDetailRows];
                              newRows[idx].process_type = e.target.value;
                              setModalDetailRows(newRows);
                            }}
                            placeholder="공정"
                          />
                        </TableCell>
                        <TableCell>
                          <Input
                            className="h-7 w-[70px] text-xs"
                            type="number"
                            value={row.loss_rate}
                            onChange={(e) => {
                              const newRows = [...modalDetailRows];
                              newRows[idx].loss_rate = e.target.value;
                              setModalDetailRows(newRows);
                            }}
                          />
                        </TableCell>
                        <TableCell>
                          <Button
                            size="sm"
                            variant="ghost"
                            className="h-7 w-7 p-0 text-destructive hover:text-destructive"
                            onClick={() => setModalDetailRows((prev) => prev.filter((_, i) => i !== idx))}
                          >
                            <X className="w-3.5 h-3.5" />
                          </Button>
                        </TableCell>
                      </TableRow>
                    ))
                  )}
                </TableBody>
              </Table>
            </div>
          </div>
        </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setIsModalOpen(false)} disabled={saving}>
              취소
            </Button>
            <Button onClick={handleSaveBom} disabled={saving}>
              {saving && <Loader2 className="w-3.5 h-3.5 animate-spin mr-1.5" />}
              {isEditMode ? "수정" : "등록"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ─── 품목 검색 모달 ──────────────────────── */}
      <Dialog open={showItemSearchModal} onOpenChange={setShowItemSearchModal}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>품목 검색</DialogTitle>
            <DialogDescription>품목코드 또는 품명으로 검색해주세요</DialogDescription>
          </DialogHeader>
          <div className="flex gap-2 mb-3">
            <Input
              className="h-9 flex-1"
              placeholder="품목코드 또는 품명 입력"
              value={itemSearchKeyword}
              onChange={(e) => setItemSearchKeyword(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && searchItems()}
            />
            <Button size="sm" className="h-9" onClick={searchItems} disabled={itemSearchLoading}>
              {itemSearchLoading ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Search className="w-3.5 h-3.5" />}
            </Button>
          </div>
          <div className="max-h-[300px] overflow-auto border rounded-lg">
            {itemSearchResults.length === 0 ? (
              <div className="flex flex-col items-center justify-center py-8 text-muted-foreground gap-1">
                <Search className="w-6 h-6 text-muted-foreground/40" />
                <p className="text-xs">검색어를 입력해주세요</p>
              </div>
            ) : (
              itemSearchResults.map((item) => {
                const badge = getItemTypeBadge(item.division);
                return (
                  <div
                    key={item.id}
                    className="flex items-center gap-3 px-3 py-2 border-b last:border-b-0 hover:bg-accent cursor-pointer transition-colors"
                    onClick={() => selectItem(item)}
                  >
                    <span className={cn("text-[10px] font-semibold px-1.5 py-0.5 rounded shrink-0", badge.className)}>
                      {badge.label}
                    </span>
                    <span className="font-mono text-[11px] text-muted-foreground">{item.item_number}</span>
                    <span className="text-xs">{item.item_name}</span>
                    <span className="ml-auto text-[11px] text-muted-foreground">{item.unit || ""}</span>
                  </div>
                );
              })
            )}
          </div>
        </DialogContent>
      </Dialog>

      {/* ─── 새 버전 생성 다이얼로그 ────────────── */}
      <Dialog open={showNewVersionDialog} onOpenChange={setShowNewVersionDialog}>
        <DialogContent className="max-w-sm">
          <DialogHeader>
            <DialogTitle>새 버전 생성</DialogTitle>
            <DialogDescription>현재 버전의 데이터를 복사하여 새 버전을 만들어요</DialogDescription>
          </DialogHeader>
          <div className="flex flex-col gap-1.5">
            <Label className="text-xs font-medium">버전명 (비워두면 자동 채번)</Label>
            <Input
              className="h-9"
              value={newVersionName}
              onChange={(e) => setNewVersionName(e.target.value)}
              placeholder="예: 2.0"
            />
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setShowNewVersionDialog(false)}>
              취소
            </Button>
            <Button onClick={handleCreateVersion}>
              <Plus className="w-3.5 h-3.5 mr-1" />
              생성
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ─── 이력 추가 다이얼로그 ───────────────── */}
      <Dialog open={showHistoryDialog} onOpenChange={setShowHistoryDialog}>
        <DialogContent className="max-w-sm">
          <DialogHeader>
            <DialogTitle>이력 추가</DialogTitle>
            <DialogDescription>BOM 변경 이력을 기록해요</DialogDescription>
          </DialogHeader>
          <div className="space-y-3">
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">
                변경 유형 <span className="text-destructive">*</span>
              </Label>
              <Select value={newHistory.change_type} onValueChange={(v) => setNewHistory((prev) => ({ ...prev, change_type: v }))}>
                <SelectTrigger className="h-9"><SelectValue placeholder="변경 유형 선택" /></SelectTrigger>
                <SelectContent>
                  <SelectItem value="design_change">설계 변경</SelectItem>
                  <SelectItem value="version_update">버전 업데이트</SelectItem>
                  <SelectItem value="material_change">자재 변경</SelectItem>
                  <SelectItem value="qty_change">수량 변경</SelectItem>
                  <SelectItem value="process_change">공정 변경</SelectItem>
                  <SelectItem value="etc">기타</SelectItem>
                </SelectContent>
              </Select>
            </div>
            <div className="flex flex-col gap-1.5">
              <Label className="text-xs font-medium">변경 내용</Label>
              <Textarea
                className="min-h-[80px] resize-none"
                value={newHistory.change_description}
                onChange={(e) => setNewHistory((prev) => ({ ...prev, change_description: e.target.value }))}
                placeholder="변경 내용을 입력해주세요"
              />
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setShowHistoryDialog(false)}>
              취소
            </Button>
            <Button onClick={handleAddHistory}>
              <Plus className="w-3.5 h-3.5 mr-1" />
              추가
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ─── 엑셀 업로드 다이얼로그 ────────────── */}
      <Dialog open={showExcelUpload} onOpenChange={setShowExcelUpload}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>BOM 엑셀 업로드</DialogTitle>
            <DialogDescription>
              {selectedBomId
                ? "선택한 BOM에 새 버전을 엑셀로 생성해요"
                : "엑셀 파일로 새 BOM을 생성해요"}
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-3">
            <div className="border-2 border-dashed rounded-lg p-6 text-center">
              <input
                type="file"
                accept=".xlsx,.xls"
                className="hidden"
                id="excel-file-input"
                onChange={(e) => setExcelFile(e.target.files?.[0] || null)}
              />
              <label htmlFor="excel-file-input" className="cursor-pointer">
                <Upload className="w-8 h-8 mx-auto mb-2 text-muted-foreground/40" />
                <p className="text-sm text-muted-foreground mb-1">
                  {excelFile ? excelFile.name : "클릭하여 파일을 선택해주세요"}
                </p>
                <p className="text-[10px] text-muted-foreground/60">.xlsx, .xls 형식</p>
              </label>
            </div>
            <div className="bg-muted/50 rounded-lg p-3 text-xs text-muted-foreground space-y-1">
              <p className="font-medium text-foreground">엑셀 형식 안내</p>
              <p>레벨 0: BOM 마스터 (최상위 품목)</p>
              <p>레벨 1: 직접 자품목</p>
              <p>레벨 2+: 자품목의 자품목</p>
              <p>필수 컬럼: level, item_number, quantity</p>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => { setShowExcelUpload(false); setExcelFile(null); }}>
              취소
            </Button>
            <Button onClick={handleExcelUpload} disabled={!excelFile || excelUploading}>
              {excelUploading && <Loader2 className="w-3.5 h-3.5 animate-spin mr-1.5" />}
              업로드
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {ConfirmDialogComponent}

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