"use client";

// 개발관리 > E-BOM 조회 (M4) — wace structureAscendingList.jsp 1:1
// 정전개(루트→리프) / 역전개(리프→부모) 토글. 동적 LEVEL 컬럼.
// 참조: docs/migration/development/02-ebom.md

import React, { useCallback, useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { PageHeader } from "@/components/common/PageHeader";
import { CompactFilterBar, CompactFilterField } from "@/components/common/CompactFilterBar";
import { Loader2, ChevronsRight, ChevronsLeft, FileSpreadsheet } from "lucide-react";
import { toast } from "sonner";
import { DataGrid, DataGridColumn } from "@/components/common/DataGrid";
import { devBomApi, BomTreeFilter, BomTreeRow } from "@/lib/api/devBom";
import { DevPartSelect } from "@/components/development/DevPartSelect";
import { SmartSelect, SmartSelectOption } from "@/components/common/SmartSelect";

const LEVEL_OPTIONS: SmartSelectOption[] = [
  { code: "1", label: "1레벨" },
  { code: "2", label: "2레벨" },
  { code: "3", label: "3레벨" },
  { code: "4", label: "4레벨" },
  { code: "5", label: "5레벨" },
];
import { PartDetailDialog } from "@/components/development/PartDetailDialog";
import { exportToExcel } from "@/lib/utils/excelExport";

type Direction = "ascending" | "descending";

const EMPTY_FILTER: BomTreeFilter = {
  search_part_no: "", search_part_name: "", search_level: "",
};

export default function EbomSearchPage() {
  const [filter, setFilter] = useState<BomTreeFilter>(EMPTY_FILTER);
  const [direction, setDirection] = useState<Direction>("ascending");
  const [rows, setRows] = useState<BomTreeRow[]>([]);
  const [maxLevel, setMaxLevel] = useState(0);
  const [loading, setLoading] = useState(false);
  const [exporting, setExporting] = useState(false);
  // 토글 접힘 상태: 접힌 부모 행의 child_objid 집합
  const [collapsedChildIds, setCollapsedChildIds] = useState<Set<string>>(new Set());
  // PART 상세 다이얼로그
  const [partDetailOpen, setPartDetailOpen] = useState(false);
  const [partDetailObjid, setPartDetailObjid] = useState<string | null>(null);

  const runQuery = useCallback(async (dir: Direction) => {
    setLoading(true);
    try {
      const fn = dir === "ascending" ? devBomApi.ascending : devBomApi.descending;
      const res = await fn(filter);
      setRows(res.rows ?? []);
      setMaxLevel(Number(res.max_level) || 0);
      setDirection(dir);
      setCollapsedChildIds(new Set());  // 새 조회 시 모두 펼침
    } catch (e: any) {
      toast.error(e?.response?.data?.message ?? e?.message ?? "조회 실패");
    } finally {
      setLoading(false);
    }
  }, [filter]);

  // wace structureAscending/DescendingListExcel.jsp 1:1 — 현재 검색 조건 그대로 .xlsx 다운로드
  const downloadExcel = useCallback(async (dir: Direction) => {
    setExporting(true);
    try {
      const fn = dir === "ascending" ? devBomApi.excelAscending : devBomApi.excelDescending;
      const { blob, fileName } = await fn(filter);
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url; a.download = fileName;
      document.body.appendChild(a); a.click();
      a.remove(); URL.revokeObjectURL(url);
      toast.success(`${fileName} 다운로드`);
    } catch (e: any) {
      toast.error(e?.response?.data?.message ?? e?.message ?? "엑셀 다운로드 실패");
    } finally {
      setExporting(false);
    }
  }, [filter]);

  // 자식 보유 행 식별 (다른 행이 parent_objid 로 참조하는 child_objid 집합)
  const hasChildSet = useMemo(() => {
    const s = new Set<string>();
    for (const r of rows) if (r.parent_objid) s.add(String(r.parent_objid));
    return s;
  }, [rows]);

  // 각 행의 ancestor child_objid 체인 (collapsed 검사용)
  const ancestorsByChildId = useMemo(() => {
    const byChild = new Map<string, BomTreeRow>();
    for (const r of rows) if (r.child_objid) byChild.set(String(r.child_objid), r);
    const result = new Map<string, string[]>();
    for (const r of rows) {
      if (!r.child_objid) continue;
      const list: string[] = [];
      let cur: string | null = r.parent_objid ? String(r.parent_objid) : null;
      const guard = new Set<string>();
      while (cur && !guard.has(cur)) {
        list.push(cur);
        guard.add(cur);
        const p = byChild.get(cur);
        cur = p?.parent_objid ? String(p.parent_objid) : null;
      }
      result.set(String(r.child_objid), list);
    }
    return result;
  }, [rows]);

  // 토글 클릭 핸들러 — 부모 행의 child_objid 를 collapsed Set 에 toggle
  const toggleCollapse = useCallback((row: any) => {
    const childId = row.child_objid ? String(row.child_objid) : "";
    if (!childId || !hasChildSet.has(childId)) return;
    setCollapsedChildIds((prev) => {
      const next = new Set(prev);
      if (next.has(childId)) next.delete(childId);
      else next.add(childId);
      return next;
    });
  }, [hasChildSet]);

  // 운영판 structureAscendingList.jsp 1:1
  //  - 첫 컬럼: -/+ 토글 (자식 있는 행만)
  //  - L1..LMaxLevel 컬럼은 해당 레벨에만 "*" 표시 (품번 표시 X)
  //  - 별도 품번 컬럼에 모든 행 part_no
  //  - 3D/2D/PDF 폴더 아이콘 (renderType: "folder")
  const columns: DataGridColumn[] = useMemo(() => {
    const levelCols: DataGridColumn[] = [];
    for (let i = 1; i <= Math.max(1, maxLevel); i++) {
      levelCols.push({
        key: `__lev_${i}`,
        label: String(i),
        width: "w-[36px]",
        align: "center",
      });
    }
    return [
      { key: "__toggle",                label: "",           width: "w-[36px]", align: "center",
        onClick: (row: any) => toggleCollapse(row) },
      ...levelCols,
      // 품번 셀 클릭 → PART 상세 (wace partMngDetailPopUp 1:1). row.part_no = part_mng.objid 임.
      { key: "pm_part_no",              label: "품번",       width: "w-[160px]",
        onClick: (row: any) => {
          if (row.part_no) {
            setPartDetailObjid(String(row.part_no));
            setPartDetailOpen(true);
          }
        } },
      { key: "pm_part_name",            label: "품명",       minWidth: "min-w-[200px]" },
      { key: "qty",                     label: "수량",       width: "w-[70px]", align: "right", formatNumber: true },
      { key: "p_qty",                   label: "항목수량",   width: "w-[80px]", align: "right", formatNumber: true },
      { key: "cu01_cnt",                label: "3D",         width: "w-[70px]", align: "center", renderType: "folder" },
      { key: "cu02_cnt",                label: "2D",         width: "w-[70px]", align: "center", renderType: "folder" },
      { key: "cu03_cnt",                label: "PDF",        width: "w-[70px]", align: "center", renderType: "folder" },
      { key: "material",                label: "재료",       width: "w-[100px]" },
      { key: "heat_treatment_hardness", label: "열처리경도", width: "w-[110px]" },
      { key: "heat_treatment_method",   label: "열처리방법", width: "w-[110px]" },
      { key: "surface_treatment",       label: "표면처리",   width: "w-[100px]" },
      { key: "maker",                   label: "메이커",     width: "w-[110px]" },
      { key: "part_type_title",         label: "범주 이름",  width: "w-[100px]", align: "center" },
      { key: "remark",                  label: "비고",       minWidth: "min-w-[140px]" },
    ];
  }, [maxLevel, toggleCollapse]);

  // 가시 행: collapsed 부모를 ancestor 로 가진 행은 hide
  // 행 데이터: __toggle 셀 + __lev_{i} "*" 표시
  const gridData = useMemo(() => {
    return rows
      .filter((r) => {
        if (!r.child_objid) return true;
        const ancestors = ancestorsByChildId.get(String(r.child_objid)) ?? [];
        return !ancestors.some((a) => collapsedChildIds.has(a));
      })
      .map((r, i) => {
        const expanded: any = { ...r };
        const lev = Number(r.lev ?? 0);
        for (let j = 1; j <= Math.max(1, maxLevel); j++) {
          expanded[`__lev_${j}`] = lev === j ? "*" : "";
        }
        const childId = r.child_objid ? String(r.child_objid) : "";
        const hasChild = childId && hasChildSet.has(childId);
        expanded.__toggle = hasChild ? (collapsedChildIds.has(childId) ? "+" : "−") : "";
        // DataGrid row key — child_objid 우선, 없으면 인덱스 fallback
        expanded.id = childId || `bom-${i}`;
        return expanded;
      });
  }, [rows, maxLevel, hasChildSet, ancestorsByChildId, collapsedChildIds]);

  // ─── 하단 통계 ──────────────────────────────────────────────
  const treeSummary = useMemo(() => {
    const intFmt = (n: number) => n.toLocaleString();
    const qtySum = gridData.reduce((acc, r: any) => acc + Number(r.qty || 0), 0);
    const pQtySum = gridData.reduce((acc, r: any) => acc + Number(r.p_qty || 0), 0);
    return [
      { label: "모드", value: direction === "ascending" ? "정전개" : "역전개" },
      { label: "표시 행", value: intFmt(gridData.length), suffix: "행" },
      { label: "원본 행", value: intFmt(rows.length), suffix: "행" },
      { label: "MAX_LEVEL", value: String(maxLevel) },
      { label: "수량 합계", value: intFmt(qtySum) },
      { label: "항목수량 합계", value: intFmt(pQtySum) },
    ];
  }, [gridData, rows.length, maxLevel, direction]);

  return (
    <div className="flex h-full flex-col overflow-hidden p-2 gap-2">
      <PageHeader
        onReset={() => { setFilter(EMPTY_FILTER); setRows([]); setMaxLevel(0); }}
        actions={
        <>
          <Button size="sm" onClick={() => runQuery("ascending")} disabled={loading}
                  variant={direction === "ascending" ? "default" : "secondary"}
                  className="h-8 gap-1 text-xs">
            {loading && direction === "ascending"
              ? <Loader2 className="h-3.5 w-3.5 animate-spin" />
              : <ChevronsRight className="h-3.5 w-3.5" />}
            정전개 조회
          </Button>
          <Button size="sm" onClick={() => runQuery("descending")} disabled={loading}
                  variant={direction === "descending" ? "default" : "secondary"}
                  className="h-8 gap-1 text-xs">
            {loading && direction === "descending"
              ? <Loader2 className="h-3.5 w-3.5 animate-spin" />
              : <ChevronsLeft className="h-3.5 w-3.5" />}
            역전개 조회
          </Button>
          <Button size="sm" variant="outline" className="h-8 gap-1 text-xs" onClick={() => downloadExcel("ascending")} disabled={exporting}>
            {exporting ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <FileSpreadsheet className="h-3.5 w-3.5" />}
            정전개 엑셀
          </Button>
          <Button size="sm" variant="outline" className="h-8 gap-1 text-xs" onClick={() => downloadExcel("descending")} disabled={exporting}>
            {exporting ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <FileSpreadsheet className="h-3.5 w-3.5" />}
            역전개 엑셀
          </Button>
        </>
      } />

      {/* 운영판 wace structureAscendingList.jsp 1:1 — 노출 검색 필드 3개
          (고객사/프로젝트번호/유닛명 은 운영판에서도 주석 처리되어 노출 안 됨) */}
      <CompactFilterBar
        totalText={<>모드: {direction === "ascending" ? "정전개 (루트 → 리프)" : "역전개 (리프 → 부모)"} · {rows.length.toLocaleString()}행 · MAX_LEVEL = {maxLevel}</>}
      >
        <CompactFilterField label="품번" width={200}>
          <DevPartSelect mode="partNo"
                         value={filter.search_part_no ?? ""}
                         onValueChange={(v, row) => setFilter((prev) => ({
                           ...prev,
                           search_part_no: v,
                           // 품번 선택 시 품명 자동 채움 (wace select2-part 1:1)
                           search_part_name: row?.part_name ?? prev.search_part_name,
                         }))} />
        </CompactFilterField>
        <CompactFilterField label="품명" width={220}>
          <DevPartSelect mode="partName"
                         value={filter.search_part_name ?? ""}
                         onValueChange={(v, row) => setFilter((prev) => ({
                           ...prev,
                           search_part_name: v,
                           // 품명 선택 시 품번 자동 채움
                           search_part_no: row?.part_no ?? prev.search_part_no,
                         }))} />
        </CompactFilterField>
        <CompactFilterField label="표시 레벨" width={120}>
          <SmartSelect
            options={LEVEL_OPTIONS}
            value={String(filter.search_level ?? "")}
            onValueChange={(v) => setFilter({ ...filter, search_level: v })}
            placeholder="전체"
          />
        </CompactFilterField>
      </CompactFilterBar>

      {direction === "descending" && (
        <div className="text-xs text-amber-600 px-2">
          역전개는 품번 또는 품명 검색 조건이 필요합니다.
        </div>
      )}

      <DataGrid
        columns={columns}
        data={gridData}
        loading={loading}
        showRowNumber
        emptyMessage="조건에 맞는 BOM이 없습니다."
        gridId={`development-ebom-search-${direction}`}
        showColumnSettings
        paginationStyle="range"
        pageSizeOptions={[20, 50, 100, 200, 500]}
        defaultPageSize={100}
        summaryStats={treeSummary}
        onRefresh={() => runQuery(direction)}
        onDownload={() => downloadExcel(direction)}
        showChart
      />

      <PartDetailDialog
        open={partDetailOpen}
        onOpenChange={setPartDetailOpen}
        objid={partDetailObjid}
      />
    </div>
  );
}

