"use client";

import React, { useState, useEffect, useCallback, useMemo, useRef } from "react";
import {
  Truck,
  DollarSign,
  FileText,
  MapPin,
  Car,
  Plus,
  Trash2,
  Download,
  Pencil,
  RefreshCw,
  Inbox,
  Loader2,
  Settings2,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
} from "@/components/ui/dialog";
import { Checkbox } from "@/components/ui/checkbox";
import { useConfirmDialog } from "@/components/common/ConfirmDialog";
import { apiClient } from "@/lib/api/client";
import { useAuth } from "@/hooks/useAuth";
import { toast } from "sonner";
import { exportToExcel } from "@/lib/utils/excelExport";
import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule";
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";

// ========== 타입 & 상수 ==========
type TabKey = "carrier" | "cost" | "contract" | "route" | "vehicle";

interface TabColumnDef {
  key: string;
  label: string;
  width?: string;
  align?: "left" | "center" | "right";
  formatNumber?: boolean;
}

interface FormFieldDef {
  key: string;
  label: string;
  type: "text" | "number" | "select" | "smartselect" | "date";
  required?: boolean;
  referenceKey?: "carrier" | "route";
  categoryKey?: string;
  options?: { value: string; label: string }[];
  placeholder?: string;
}

interface TabConfig {
  key: TabKey;
  label: string;
  icon: React.ReactNode;
  tableName: string;
  columns: TabColumnDef[];
  formFields: FormFieldDef[];
  defaultSortColumn: string;
}

const TAB_CONFIGS: TabConfig[] = [
  {
    key: "carrier",
    label: "운송업체",
    icon: <Truck className="h-3.5 w-3.5" />,
    tableName: "carrier_mng",
    defaultSortColumn: "carrier_code",
    columns: [
      { key: "carrier_code", label: "업체코드", width: "120px" },
      { key: "carrier_name", label: "업체명", width: "160px" },
      { key: "carrier_type", label: "업체유형", width: "100px" },
      { key: "contact_person", label: "담당자", width: "100px" },
      { key: "contact_phone", label: "연락처", width: "130px" },
      { key: "email", label: "이메일", width: "180px" },
      { key: "address", label: "주소", width: "220px" },
      { key: "rating", label: "등급", width: "70px", align: "center" },
      { key: "status", label: "상태", width: "80px", align: "center" },
    ],
    formFields: [
      { key: "carrier_code", label: "업체코드", type: "text", required: true, placeholder: "업체코드를 입력해주세요" },
      { key: "carrier_name", label: "업체명", type: "text", required: true, placeholder: "업체명을 입력해주세요" },
      { key: "carrier_type", label: "업체유형", type: "select", required: true, categoryKey: "carrier_mng:carrier_type", placeholder: "업체유형을 선택해주세요" },
      { key: "contact_person", label: "담당자", type: "text", placeholder: "담당자명" },
      { key: "contact_phone", label: "연락처", type: "text", placeholder: "예: 02-1234-5678" },
      { key: "email", label: "이메일", type: "text", placeholder: "email@example.com" },
      { key: "address", label: "주소", type: "text", placeholder: "주소를 입력해주세요" },
      { key: "rating", label: "등급", type: "select", categoryKey: "carrier_mng:rating", placeholder: "등급을 선택해주세요" },
      { key: "status", label: "상태", type: "select", categoryKey: "carrier_mng:status", placeholder: "상태를 선택해주세요" },
    ],
  },
  {
    key: "cost",
    label: "물류비",
    icon: <DollarSign className="h-3.5 w-3.5" />,
    tableName: "logistics_cost_mng",
    defaultSortColumn: "carrier_code",
    columns: [
      { key: "carrier_code", label: "운송업체", width: "120px" },
      { key: "route_code", label: "구간코드", width: "120px" },
      { key: "route_name", label: "구간명", width: "160px" },
      { key: "base_fee", label: "기본요금", width: "110px", align: "right", formatNumber: true },
      { key: "unit", label: "단위", width: "70px", align: "center" },
      { key: "unit_fee", label: "단가", width: "110px", align: "right", formatNumber: true },
      { key: "min_weight", label: "최소중량", width: "100px", align: "right", formatNumber: true },
      { key: "max_weight", label: "최대중량", width: "100px", align: "right", formatNumber: true },
      { key: "delivery_days", label: "배송일수", width: "80px", align: "center" },
    ],
    formFields: [
      { key: "carrier_code", label: "운송업체", type: "smartselect", required: true, referenceKey: "carrier" },
      { key: "route_code", label: "배송구간", type: "smartselect", required: true, referenceKey: "route" },
      { key: "base_fee", label: "기본요금", type: "number", placeholder: "0" },
      { key: "unit", label: "단위", type: "text", placeholder: "kg, 건 등" },
      { key: "unit_fee", label: "단가", type: "number", placeholder: "0" },
      { key: "min_weight", label: "최소중량", type: "number", placeholder: "0" },
      { key: "max_weight", label: "최대중량", type: "number", placeholder: "0" },
      { key: "delivery_days", label: "배송일수", type: "number", placeholder: "0" },
    ],
  },
  {
    key: "contract",
    label: "계약서",
    icon: <FileText className="h-3.5 w-3.5" />,
    tableName: "carrier_contract_mng",
    defaultSortColumn: "contract_no",
    columns: [
      { key: "contract_no", label: "계약번호", width: "130px" },
      { key: "carrier_code", label: "운송업체", width: "120px" },
      { key: "contract_start_date", label: "시작일", width: "110px" },
      { key: "contract_end_date", label: "종료일", width: "110px" },
      { key: "contract_amount", label: "계약금액", width: "130px", align: "right", formatNumber: true },
      { key: "contact_person", label: "담당자", width: "100px" },
      { key: "status", label: "상태", width: "80px", align: "center" },
    ],
    formFields: [
      { key: "contract_no", label: "계약번호", type: "text", required: true, placeholder: "계약번호를 입력해주세요" },
      { key: "carrier_code", label: "운송업체", type: "smartselect", required: true, referenceKey: "carrier" },
      { key: "contract_start_date", label: "시작일", type: "date", required: true },
      { key: "contract_end_date", label: "종료일", type: "date", required: true },
      { key: "contract_amount", label: "계약금액", type: "number", placeholder: "0" },
      { key: "contact_person", label: "담당자", type: "text", placeholder: "담당자명을 입력해주세요" },
      { key: "status", label: "상태", type: "select", categoryKey: "carrier_contract_mng:status", placeholder: "상태를 선택해주세요" },
    ],
  },
  {
    key: "route",
    label: "배송구간",
    icon: <MapPin className="h-3.5 w-3.5" />,
    tableName: "delivery_route_mng",
    defaultSortColumn: "route_code",
    columns: [
      { key: "route_code", label: "구간코드", width: "120px" },
      { key: "route_name", label: "구간명", width: "160px" },
      { key: "departure", label: "출발지", width: "120px" },
      { key: "destination", label: "도착지", width: "120px" },
      { key: "distance_km", label: "거리(km)", width: "100px", align: "right", formatNumber: true },
      { key: "avg_time_hours", label: "평균시간(h)", width: "100px", align: "right" },
      { key: "route_type", label: "구간유형", width: "100px" },
      { key: "status", label: "상태", width: "80px", align: "center" },
    ],
    formFields: [
      { key: "route_code", label: "구간코드", type: "text", required: true, placeholder: "구간코드를 입력해주세요" },
      { key: "departure", label: "출발지", type: "text", required: true, placeholder: "출발지" },
      { key: "destination", label: "도착지", type: "text", required: true, placeholder: "도착지" },
      { key: "distance_km", label: "거리(km)", type: "number", placeholder: "0" },
      { key: "avg_time_hours", label: "평균시간(h)", type: "number", placeholder: "0" },
      { key: "route_type", label: "구간유형", type: "select", categoryKey: "delivery_route_mng:route_type", placeholder: "유형을 선택해주세요" },
      { key: "status", label: "상태", type: "select", categoryKey: "delivery_route_mng:status", placeholder: "상태를 선택해주세요" },
    ],
  },
  {
    key: "vehicle",
    label: "차량",
    icon: <Car className="h-3.5 w-3.5" />,
    tableName: "carrier_vehicle_mng",
    defaultSortColumn: "vehicle_code",
    columns: [
      { key: "vehicle_code", label: "차량코드", width: "120px" },
      { key: "vehicle_number", label: "차량번호", width: "120px" },
      { key: "vehicle_type", label: "차량유형", width: "100px" },
      { key: "carrier_code", label: "운송업체", width: "120px" },
      { key: "load_capacity_kg", label: "적재용량(kg)", width: "120px", align: "right", formatNumber: true },
      { key: "driver_name", label: "운전자", width: "100px" },
      { key: "last_maintenance_date", label: "최종정비일", width: "110px" },
      { key: "status", label: "상태", width: "80px", align: "center" },
    ],
    formFields: [
      { key: "vehicle_code", label: "차량코드", type: "text", required: true, placeholder: "차량코드를 입력해주세요" },
      { key: "vehicle_number", label: "차량번호", type: "text", required: true, placeholder: "12가 3456" },
      { key: "vehicle_type", label: "차량유형", type: "select", required: true, categoryKey: "carrier_vehicle_mng:vehicle_type", placeholder: "차량유형을 선택해주세요" },
      { key: "carrier_code", label: "운송업체", type: "smartselect", required: true, referenceKey: "carrier" },
      { key: "load_capacity_kg", label: "적재용량(kg)", type: "number", placeholder: "0" },
      { key: "driver_name", label: "운전자", type: "text", placeholder: "운전자명" },
      { key: "last_maintenance_date", label: "최종정비일", type: "date" },
      { key: "status", label: "상태", type: "select", categoryKey: "carrier_vehicle_mng:status", placeholder: "상태를 선택해주세요" },
    ],
  },
];

// 카테고리 계층 평탄화
function flattenCategories(items: any[]): { value: string; label: string }[] {
  const result: { value: string; label: string }[] = [];
  function walk(arr: any[]) {
    for (const item of arr) {
      const val = item.valueCode || item.value || item.name;
      const lbl = item.valueLabel || item.label || item.name || val;
      if (val) {
        result.push({ value: val, label: lbl });
      }
      if (item.children?.length) walk(item.children);
    }
  }
  walk(items);
  return result;
}

// 채번 대상 필드 매핑: tableName → 코드 필드 key
const NUMBERING_FIELD_MAP: Record<string, string> = {
  carrier_mng: "carrier_code",
  delivery_route_mng: "route_code",
  carrier_vehicle_mng: "vehicle_code",
};

// ========== 메인 컴포넌트 ==========
export default function LogisticsInfoPage() {
  const { user } = useAuth();
  const { confirm, ConfirmDialogComponent } = useConfirmDialog();

  // 탭 상태
  const [activeTab, setActiveTab] = useState<TabKey>("carrier");

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

  // 탭별 독립 상태
  const [tabData, setTabData] = useState<Record<TabKey, any[]>>({
    carrier: [], cost: [], contract: [], route: [], vehicle: [],
  });
  const [tabLoading, setTabLoading] = useState<Record<TabKey, boolean>>({
    carrier: false, cost: false, contract: false, route: false, vehicle: false,
  });
  const [tabChecked, setTabChecked] = useState<Record<TabKey, string[]>>({
    carrier: [], cost: [], contract: [], route: [], vehicle: [],
  });

  // FK 참조 데이터 (캐싱)
  const [carrierOptions, setCarrierOptions] = useState<{ code: string; label: string }[]>([]);
  const [routeOptions, setRouteOptions] = useState<{ code: string; label: string }[]>([]);

  // 카테고리 옵션 캐시
  const [categoryOptions, setCategoryOptions] = useState<Record<string, { value: string; label: string }[]>>({});
  const loadedCategories = useRef(new Set<string>());

  // 모달 상태
  const [formOpen, setFormOpen] = useState(false);
  const [editMode, setEditMode] = useState(false);
  const [editId, setEditId] = useState<string | null>(null);
  const [formData, setFormData] = useState<Record<string, any>>({});

  // 채번 시스템
  const [numberingRuleId, setNumberingRuleId] = useState<string | null>(null);
  const [previewCode, setPreviewCode] = useState<string | null>(null);

  // 테이블 설정 (탭별)
  const tsCarrier = useTableSettings("c16-logistics-carrier", TAB_CONFIGS[0].tableName, TAB_CONFIGS[0].columns);
  const tsCost = useTableSettings("c16-logistics-cost", TAB_CONFIGS[1].tableName, TAB_CONFIGS[1].columns);
  const tsContract = useTableSettings("c16-logistics-contract", TAB_CONFIGS[2].tableName, TAB_CONFIGS[2].columns);
  const tsRoute = useTableSettings("c16-logistics-route", TAB_CONFIGS[3].tableName, TAB_CONFIGS[3].columns);
  const tsVehicle = useTableSettings("c16-logistics-vehicle", TAB_CONFIGS[4].tableName, TAB_CONFIGS[4].columns);
  const tsMap: Record<TabKey, typeof tsCarrier> = { carrier: tsCarrier, cost: tsCost, contract: tsContract, route: tsRoute, vehicle: tsVehicle };
  const activeTs = tsMap[activeTab];

  const activeConfig = useMemo(
    () => TAB_CONFIGS.find((c) => c.key === activeTab)!,
    [activeTab]
  );

  // 컬럼 가시성 헬퍼
  const getVisibleColumns = (tabKey: TabKey) => tsMap[tabKey].visibleColumns;

  // 클라이언트 사이드 필터링
  const filteredData = useMemo(() => {
    const data = tabData[activeTab];
    if (searchFilters.length === 0) return data;
    return data.filter((row) =>
      searchFilters.every((f) => {
        if (!f.value) return true;
        const kw = f.value.toLowerCase();
        if (f.columnName) {
          return String(row[f.columnName] ?? "").toLowerCase().includes(kw);
        }
        return Object.values(row).some((v) => String(v ?? "").toLowerCase().includes(kw));
      })
    );
  }, [tabData, activeTab, searchFilters]);

  // FK 참조 데이터 로드
  const loadReferences = useCallback(async () => {
    try {
      const [carrierRes, routeRes] = await Promise.all([
        apiClient.post("/table-management/tables/carrier_mng/data", {
          page: 1, size: 0, autoFilter: true,
          sort: { columnName: "carrier_code", order: "asc" },
        }),
        apiClient.post("/table-management/tables/delivery_route_mng/data", {
          page: 1, size: 0, autoFilter: true,
          sort: { columnName: "route_code", order: "asc" },
        }),
      ]);
      const carriers = carrierRes.data?.data?.data || carrierRes.data?.data?.rows || [];
      setCarrierOptions(
        carriers.map((r: any) => ({
          code: r.carrier_code || "",
          label: `${r.carrier_code} - ${r.carrier_name || ""}`,
        }))
      );
      const routes = routeRes.data?.data?.data || routeRes.data?.data?.rows || [];
      setRouteOptions(
        routes.map((r: any) => ({
          code: r.route_code || "",
          label: `${r.route_code} - ${r.route_name || ""}`,
        }))
      );
    } catch {
      // FK 참조 로드 실패 시 무시
    }
  }, []);

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

  // 참조 코드 → 업체명/구간명 변환 (목록 셀용 — 코드 제외, 업체명만 표시)
  const getRefName = useCallback((refKey: "carrier" | "route", code: string): string => {
    if (!code) return "-";
    const opts = refKey === "carrier" ? carrierOptions : routeOptions;
    const lbl = opts.find((o) => o.code === code)?.label || "";
    const parts = String(lbl).split(" - ");
    return parts.length > 1 ? parts.slice(1).join(" - ") : code;
  }, [carrierOptions, routeOptions]);

  // 카테고리 옵션 로드 (관리자 계정일 때 filterCompanyCode 미제공 시 "*" 스코프로 빈 결과 반환됨)
  const loadCategoryOptions = useCallback(async (tableColumn: string) => {
    if (loadedCategories.current.has(tableColumn)) return;
    loadedCategories.current.add(tableColumn);
    const [tableName, columnName] = tableColumn.split(":");
    try {
      const res = await apiClient.get(
        `/table-categories/${tableName}/${columnName}/values?filterCompanyCode=COMPANY_16`
      );
      const data = res.data?.data || [];
      setCategoryOptions((prev) => ({
        ...prev,
        [tableColumn]: data.length > 0 ? flattenCategories(data) : [],
      }));
    } catch {
      setCategoryOptions((prev) => ({ ...prev, [tableColumn]: [] }));
    }
  }, []);

  // 활성 탭의 카테고리 로드
  useEffect(() => {
    const config = TAB_CONFIGS.find((c) => c.key === activeTab);
    if (!config) return;
    config.formFields.forEach((f) => {
      if (f.categoryKey) loadCategoryOptions(f.categoryKey);
    });
  }, [activeTab, loadCategoryOptions]);

  // 데이터 조회
  const fetchTabData = useCallback(async (tab: TabKey) => {
    const config = TAB_CONFIGS.find((c) => c.key === tab);
    if (!config) return;
    setTabLoading((prev) => ({ ...prev, [tab]: true }));
    try {
      const res = await apiClient.post(
        `/table-management/tables/${config.tableName}/data`,
        {
          page: 1, size: 0, autoFilter: true,
          sort: { columnName: config.defaultSortColumn, order: "asc" },
        }
      );
      const rows = res.data?.data?.data || res.data?.data?.rows || [];
      setTabData((prev) => ({ ...prev, [tab]: rows }));
    } catch {
      toast.error("데이터를 불러오는 데 실패했어요.");
      setTabData((prev) => ({ ...prev, [tab]: [] }));
    } finally {
      setTabLoading((prev) => ({ ...prev, [tab]: false }));
    }
  }, []);

  // 마운트 시 5개 탭 전체 로드(카운트 즉시 정확), 이후 탭 전환 시 활성 탭만 재로드
  // 두 useEffect를 분리하면 mount 시 동시 실행으로 race condition 발생 → 단일 useEffect + ref 가드
  const isInitialLoadRef = useRef(true);
  useEffect(() => {
    if (isInitialLoadRef.current) {
      isInitialLoadRef.current = false;
      TAB_CONFIGS.forEach((c) => fetchTabData(c.key));
    } else {
      fetchTabData(activeTab);
    }
  }, [activeTab, fetchTabData]);

  // 탭 변경
  const handleTabChange = useCallback((tab: string) => {
    setActiveTab(tab as TabKey);
    setSearchFilters([]);
  }, []);

  // 등록 모달 열기
  const handleOpenAdd = useCallback(async () => {
    setEditMode(false);
    setEditId(null);
    setFormData({});
    setPreviewCode(null);
    setNumberingRuleId(null);
    setFormOpen(true);

    // 현재 탭의 채번 규칙 조회
    const config = TAB_CONFIGS.find((c) => c.key === activeTab);
    if (!config) return;
    const codeField = NUMBERING_FIELD_MAP[config.tableName];
    if (!codeField) return; // 채번 대상이 아닌 탭

    try {
      const ruleRes = await apiClient.get(
        `/numbering-rules/by-column/${config.tableName}/${codeField}`
      );
      const ruleData = ruleRes.data;
      if (ruleData?.success && ruleData?.data?.ruleId) {
        const ruleId = ruleData.data.ruleId;
        setNumberingRuleId(ruleId);
        const previewRes = await previewNumberingCode(ruleId);
        if (previewRes.success && previewRes.data?.generatedCode) {
          setPreviewCode(previewRes.data.generatedCode);
        }
      }
    } catch {
      // 채번 규칙 없으면 무시 — 사용자가 직접 입력
    }
  }, [activeTab]);

  // 수정 모달 열기
  const handleOpenEdit = useCallback((row: any) => {
    setEditMode(true);
    setEditId(row.id ? String(row.id) : null);
    setFormData({ ...row });
    setFormOpen(true);
  }, []);

  // 저장
  const handleSave = useCallback(async () => {
    const config = TAB_CONFIGS.find((c) => c.key === activeTab);
    if (!config) return;

    // 필수값 검증 (등록 모드에서 채번 대상 코드 필드는 자동 할당이므로 스킵)
    const numberingCodeField = NUMBERING_FIELD_MAP[config.tableName];
    for (const field of config.formFields) {
      if (!editMode && numberingRuleId && field.key === numberingCodeField) continue;
      if (field.required && !formData[field.key]?.toString().trim()) {
        toast.error(`${field.label}은(는) 필수 입력이에요.`);
        return;
      }
    }

    try {
      // 배송구간: 출발지→도착지 로 구간명 자동 생성
      const saveData = { ...formData };
      if (activeTab === "route" && saveData.departure && saveData.destination) {
        saveData.route_name = `${saveData.departure}→${saveData.destination}`;
      }

      if (editMode && editId) {
        await apiClient.put(`/table-management/tables/${config.tableName}/edit`, {
          originalData: { id: editId },
          updatedData: saveData,
        });
        toast.success("수정이 완료되었어요.");
      } else {
        // 채번 규칙이 있으면 allocate로 실제 코드 할당
        const codeField = NUMBERING_FIELD_MAP[config.tableName];
        if (codeField && numberingRuleId) {
          const allocRes = await allocateNumberingCode(numberingRuleId);
          if (allocRes.success && allocRes.data?.generatedCode) {
            saveData[codeField] = allocRes.data.generatedCode;
          } else {
            toast.error("채번 코드 할당에 실패했습니다.");
            return;
          }
        }

        await apiClient.post(
          `/table-management/tables/${config.tableName}/add`,
          { id: crypto.randomUUID(), ...saveData }
        );
        toast.success("등록이 완료되었어요.");
      }
      setFormOpen(false);
      fetchTabData(activeTab);
      // FK 참조 테이블 변경 시 캐시 갱신
      if (activeTab === "carrier" || activeTab === "route") {
        loadReferences();
      }
    } catch (err: any) {
      toast.error(err?.response?.data?.message || "저장에 실패했어요.");
    }
  }, [activeTab, editMode, editId, formData, fetchTabData, loadReferences, numberingRuleId]);

  // 삭제
  const handleDelete = useCallback(async () => {
    const config = TAB_CONFIGS.find((c) => c.key === activeTab);
    if (!config) return;
    const ids = tabChecked[activeTab];
    if (ids.length === 0) {
      toast.error("삭제할 항목을 선택해주세요.");
      return;
    }
    const ok = await confirm(`선택한 ${ids.length}건을 삭제할까요?`, {
      description: "삭제된 데이터는 복구할 수 없어요.",
      variant: "destructive",
    });
    if (!ok) return;
    try {
      await apiClient.delete(
        `/table-management/tables/${config.tableName}/delete`,
        { data: ids.map((id) => ({ id })) }
      );
      toast.success(`${ids.length}건이 삭제되었어요.`);
      setTabChecked((prev) => ({ ...prev, [activeTab]: [] }));
      fetchTabData(activeTab);
      if (activeTab === "carrier" || activeTab === "route") {
        loadReferences();
      }
    } catch {
      toast.error("삭제에 실패했어요.");
    }
  }, [activeTab, tabChecked, confirm, fetchTabData, loadReferences]);

  // 엑셀 다운로드 (필터된 데이터 기준)
  const handleExcelDownload = useCallback(async () => {
    const config = TAB_CONFIGS.find((c) => c.key === activeTab);
    if (!config) return;
    if (filteredData.length === 0) {
      toast.error("다운로드할 데이터가 없어요.");
      return;
    }
    const exportData = filteredData.map((row) => {
      const obj: Record<string, any> = {};
      config.columns.forEach((col) => {
        obj[col.label] = row[col.key] ?? "";
      });
      return obj;
    });
    await exportToExcel(exportData, `${config.label}.xlsx`, config.label);
    toast.success("엑셀 다운로드가 완료되었어요.");
  }, [activeTab, filteredData]);

  // 폼 필드 변경
  const updateFormField = useCallback((key: string, value: any) => {
    setFormData((prev) => ({ ...prev, [key]: value }));
  }, []);

  // 행 체크 토글
  const toggleRowCheck = useCallback((tabKey: TabKey, rowId: string) => {
    setTabChecked((prev) => {
      const ids = prev[tabKey];
      return {
        ...prev,
        [tabKey]: ids.includes(rowId) ? ids.filter((x) => x !== rowId) : [...ids, rowId],
      };
    });
  }, []);

  // 전체 체크 토글
  const toggleAllCheck = useCallback((tabKey: TabKey, checked: boolean) => {
    setTabChecked((prev) => ({
      ...prev,
      [tabKey]: checked ? tabData[tabKey].map((r: any) => String(r.id)) : [],
    }));
  }, [tabData]);

  // 폼 필드 렌더
  const renderFormField = useCallback(
    (field: FormFieldDef) => {
      const value = formData[field.key] ?? "";
      // 현재 탭의 채번 대상 코드 필드인지 확인
      const numberingCodeField = NUMBERING_FIELD_MAP[activeConfig.tableName];
      const isNumberingTarget = !editMode && numberingRuleId && field.key === numberingCodeField;
      // 수정 모드에서 코드/번호 필드는 읽기전용
      const isCodeField =
        editMode &&
        field.type === "text" &&
        (field.key.endsWith("_code") || field.key.endsWith("_no"));

      switch (field.type) {
        case "text":
          // 등록 모드 + 채번 대상 필드: readOnly로 미리보기 코드 표시
          if (isNumberingTarget) {
            return (
              <Input
                value={previewCode || ""}
                readOnly
                placeholder="채번 조회 중..."
                className="h-9 text-sm bg-muted text-muted-foreground"
              />
            );
          }
          return (
            <Input
              value={value}
              onChange={(e) => updateFormField(field.key, e.target.value)}
              placeholder={field.placeholder}
              readOnly={isCodeField}
              className={cn(
                "h-9 text-sm",
                isCodeField && "bg-muted text-muted-foreground"
              )}
            />
          );
        case "number":
          return (
            <Input
              type="number"
              value={value}
              onChange={(e) => updateFormField(field.key, e.target.value)}
              placeholder={field.placeholder}
              className="h-9 text-sm"
            />
          );
        case "select": {
          const opts =
            field.options ||
            (field.categoryKey ? categoryOptions[field.categoryKey] : []) ||
            [];
          return (
            <Select
              value={String(value)}
              onValueChange={(v) => updateFormField(field.key, v)}
            >
              <SelectTrigger className="h-9 text-sm">
                <SelectValue placeholder={field.placeholder || "선택해주세요"} />
              </SelectTrigger>
              <SelectContent>
                {opts.map((o) => (
                  <SelectItem key={o.value} value={o.value}>
                    {o.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          );
        }
        case "smartselect": {
          // SmartSelect 대신 Select로 직접 구현
          const opts =
            field.referenceKey === "carrier" ? carrierOptions : routeOptions;
          return (
            <Select
              value={String(value)}
              onValueChange={(v) => updateFormField(field.key, v)}
            >
              <SelectTrigger className="h-9 text-sm">
                <SelectValue placeholder={field.placeholder || "선택해주세요"} />
              </SelectTrigger>
              <SelectContent>
                {opts.map((o) => (
                  <SelectItem key={o.code} value={o.code}>
                    {o.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          );
        }
        case "date":
          return (
            <Input
              type="date"
              value={value ? String(value).split("T")[0] : ""}
              onChange={(e) => updateFormField(field.key, e.target.value)}
              className="h-9 text-sm"
            />
          );
        default:
          return null;
      }
    },
    [formData, editMode, carrierOptions, routeOptions, categoryOptions, updateFormField, activeConfig, numberingRuleId, previewCode]
  );

  // ========== 렌더링 ==========
  return (
    <div className="flex h-[calc(100vh-4rem)] flex-col gap-3 p-3">
      {/* 검색 필터 바 */}
      <DynamicSearchFilter
        tableName={activeConfig.tableName}
        filterId="c16-logistics-info"
        onFilterChange={setSearchFilters}
        externalFilterConfig={activeTs.filterConfig}
        dataCount={filteredData.length}
      />

      {/* 탭 + 콘텐츠 영역 */}
      <Tabs
        value={activeTab}
        onValueChange={handleTabChange}
        className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-lg border bg-card"
      >
        <TabsList className="h-auto w-full shrink-0 justify-start gap-0 rounded-none border-b bg-muted/30 p-0">
          {TAB_CONFIGS.map((tab) => (
            <TabsTrigger
              key={tab.key}
              value={tab.key}
              className="flex items-center gap-1.5 rounded-none border-b-2 border-transparent px-4 py-2.5 text-sm font-medium text-muted-foreground data-[state=active]:border-primary data-[state=active]:font-semibold data-[state=active]:text-foreground data-[state=active]:shadow-none"
            >
              {tab.icon}
              {tab.label}
              <Badge
                variant="outline"
                className="ml-1 h-5 min-w-[22px] justify-center px-1.5 font-mono text-[10px]"
              >
                {tabData[tab.key]?.length || 0}
              </Badge>
            </TabsTrigger>
          ))}
        </TabsList>

        {TAB_CONFIGS.map((tab) => {
          const displayData = tab.key === activeTab ? filteredData : tabData[tab.key];
          const isAllChecked =
            tabData[tab.key].length > 0 &&
            tabData[tab.key].every((r: any) => tabChecked[tab.key].includes(String(r.id)));

          return (
            <TabsContent
              key={tab.key}
              value={tab.key}
              className="m-0 flex flex-1 flex-col overflow-hidden data-[state=inactive]:hidden"
            >
              {/* 액션 바 */}
              <div className="flex shrink-0 items-center justify-between border-b px-3 py-2">
                <div className="flex items-center gap-2">
                  <h2 className="text-sm font-bold">{tab.label} 목록</h2>
                  <Badge className="bg-primary/10 font-mono text-[11px] text-primary">
                    {tab.key === activeTab ? displayData.length : tabData[tab.key]?.length || 0}건
                  </Badge>
                </div>
                <div className="flex items-center gap-1.5">
                  <Button size="sm" className="h-8 text-xs" onClick={handleOpenAdd}>
                    <Plus className="mr-1 h-3.5 w-3.5" />
                    등록
                  </Button>
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-8 text-xs"
                    disabled={tabChecked[tab.key].length !== 1}
                    onClick={() => {
                      const row = tabData[tab.key].find(
                        (r: any) => String(r.id) === tabChecked[tab.key][0]
                      );
                      if (row) handleOpenEdit(row);
                    }}
                  >
                    <Pencil className="mr-1 h-3.5 w-3.5" />
                    수정
                  </Button>
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-8 text-xs text-destructive hover:bg-destructive/10"
                    disabled={tabChecked[tab.key].length === 0}
                    onClick={handleDelete}
                  >
                    <Trash2 className="mr-1 h-3.5 w-3.5" />
                    삭제
                  </Button>
                  <div className="mx-1 h-5 w-px bg-border" />
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-8 text-xs"
                    onClick={handleExcelDownload}
                  >
                    <Download className="mr-1 h-3.5 w-3.5" />
                    엑셀
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-8 w-8 p-0"
                    onClick={() => fetchTabData(tab.key)}
                  >
                    <RefreshCw
                      className={cn(
                        "h-3.5 w-3.5",
                        tabLoading[tab.key] && "animate-spin"
                      )}
                    />
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-8 w-8 p-0"
                    onClick={() => activeTs.setOpen(true)}
                  >
                    <Settings2 className="h-3.5 w-3.5" />
                  </Button>
                </div>
              </div>

              {/* 테이블 영역 */}
              <div className="flex-1 overflow-auto">
                <EDataTable
                  columns={getVisibleColumns(tab.key).map((col): EDataTableColumn => {
                    const formField = tab.formFields.find((f) => f.key === col.key && f.categoryKey);
                    const refField = tab.formFields.find((f) => f.key === col.key && f.referenceKey);
                    let customRender: ((value: any, row: any) => React.ReactNode) | undefined;
                    if (formField?.categoryKey) {
                      customRender = (value: any) => {
                        const opts = categoryOptions[formField.categoryKey!] || [];
                        const matched = opts.find((o: any) => o.value === value);
                        return matched?.label || value || "-";
                      };
                    } else if (refField?.referenceKey) {
                      customRender = (value: any) => getRefName(refField.referenceKey!, value);
                    } else if (col.key === "route_name") {
                      customRender = (_v: any, row: any) => getRefName("route", row.route_code);
                    }
                    return {
                      key: col.key,
                      label: col.label,
                      align: col.align,
                      formatNumber: col.formatNumber,
                      truncate: true,
                      render: customRender,
                    };
                  })}
                  data={tsMap[tab.key].groupData(displayData)}
                  rowKey={(row: any) => String(row.id)}
                  loading={tabLoading[tab.key]}
                  emptyMessage={`등록된 ${tab.label} 정보가 없어요`}
                  showCheckbox
                  checkedIds={tabChecked[tab.key]}
                  onCheckedChange={(ids) => setTabChecked((prev) => ({ ...prev, [tab.key]: ids }))}
                  onRowDoubleClick={(row) => handleOpenEdit(row)}
                  showPagination={false}
                  draggableColumns={false}
                />
              </div>
            </TabsContent>
          );
        })}
      </Tabs>

      {/* 등록/수정 모달 */}
      <Dialog open={formOpen} onOpenChange={setFormOpen}>
        <DialogContent className="flex max-h-[85vh] flex-col gap-0 overflow-hidden p-0 sm:max-w-[680px]">
          <DialogHeader className="shrink-0 border-b px-6 py-4">
            <DialogTitle>
              {activeConfig.label} {editMode ? "수정" : "등록"}
            </DialogTitle>
            <DialogDescription>
              {editMode
                ? `${activeConfig.label} 정보를 수정해주세요.`
                : `새 ${activeConfig.label} 정보를 입력해주세요.`}
            </DialogDescription>
          </DialogHeader>
          <div className="flex-1 overflow-y-auto p-6">
            <div className="grid grid-cols-2 gap-4">
              {activeConfig.formFields.map((field) => (
                <div key={field.key} className="flex flex-col gap-1.5">
                  <Label className="text-xs font-semibold text-muted-foreground">
                    {field.label}
                    {field.required && (
                      <span className="ml-0.5 text-destructive">*</span>
                    )}
                  </Label>
                  {renderFormField(field)}
                </div>
              ))}
            </div>
          </div>
          <div className="shrink-0 border-t">
            <div className="flex items-center justify-end gap-2 px-6 py-3">
              <Button variant="outline" onClick={() => setFormOpen(false)}>
                취소
              </Button>
              <Button onClick={handleSave}>
                {editMode ? "수정" : "등록"}
              </Button>
            </div>
          </div>
        </DialogContent>
      </Dialog>

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

      {ConfirmDialogComponent}
    </div>
  );
}
