/* global React, Icon, Button, Field, ChipFilter, AdvFilterBtn, FdrChipGroup, FilterDrawer, FilterGroup, FilterTagStrip, Pager, ModeToggle, useToast, ImportBanner, runImportProgress, BATCH_NAMES, SOURCES, PAGE_SIZES, PRODUCT_MASTER, SALE_STATUS_LABELS, SkuToolbar, useSortableTable, pmWireframeRow, TruncCell */
// 商品主檔 L1 — 唯讀列表、批次匯出

const { useState, useMemo } = React;

// ── Column definitions ────────────────────────────────────────────────────
const col = (key, label, w, group, opts = {}) => ({ key, label, w, group, ...opts });

const PM_GROUP_LABELS = {
  A: "識別與分類", B: "進價與售價", C: "主檔與銷售", D: "說明與規格",
  E: "品牌與產地", F: "法規", G: "圖片", H: "效期與條碼",
  I: "Oracle 與稅務", J: "物流與廠商", K: "庫存",
};

const PM_IMAGE_KEYS = new Set([
  "imageUrl", "imagePromo", "imageCalorie",
  "imageScene1", "imageScene2", "imageScene3", "imageScene4",
]);

// 精選 12 欄 — External Data 為第一資料欄（wireframe）
const COMPACT_COLS = [
  col("#",              "#",             48,  "A", { stickyNum: true }),
  col("externalData",   "External Data", 150, "A", { mono: true, sticky2nd: true }),
  col("skuNo",          "品號",          140, "A", { mono: true }),
  col("itemName",       "品名",          260, "A"),
  col("menu",           "主類別",        120, "A"),
  col("category",       "次類別",        120, "A"),
  col("supplierName",   "廠商",          160, "A"),
  col("costExTax",      "進價（未稅）",  110, "B", { num: true, nt: true }),
  col("regularPrice",   "建議售價",       90, "B", { num: true, nt: true }),
  col("productMaster",  "販售狀態",       90, "C"),
  col("grade",          "品項分級",       90, "C"),
  col("tempLayer",      "溫層",           80, "C"),
  col("margin",         "毛利率",         90, "B"),
];

// 全欄位 99 欄 + # — 對齊 Figma 歷史菜單表
const FULL_COLS = [
  col("#",              "#",          48,  "A", { stickyNum: true }),
  col("externalData",   "External Data", 150, "A", { mono: true, sticky2nd: true }),
  col("menu",           "Menu",        160, "A"),
  col("category",       "Category",    160, "A"),
  col("analysisMainCat","分析主分類",  160, "A"),
  col("analysisSubCat", "分析次分類",  160, "A"),
  col("analysisChildCat","分析子分類", 160, "A"),
  col("groupSkuNo",     "群組貨號",    140, "A", { mono: true }),
  col("groupSkuName",   "群組中文名稱",180, "A"),
  col("skuNo",          "品號",        140, "A", { mono: true }),
  col("itemName",       "品名",        260, "A"),
  col("isDescProduct",  "是否為說明使用的商品", 140, "A"),
  col("title",          "Title (顯示在菜單的商品名稱)", 220, "A"),
  col("newProductBatch","新商品所屬批次", 160, "A"),
  col("originalCost",   "商品原進價",   90, "B", { num: true, nt: true }),
  col("regularCost",    "常態進價",     90, "B", { num: true, nt: true }),
  col("costExTax",      "目前進價(未稅)", 110, "B", { num: true, nt: true }),
  col("costIncTax",     "目前進價(含稅)", 110, "B", { num: true, nt: true }),
  col("margin",         "毛利",         80, "B", { num: true }),
  col("listPrice",      "牌價",         80, "B", { num: true, nt: true }),
  col("regularPrice",   "常態售價",     90, "B", { num: true, nt: true }),
  col("u1PromoPrice",   "U1 Promo Price", 110, "B", { num: true, nt: true }),
  col("promoPrice",     "Promo Price",  90, "B", { num: true, nt: true }),
  col("salesPrice",     "Sales Price",  90, "B", { num: true, nt: true }),
  col("bundlePrice",    "商品一組價",   90, "B", { num: true, nt: true }),
  col("postSaleSubsidy","實銷後補",     90, "B", { num: true, nt: true }),
  col("purchaseQty",    "purchase_quantity", 110, "B", { num: true }),
  col("discountedQty",  "discounted_quantity", 120, "B", { num: true }),
  col("promoType",      "Promo Type",  130, "B"),
  col("productMaster",  "商品主檔",    100, "C"),
  col("saleRegion",     "銷售地區",    100, "C"),
  col("customStores",   "自訂販售門店",160, "C"),
  col("grade",          "陳列等級",     80, "C"),
  col("tempLayer",      "溫層",         70, "C"),
  col("saleStart",      "啟售日",      110, "C", { mono: true }),
  col("saleEnd",        "停售日",      110, "C", { mono: true }),
  col("exitDate",       "成功退場日",  110, "C", { mono: true }),
  col("description",    "Description (顯示在菜單上的商品說明)", 260, "D"),
  col("specNum",        "規格數字",     80, "D", { num: true }),
  col("specUnit",       "規格單位",     80, "D"),
  col("saleQty",        "銷售入數",     80, "D", { num: true }),
  col("packQty",        "單包入數",     80, "D", { num: true }),
  col("unit",           "單位",         60, "D"),
  col("dimL",           "長",           70, "D", { num: true }),
  col("dimW",           "寬",           70, "D", { num: true }),
  col("dimH",           "高",           70, "D", { num: true }),
  col("weight",         "重量毛重",     90, "D"),
  col("brand",          "品牌",        110, "E"),
  col("series",         "系列",        110, "E"),
  col("generalDesc",    "一般敘述",    200, "E"),
  col("productDesc",    "商品描述",    200, "E"),
  col("origin",         "產地",         90, "E"),
  col("originFull",     "商品產地 (驗收工具使用)", 160, "E"),
  col("meatOrigin",     "肉類來源",    110, "E"),
  col("vegetarian",     "素食別",       80, "E"),
  col("foodBizNo",      "食品業者登錄字號", 160, "F"),
  col("productLiabIns", "產品責任險",  160, "F"),
  col("medDeviceNo",    "醫材許可證字號或登錄字號", 180, "F"),
  col("medDeviceOwner", "許可證所有人或登錄者之名稱及地址", 220, "F"),
  col("manufacturer",   "製造業者名稱及地址", 200, "F"),
  col("imageUrl",       "商品主圖",     80, "G"),
  col("imagePromo",     "活動圖檔",    130, "G"),
  col("imageCalorie",   "包裝熱量照",  130, "G"),
  col("imageScene1",    "情境圖檔1",   120, "G"),
  col("imageScene2",    "情境圖檔2",   120, "G"),
  col("imageScene3",    "情境圖檔3",   120, "G"),
  col("imageScene4",    "情境圖檔4",   120, "G"),
  col("expiry",         "效期",         80, "H", { num: true }),
  col("expiryDisplay",  "效期呈現方式",110, "H"),
  col("barcodeA",       "商品條碼A",   140, "H", { mono: true }),
  col("barcodeB",       "商品條碼B",   140, "H", { mono: true }),
  col("barcodeC",       "商品條碼C",   140, "H", { mono: true }),
  col("barcodeD",       "商品條碼D",   140, "H", { mono: true }),
  col("oracleItemNo",   "Oracle 貨號", 120, "I", { mono: true }),
  col("vat",            "VAT",          60, "I", { num: true }),
  col("clearanceDays",  "出清天數",     80, "I", { num: true }),
  col("taxType",        "應稅未稅",     80, "I"),
  col("moq",            "MOQ",          70, "I", { num: true }),
  col("moa",            "MOA",          70, "I", { num: true }),
  col("returnDays",     "可退換天數",   90, "I"),
  col("returnOrExchange","可退 or 可換",100, "I"),
  col("deliveryMethod", "商品配貨方式",110, "J"),
  col("logisticsInfo",  "物流資訊",    140, "J"),
  col("supplierNo",     "廠商代號",    100, "J", { mono: true }),
  col("supplierName",   "廠商",        160, "J"),
  col("buyer",          "採購",         90, "J"),
  col("oracleReady",    "是否在Oracle已建檔", 140, "J"),
  col("totalStock",     "各店總庫存",   90, "K", { num: true }),
  col("stock_zhongshan","中山店",       70, "K", { num: true }),
  col("stock_zhonghe",  "中和店",       70, "K", { num: true }),
  col("stock_neihu",    "內湖店",       70, "K", { num: true }),
  col("stock_sanchong", "三重店",       70, "K", { num: true }),
  col("stock_xindian",  "新店店",       70, "K", { num: true }),
  col("stock_daan",     "大安店",       70, "K", { num: true }),
  col("stock_beitou",   "北投店",       70, "K", { num: true }),
  col("stock_shulin",   "樹林店",       70, "K", { num: true }),
  col("stock_jingwu",   "精武店",       70, "K", { num: true }),
  col("stock_taoyuan",  "桃園店",       70, "K", { num: true }),
  col("stock_nantun",   "南屯店",       70, "K", { num: true }),
  col("stock_hsinchu",  "新竹店",       70, "K", { num: true }),
];

function PM_buildGroups(cols) {
  const groups = [];
  let i = 0;
  while (i < cols.length) {
    const g = cols[i].group;
    let j = i;
    while (j < cols.length && cols[j].group === g) j++;
    groups.push({ group: g, colSpan: j - i });
    i = j;
  }
  return groups;
}

const pmSortVal = (raw, key) => {
  if (key === "#") return null;
  return pmWireframeRow(raw)[key];
};

const renderCell = (item, c, idx) => {
  if (c.key === "#") return <span style={{ color: "var(--fg-3)", fontSize: "var(--fs-12)" }}>{idx + 1}</span>;
  const v = item[c.key];
  if (v === "" || v == null) return <span className="cell-empty">—</span>;
  if (c.key === "productMaster") {
    const bad = v === "outOfStock" || v === "discontinued";
    return <span style={{ fontSize: "var(--fs-12)", padding: "1px 6px", borderRadius: 2,
      background: bad ? "var(--danger-bg)" : "var(--success-bg)",
      color: bad ? "var(--danger)" : "var(--tag-approved-fg)" }}>
      {SALE_STATUS_LABELS[v] || v}
    </span>;
  }
  if (c.key === "isDescProduct") return <span>{v ? "是" : "否"}</span>;
  if (c.key === "margin") {
    if (typeof v === "number") return <span className="mono">{(v * 100).toFixed(1)}%</span>;
    if (typeof v === "string" && v) return <span className="mono">{v}</span>;
    return <span className="cell-empty">—</span>;
  }
  if (c.nt) return <span className="mono">{`NT$${Number(v).toLocaleString()}`}</span>;
  if (c.mono) return <span className="mono" style={{ fontSize: "var(--fs-12)" }}>{v}</span>;
  if (PM_IMAGE_KEYS.has(c.key)) {
    return <TruncCell text={v} style={{ color: "var(--fg-3)", fontFamily: "var(--font-mono)", fontSize: "var(--fs-12)" }} />;
  }
  if (c.key === "description") {
    return (
      <span style={{ fontSize: "var(--fs-12)", color: "var(--fg-2)", display: "block", maxWidth: 280, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{v}</span>
    );
  }
  return v;
};

// ── Derived option lists ──────────────────────────────────────────────────
const uniq = (arr) => [...new Set(arr.filter(Boolean))].sort();
const ALL_SUPPLIERS   = uniq(PRODUCT_MASTER.map(p => p.supplierName));
const ALL_MAIN_CATS   = uniq(PRODUCT_MASTER.map(p => p.mainCat));
const ALL_SUB_CATS    = uniq(PRODUCT_MASTER.map(p => p.subCat));
const ALL_TEMPS       = uniq(PRODUCT_MASTER.map(p => p.temp));
const ALL_TIERS       = uniq(PRODUCT_MASTER.map(p => p.tier));
const ALL_REGIONS     = uniq(PRODUCT_MASTER.map(p => p.region));
const ALL_DELIVS      = uniq(PRODUCT_MASTER.map(p => p.deliv));
const ALL_IMPORTS     = uniq(PRODUCT_MASTER.map(p => p.imported));
const ALL_TAX_RATES   = uniq(PRODUCT_MASTER.map(p => p.taxRate));
const ALL_SALE_STATUSES = uniq(PRODUCT_MASTER.map(p => p.saleStatus).filter(Boolean));
const ALL_PROMO_TYPES = uniq(PRODUCT_MASTER.map(p => p.promoType).filter(Boolean));
const ALL_VEG_TYPES   = uniq(PRODUCT_MASTER.map(p => p.vegType).filter(Boolean));
const ALL_SEGMENTS1   = uniq(PRODUCT_MASTER.map(p => p.segment1).filter(Boolean));
const ALL_SEGMENTS2   = uniq(PRODUCT_MASTER.map(p => p.segment2).filter(Boolean));
const ALL_SEGMENTS3   = uniq(PRODUCT_MASTER.map(p => p.segment3).filter(Boolean));
const ALL_UNITS       = uniq(PRODUCT_MASTER.map(p => p.unit).filter(Boolean));
const ALL_SPEC_UNITS  = uniq(PRODUCT_MASTER.map(p => p.specUnit).filter(Boolean));
const ALL_EXP_TYPES   = uniq(PRODUCT_MASTER.map(p => p.expType).filter(Boolean));

// ── Advanced filter initial state ─────────────────────────────────────────
const ADV_INIT = {
  // 基本識別
  groupId: "", groupName: "",
  // 商業資訊
  supplierNo: "",
  costMin: "", costMax: "",
  listPriceMin: "", listPriceMax: "",
  suggestPriceMin: "", suggestPriceMax: "",
  marginMin: "", marginMax: "",
  monthRevenueMin: "", monthRevenueMax: "",
  origCostMin: "", origCostMax: "",
  promoCostMin: "", promoCostMax: "",
  promoStartMin: "", promoStartMax: "",
  promoEndMin: "", promoEndMax: "",
  promoType: [],
  competitorPrice: "", altItem: "", stores: "",
  // 品項設定
  deliv: [], hold: "", imported: [],
  returnDaysMin: "", returnDaysMax: "",
  // 規格
  taxRate: [],
  shelfDaysMin: "", shelfDaysMax: "",
  minOrderMin: "", minOrderMax: "",
  unit: [], specUnit: [], expType: [],
  specNumMin: "", specNumMax: "",
  saleCountMin: "", saleCountMax: "",
  packCountMin: "", packCountMax: "",
  lengthCmMin: "", lengthCmMax: "",
  widthCmMin: "", widthCmMax: "",
  heightCmMin: "", heightCmMax: "",
  weightGMin: "", weightGMax: "",
  specSummary: "",
  // 法規
  vegType: [],
  meatOrigin: "", foodBizNo: "", prodLiability: "",
  medLicense: "", licenseOwner: "",
  // 商品資訊
  brand: "", origin: "", manufacturer: "", desc: "",
  series: "", imageUrl: "",
  segment1: [], segment2: [], segment3: [],
  // 審核
  checkSku: "", checkCat: "", reviewComment: "",
  // 圖片
  imgMain: "", imgActivity: "", imgNutrition: "", imgScene1: "", imgScene2: "", imgScene3: "", imgScene4: "",
};

// ── ProductMasterList ─────────────────────────────────────────────────────
const ProductMasterList = () => {
  const toast = useToast();
  const [mode, setMode] = useState("compact");
  const [search, setSearch] = useState("");
  const [filterBatch, setFilterBatch]       = useState([]);
  const [filterSupplier, setFilterSupplier] = useState([]);
  const [filterMainCat, setFilterMainCat]   = useState([]);
  const [filterSubCat, setFilterSubCat]     = useState([]);
  const [filterTemp, setFilterTemp]         = useState([]);
  const [filterTier, setFilterTier]         = useState([]);
  const [filterRegion, setFilterRegion]         = useState([]);
  const [filterSaleStatus, setFilterSaleStatus] = useState([]);
  const [advDrawerOpen, setAdvDrawerOpen]       = useState(false);
  const [advFilters, setAdvFilters]         = useState(ADV_INIT);
  const [appliedAdv, setAppliedAdv]         = useState(ADV_INIT);
  const [page, setPage]                     = useState(1);
  const [pageSize, setPageSize]             = useState(20);
  const { SortHead, applySortTo }           = useSortableTable("externalData", "asc");
  const [exportPhase, setExportPhase]       = useState(null);
  const [exportTotal, setExportTotal]       = useState(0);
  const [exportDone, setExportDone]         = useState(0);

  const cols = mode === "compact" ? COMPACT_COLS : FULL_COLS;

  // ── Filtering ─────────────────────────────────────────────────────────────
  const filtered = useMemo(() => {
    let data = PRODUCT_MASTER;
    const q = search.trim().toLowerCase();
    if (q) data = data.filter(p => p.barcode.toLowerCase().includes(q) || p.name.toLowerCase().includes(q));
    if (filterBatch.length)    data = data.filter(p => filterBatch.includes(p.batch));
    if (filterSupplier.length) data = data.filter(p => filterSupplier.includes(p.supplierName));
    if (filterMainCat.length)  data = data.filter(p => filterMainCat.includes(p.mainCat));
    if (filterSubCat.length)   data = data.filter(p => filterSubCat.includes(p.subCat));
    if (filterTemp.length)     data = data.filter(p => filterTemp.includes(p.temp));
    if (filterTier.length)     data = data.filter(p => filterTier.includes(p.tier));
    if (filterRegion.length)     data = data.filter(p => filterRegion.includes(p.region));
    if (filterSaleStatus.length) data = data.filter(p => filterSaleStatus.includes(p.saleStatus));
    const a = appliedAdv;
    // 基本識別
    if (a.groupId.trim())    data = data.filter(p => (p.groupId||"").toLowerCase().includes(a.groupId.trim().toLowerCase()));
    if (a.groupName.trim())  data = data.filter(p => (p.groupName||"").toLowerCase().includes(a.groupName.trim().toLowerCase()));
    // 商業資訊
    if (a.supplierNo.trim()) data = data.filter(p => (p.supplierNo||"").toLowerCase().includes(a.supplierNo.trim().toLowerCase()));
    if (a.costMin)           data = data.filter(p => +p.cost >= +a.costMin);
    if (a.costMax)           data = data.filter(p => +p.cost <= +a.costMax);
    if (a.listPriceMin)      data = data.filter(p => +p.listPrice >= +a.listPriceMin);
    if (a.listPriceMax)      data = data.filter(p => +p.listPrice <= +a.listPriceMax);
    if (a.suggestPriceMin)   data = data.filter(p => +p.suggestPrice >= +a.suggestPriceMin);
    if (a.suggestPriceMax)   data = data.filter(p => +p.suggestPrice <= +a.suggestPriceMax);
    if (a.marginMin)         data = data.filter(p => parseFloat(p.marginPct) >= +a.marginMin);
    if (a.marginMax)         data = data.filter(p => parseFloat(p.marginPct) <= +a.marginMax);
    if (a.monthRevenueMin)   data = data.filter(p => +p.monthRevenue >= +a.monthRevenueMin);
    if (a.monthRevenueMax)   data = data.filter(p => +p.monthRevenue <= +a.monthRevenueMax);
    if (a.origCostMin)       data = data.filter(p => +p.origCost >= +a.origCostMin);
    if (a.origCostMax)       data = data.filter(p => +p.origCost <= +a.origCostMax);
    if (a.promoCostMin)      data = data.filter(p => +p.promoCost >= +a.promoCostMin);
    if (a.promoCostMax)      data = data.filter(p => +p.promoCost <= +a.promoCostMax);
    if (a.promoStartMin)     data = data.filter(p => (p.promoStart||"") >= a.promoStartMin);
    if (a.promoStartMax)     data = data.filter(p => (p.promoStart||"") <= a.promoStartMax);
    if (a.promoEndMin)       data = data.filter(p => (p.promoEnd||"") >= a.promoEndMin);
    if (a.promoEndMax)       data = data.filter(p => (p.promoEnd||"") <= a.promoEndMax);
    if (a.promoType.length)  data = data.filter(p => a.promoType.includes(p.promoType));
    if (a.competitorPrice.trim()) data = data.filter(p => (p.competitorPrice||"").toLowerCase().includes(a.competitorPrice.trim().toLowerCase()));
    if (a.altItem.trim())    data = data.filter(p => (p.altItem||"").toLowerCase().includes(a.altItem.trim().toLowerCase()));
    if (a.stores.trim())     data = data.filter(p => (p.stores||"").toLowerCase().includes(a.stores.trim().toLowerCase()));
    // 品項設定
    if (a.deliv.length)      data = data.filter(p => a.deliv.includes(p.deliv));
    if (a.hold === "yes")    data = data.filter(p => p.hold);
    if (a.hold === "no")     data = data.filter(p => !p.hold);
    if (a.imported.length)   data = data.filter(p => a.imported.includes(p.imported));
    if (a.returnDaysMin)     data = data.filter(p => +p.returnDays >= +a.returnDaysMin);
    if (a.returnDaysMax)     data = data.filter(p => +p.returnDays <= +a.returnDaysMax);
    // 規格
    if (a.taxRate.length)    data = data.filter(p => a.taxRate.includes(p.taxRate));
    if (a.shelfDaysMin)      data = data.filter(p => +p.shelfDays >= +a.shelfDaysMin);
    if (a.shelfDaysMax)      data = data.filter(p => +p.shelfDays <= +a.shelfDaysMax);
    if (a.minOrderMin)       data = data.filter(p => +p.minOrder >= +a.minOrderMin);
    if (a.minOrderMax)       data = data.filter(p => +p.minOrder <= +a.minOrderMax);
    if (a.unit.length)       data = data.filter(p => a.unit.includes(p.unit));
    if (a.specUnit.length)   data = data.filter(p => a.specUnit.includes(p.specUnit));
    if (a.expType.length)    data = data.filter(p => a.expType.includes(p.expType));
    if (a.specNumMin)        data = data.filter(p => +p.specNum >= +a.specNumMin);
    if (a.specNumMax)        data = data.filter(p => +p.specNum <= +a.specNumMax);
    if (a.saleCountMin)      data = data.filter(p => +p.saleCount >= +a.saleCountMin);
    if (a.saleCountMax)      data = data.filter(p => +p.saleCount <= +a.saleCountMax);
    if (a.packCountMin)      data = data.filter(p => +p.packCount >= +a.packCountMin);
    if (a.packCountMax)      data = data.filter(p => +p.packCount <= +a.packCountMax);
    if (a.lengthCmMin)       data = data.filter(p => +p.lengthCm >= +a.lengthCmMin);
    if (a.lengthCmMax)       data = data.filter(p => +p.lengthCm <= +a.lengthCmMax);
    if (a.widthCmMin)        data = data.filter(p => +p.widthCm >= +a.widthCmMin);
    if (a.widthCmMax)        data = data.filter(p => +p.widthCm <= +a.widthCmMax);
    if (a.heightCmMin)       data = data.filter(p => +p.heightCm >= +a.heightCmMin);
    if (a.heightCmMax)       data = data.filter(p => +p.heightCm <= +a.heightCmMax);
    if (a.weightGMin)        data = data.filter(p => +p.weightG >= +a.weightGMin);
    if (a.weightGMax)        data = data.filter(p => +p.weightG <= +a.weightGMax);
    if (a.specSummary.trim()) data = data.filter(p => (p.specSummary||"").toLowerCase().includes(a.specSummary.trim().toLowerCase()));
    // 法規
    if (a.vegType.length)    data = data.filter(p => a.vegType.includes(p.vegType));
    if (a.meatOrigin.trim()) data = data.filter(p => (p.meatOrigin||"").toLowerCase().includes(a.meatOrigin.trim().toLowerCase()));
    if (a.foodBizNo.trim())  data = data.filter(p => (p.foodBizNo||"").toLowerCase().includes(a.foodBizNo.trim().toLowerCase()));
    if (a.prodLiability.trim()) data = data.filter(p => (p.prodLiability||"").toLowerCase().includes(a.prodLiability.trim().toLowerCase()));
    if (a.medLicense.trim()) data = data.filter(p => (p.medLicense||"").toLowerCase().includes(a.medLicense.trim().toLowerCase()));
    if (a.licenseOwner.trim()) data = data.filter(p => (p.licenseOwner||"").toLowerCase().includes(a.licenseOwner.trim().toLowerCase()));
    // 商品資訊
    if (a.brand.trim())      data = data.filter(p => (p.brand||"").toLowerCase().includes(a.brand.trim().toLowerCase()));
    if (a.origin.trim())     data = data.filter(p => (p.origin||"").toLowerCase().includes(a.origin.trim().toLowerCase()));
    if (a.manufacturer.trim()) data = data.filter(p => (p.manufacturer||"").toLowerCase().includes(a.manufacturer.trim().toLowerCase()));
    if (a.desc.trim())       data = data.filter(p => (p.desc||"").toLowerCase().includes(a.desc.trim().toLowerCase()));
    if (a.series.trim())     data = data.filter(p => (p.series||"").toLowerCase().includes(a.series.trim().toLowerCase()));
    if (a.imageUrl === "has")      data = data.filter(p => p.imageUrl && p.imageUrl !== "");
    if (a.imageUrl === "none")     data = data.filter(p => !p.imageUrl || p.imageUrl === "");
    // 圖片
    ["imgMain","imgActivity","imgNutrition","imgScene1","imgScene2","imgScene3","imgScene4"].forEach(k => {
      if (a[k] === "has")  data = data.filter(p => p[k] && p[k] !== "");
      if (a[k] === "none") data = data.filter(p => !p[k] || p[k] === "");
    });
    if (a.segment1.length)   data = data.filter(p => a.segment1.includes(p.segment1));
    if (a.segment2.length)   data = data.filter(p => a.segment2.includes(p.segment2));
    if (a.segment3.length)   data = data.filter(p => a.segment3.includes(p.segment3));
    // 審核
    if (a.checkSku === "yes") data = data.filter(p => p.checkSku);
    if (a.checkSku === "no")  data = data.filter(p => !p.checkSku);
    if (a.checkCat === "yes") data = data.filter(p => p.checkCat);
    if (a.checkCat === "no")  data = data.filter(p => !p.checkCat);
    if (a.reviewComment.trim()) data = data.filter(p => (p.reviewComment||"").toLowerCase().includes(a.reviewComment.trim().toLowerCase()));
    return applySortTo(data, pmSortVal);
  }, [search, filterBatch, filterSupplier, filterMainCat, filterSubCat, filterTemp, filterTier, filterRegion, filterSaleStatus, appliedAdv, applySortTo]);

  // ── Active adv filter count ────────────────────────────────────────────────
  const advActiveCount = useMemo(() => {
    let n = 0;
    const a = appliedAdv;
    if (a.groupId.trim() || a.groupName.trim()) n++;
    if (a.supplierNo.trim()) n++;
    if (a.costMin || a.costMax) n++;
    if (a.listPriceMin || a.listPriceMax) n++;
    if (a.suggestPriceMin || a.suggestPriceMax) n++;
    if (a.marginMin || a.marginMax) n++;
    if (a.monthRevenueMin || a.monthRevenueMax) n++;
    if (a.origCostMin || a.origCostMax) n++;
    if (a.promoCostMin || a.promoCostMax) n++;
    if (a.promoStartMin || a.promoStartMax) n++;
    if (a.promoEndMin || a.promoEndMax) n++;
    if (a.promoType.length) n++;
    if (a.competitorPrice.trim()) n++;
    if (a.altItem.trim()) n++;
    if (a.stores.trim()) n++;
    if (a.deliv.length) n++;
    if (a.hold) n++;
    if (a.imported.length) n++;
    if (a.returnDaysMin || a.returnDaysMax) n++;
    if (a.taxRate.length) n++;
    if (a.shelfDaysMin || a.shelfDaysMax) n++;
    if (a.minOrderMin || a.minOrderMax) n++;
    if (a.unit.length) n++;
    if (a.specUnit.length) n++;
    if (a.expType.length) n++;
    if (a.specNumMin || a.specNumMax) n++;
    if (a.saleCountMin || a.saleCountMax) n++;
    if (a.packCountMin || a.packCountMax) n++;
    if (a.lengthCmMin || a.lengthCmMax) n++;
    if (a.widthCmMin || a.widthCmMax) n++;
    if (a.heightCmMin || a.heightCmMax) n++;
    if (a.weightGMin || a.weightGMax) n++;
    if (a.specSummary.trim()) n++;
    if (a.vegType.length) n++;
    if (a.meatOrigin.trim()) n++;
    if (a.foodBizNo.trim()) n++;
    if (a.prodLiability.trim()) n++;
    if (a.medLicense.trim()) n++;
    if (a.licenseOwner.trim()) n++;
    if (a.brand.trim()) n++;
    if (a.origin.trim()) n++;
    if (a.manufacturer.trim()) n++;
    if (a.desc.trim()) n++;
    if (a.series.trim()) n++;
    if (a.imageUrl) n++;
    ["imgMain","imgActivity","imgNutrition","imgScene1","imgScene2","imgScene3","imgScene4"].forEach(k => { if (a[k]) n++; });
    if (a.segment1.length) n++;
    if (a.segment2.length) n++;
    if (a.segment3.length) n++;
    if (a.checkSku) n++;
    if (a.checkCat) n++;
    if (a.reviewComment.trim()) n++;
    return n;
  }, [appliedAdv]);

  // ── Active tags for FilterTagStrip ─────────────────────────────────────────
  const activeTags = useMemo(() => {
    const tags = [];
    const a = appliedAdv;
    const rmv = (...keys) => () => setAppliedAdv(prev => {
      const next = { ...prev };
      keys.forEach(k => { next[k] = Array.isArray(prev[k]) ? [] : ""; });
      return next;
    });
    const rangeLbl = (min, max, label, unit = "") =>
      min && max ? `${label} ${min}–${max}${unit}` : min ? `${label} ≥ ${min}${unit}` : `${label} ≤ ${max}${unit}`;
    const ntLbl = (min, max, label) =>
      min && max ? `${label} NT$${min}–${max}` : min ? `${label} ≥ NT$${min}` : `${label} ≤ NT$${max}`;
    const dateLbl = (min, max, label) =>
      min && max ? `${label} ${min} – ${max}` : min ? `${label} ≥ ${min}` : `${label} ≤ ${max}`;

    if (a.groupId.trim() || a.groupName.trim()) {
      const lbl = [a.groupId.trim() && `商品組 ID：${a.groupId}`, a.groupName.trim() && `商品組名稱：${a.groupName}`].filter(Boolean).join("、");
      tags.push({ label: lbl, onRemove: rmv("groupId", "groupName") });
    }
    if (a.supplierNo.trim()) tags.push({ label: `廠商編號：${a.supplierNo}`, onRemove: rmv("supplierNo") });
    if (a.costMin || a.costMax) tags.push({ label: ntLbl(a.costMin, a.costMax, "進價"), onRemove: rmv("costMin", "costMax") });
    if (a.listPriceMin || a.listPriceMax) tags.push({ label: ntLbl(a.listPriceMin, a.listPriceMax, "牌價"), onRemove: rmv("listPriceMin", "listPriceMax") });
    if (a.suggestPriceMin || a.suggestPriceMax) tags.push({ label: ntLbl(a.suggestPriceMin, a.suggestPriceMax, "售價"), onRemove: rmv("suggestPriceMin", "suggestPriceMax") });
    if (a.marginMin || a.marginMax) tags.push({ label: rangeLbl(a.marginMin, a.marginMax, "毛利率", "%"), onRemove: rmv("marginMin", "marginMax") });
    if (a.monthRevenueMin || a.monthRevenueMax) tags.push({ label: ntLbl(a.monthRevenueMin, a.monthRevenueMax, "預估業績"), onRemove: rmv("monthRevenueMin", "monthRevenueMax") });
    if (a.origCostMin || a.origCostMax) tags.push({ label: ntLbl(a.origCostMin, a.origCostMax, "原進價"), onRemove: rmv("origCostMin", "origCostMax") });
    if (a.promoCostMin || a.promoCostMax) tags.push({ label: ntLbl(a.promoCostMin, a.promoCostMax, "促進進價"), onRemove: rmv("promoCostMin", "promoCostMax") });
    if (a.promoStartMin || a.promoStartMax) tags.push({ label: dateLbl(a.promoStartMin, a.promoStartMax, "促進開始"), onRemove: rmv("promoStartMin", "promoStartMax") });
    if (a.promoEndMin || a.promoEndMax) tags.push({ label: dateLbl(a.promoEndMin, a.promoEndMax, "促進結束"), onRemove: rmv("promoEndMin", "promoEndMax") });
    if (a.promoType.length) tags.push({ label: `促銷類型：${a.promoType.join("、")}`, onRemove: rmv("promoType") });
    if (a.competitorPrice.trim()) tags.push({ label: `競對價格：${a.competitorPrice}`, onRemove: rmv("competitorPrice") });
    if (a.altItem.trim()) tags.push({ label: `替代品項：${a.altItem}`, onRemove: rmv("altItem") });
    if (a.stores.trim()) tags.push({ label: `特定門店：${a.stores}`, onRemove: rmv("stores") });
    if (a.deliv.length) tags.push({ label: `配貨方式：${a.deliv.join("、")}`, onRemove: rmv("deliv") });
    if (a.hold === "yes") tags.push({ label: "暫緩上架：是", onRemove: rmv("hold") });
    if (a.hold === "no")  tags.push({ label: "暫緩上架：否", onRemove: rmv("hold") });
    if (a.imported.length) tags.push({ label: `進口/台灣：${a.imported.join("、")}`, onRemove: rmv("imported") });
    if (a.returnDaysMin || a.returnDaysMax) tags.push({ label: rangeLbl(a.returnDaysMin, a.returnDaysMax, "可退天數", "天"), onRemove: rmv("returnDaysMin", "returnDaysMax") });
    if (a.taxRate.length) tags.push({ label: `稅率：${a.taxRate.join("、")}`, onRemove: rmv("taxRate") });
    if (a.shelfDaysMin || a.shelfDaysMax) tags.push({ label: rangeLbl(a.shelfDaysMin, a.shelfDaysMax, "效期", "天"), onRemove: rmv("shelfDaysMin", "shelfDaysMax") });
    if (a.minOrderMin || a.minOrderMax) tags.push({ label: rangeLbl(a.minOrderMin, a.minOrderMax, "最低訂量"), onRemove: rmv("minOrderMin", "minOrderMax") });
    if (a.unit.length) tags.push({ label: `單位：${a.unit.join("、")}`, onRemove: rmv("unit") });
    if (a.specUnit.length) tags.push({ label: `規格單位：${a.specUnit.join("、")}`, onRemove: rmv("specUnit") });
    if (a.expType.length) tags.push({ label: `效期類型：${a.expType.join("、")}`, onRemove: rmv("expType") });
    if (a.specNumMin || a.specNumMax) tags.push({ label: rangeLbl(a.specNumMin, a.specNumMax, "規格數字"), onRemove: rmv("specNumMin", "specNumMax") });
    if (a.saleCountMin || a.saleCountMax) tags.push({ label: rangeLbl(a.saleCountMin, a.saleCountMax, "銷售入數"), onRemove: rmv("saleCountMin", "saleCountMax") });
    if (a.packCountMin || a.packCountMax) tags.push({ label: rangeLbl(a.packCountMin, a.packCountMax, "裝箱數"), onRemove: rmv("packCountMin", "packCountMax") });
    if (a.lengthCmMin || a.lengthCmMax) tags.push({ label: rangeLbl(a.lengthCmMin, a.lengthCmMax, "長 (cm)"), onRemove: rmv("lengthCmMin", "lengthCmMax") });
    if (a.widthCmMin || a.widthCmMax) tags.push({ label: rangeLbl(a.widthCmMin, a.widthCmMax, "寬 (cm)"), onRemove: rmv("widthCmMin", "widthCmMax") });
    if (a.heightCmMin || a.heightCmMax) tags.push({ label: rangeLbl(a.heightCmMin, a.heightCmMax, "高 (cm)"), onRemove: rmv("heightCmMin", "heightCmMax") });
    if (a.weightGMin || a.weightGMax) tags.push({ label: rangeLbl(a.weightGMin, a.weightGMax, "重量 (g)"), onRemove: rmv("weightGMin", "weightGMax") });
    if (a.specSummary.trim()) tags.push({ label: `規格摘要：${a.specSummary}`, onRemove: rmv("specSummary") });
    if (a.vegType.length) tags.push({ label: `蔬食：${a.vegType.join("、")}`, onRemove: rmv("vegType") });
    if (a.meatOrigin.trim()) tags.push({ label: `肉品產地：${a.meatOrigin}`, onRemove: rmv("meatOrigin") });
    if (a.foodBizNo.trim()) tags.push({ label: `食品業者登錄字號：${a.foodBizNo}`, onRemove: rmv("foodBizNo") });
    if (a.prodLiability.trim()) tags.push({ label: `產品責任險：${a.prodLiability}`, onRemove: rmv("prodLiability") });
    if (a.medLicense.trim()) tags.push({ label: `衛署食字號：${a.medLicense}`, onRemove: rmv("medLicense") });
    if (a.licenseOwner.trim()) tags.push({ label: `許可證持有者：${a.licenseOwner}`, onRemove: rmv("licenseOwner") });
    if (a.brand.trim()) tags.push({ label: `品牌：${a.brand}`, onRemove: rmv("brand") });
    if (a.origin.trim()) tags.push({ label: `產地：${a.origin}`, onRemove: rmv("origin") });
    if (a.manufacturer.trim()) tags.push({ label: `製造商：${a.manufacturer}`, onRemove: rmv("manufacturer") });
    if (a.desc.trim()) tags.push({ label: `商品描述：${a.desc}`, onRemove: rmv("desc") });
    if (a.series.trim()) tags.push({ label: `系列：${a.series}`, onRemove: rmv("series") });
    if (a.imageUrl === "has")  tags.push({ label: "商品圖片連結：有圖", onRemove: rmv("imageUrl") });
    if (a.imageUrl === "none") tags.push({ label: "商品圖片連結：無圖", onRemove: rmv("imageUrl") });
    const imgLabels = { imgMain:"商品主圖", imgActivity:"活動圖檔", imgNutrition:"包裝熱量照", imgScene1:"情境圖 1", imgScene2:"情境圖 2", imgScene3:"情境圖 3", imgScene4:"情境圖 4" };
    Object.entries(imgLabels).forEach(([k, lbl]) => {
      if (a[k] === "has")  tags.push({ label: `${lbl}：有圖`, onRemove: rmv(k) });
      if (a[k] === "none") tags.push({ label: `${lbl}：無圖`, onRemove: rmv(k) });
    });
    if (a.segment1.length) tags.push({ label: `大分類(分析用)：${a.segment1.join("、")}`, onRemove: rmv("segment1") });
    if (a.segment2.length) tags.push({ label: `次分類(分析用)：${a.segment2.join("、")}`, onRemove: rmv("segment2") });
    if (a.segment3.length) tags.push({ label: `子分類(分析用)：${a.segment3.join("、")}`, onRemove: rmv("segment3") });
    if (a.checkSku === "yes") tags.push({ label: "SKU 審核：✓", onRemove: rmv("checkSku") });
    if (a.checkSku === "no")  tags.push({ label: "SKU 審核：待審", onRemove: rmv("checkSku") });
    if (a.checkCat === "yes") tags.push({ label: "品類審核：✓", onRemove: rmv("checkCat") });
    if (a.checkCat === "no")  tags.push({ label: "品類審核：待審", onRemove: rmv("checkCat") });
    if (a.reviewComment.trim()) tags.push({ label: `審核備註：${a.reviewComment}`, onRemove: rmv("reviewComment") });
    return tags;
  }, [appliedAdv]);

  // ── Paging ────────────────────────────────────────────────────────────────
  const pageItems = useMemo(() => {
    const start = (page - 1) * pageSize;
    return filtered.slice(start, start + pageSize);
  }, [filtered, page, pageSize]);

  const resetPage = () => setPage(1);

  // ── Export ────────────────────────────────────────────────────────────────
  const doExport = () => {
    const total = filtered.length;
    setExportTotal(total);
    setExportDone(0);
    setExportPhase("parsing");
    runImportProgress(total || 1, setExportDone, () => {
      setExportPhase("ok");
      setTimeout(() => setExportPhase(null), 1500);
    });
  };

  // ── Adv filter helpers ────────────────────────────────────────────────────
  const setAdv = (key) => (val) => setAdvFilters(prev => ({ ...prev, [key]: val }));
  const toggleAdvChip = (key, val) => setAdvFilters(prev => {
    const cur = prev[key] || [];
    return { ...prev, [key]: cur.includes(val) ? cur.filter(v => v !== val) : [...cur, val] };
  });
  const applyAdv = () => { setAppliedAdv({ ...advFilters }); setAdvDrawerOpen(false); resetPage(); };
  const clearAdv = () => { setAdvFilters(ADV_INIT); setAppliedAdv(ADV_INIT); resetPage(); };
  const clearAllTags = () => clearAdv();

  const fdrText = (key, label, placeholder) => (
    <div className="fdr-row">
      <label className="fdr-label">{label}</label>
      <input className="fdr-text-input" type="text" placeholder={placeholder} value={advFilters[key]} onChange={e => setAdv(key)(e.target.value)} />
    </div>
  );

  const fdrRange = (keyMin, keyMax, label) => (
    <div className="fdr-row">
      <label className="fdr-label">{label}</label>
      <div className="fdr-range">
        <input className="fdr-range__input" type="number" placeholder="最小" value={advFilters[keyMin]} onChange={e => setAdv(keyMin)(e.target.value)} />
        <span className="fdr-range__sep">–</span>
        <input className="fdr-range__input" type="number" placeholder="最大" value={advFilters[keyMax]} onChange={e => setAdv(keyMax)(e.target.value)} />
      </div>
    </div>
  );

  const fdrDateRange = (keyMin, keyMax, label) => (
    <div className="fdr-row">
      <label className="fdr-label">{label}</label>
      <div className="fdr-range">
        <input className="fdr-range__input" type="date" value={advFilters[keyMin]} onChange={e => setAdv(keyMin)(e.target.value)} />
        <span className="fdr-range__sep">–</span>
        <input className="fdr-range__input" type="date" value={advFilters[keyMax]} onChange={e => setAdv(keyMax)(e.target.value)} />
      </div>
    </div>
  );

  const fdrChips = (key, label, options, noDataMsg) => (
    <FdrChipGroup
      label={label}
      options={options}
      selected={advFilters[key]}
      noDataMsg={noDataMsg}
      onChange={newArr => setAdv(key)(newArr)}
    />
  );

  const fdrYesNo = (key, label) => (
    <div className="fdr-row">
      <label className="fdr-label">{label}</label>
      <div className="fdr-chips">
        {["是", "否"].map(v => {
          const val = v === "是" ? "yes" : "no";
          return <span key={v} className={"fdr-chip" + (advFilters[key] === val ? " on" : "")} onClick={() => setAdv(key)(advFilters[key] === val ? "" : val)}>{v}</span>;
        })}
      </div>
    </div>
  );

  return (
    <>
      <PageHead
        section="商品資料"
        title="商品主檔"
        subtitle="查詢各品項的完整主檔資料，可依規格、廠商、定價等條件篩選，並匯出 Excel。"
        actions={
          <Button variant="primary" icon="download" onClick={doExport} disabled={exportPhase === "parsing"}>
            {exportPhase === "parsing" ? "匯出中…" : `匯出 Excel（${filtered.length} 筆）`}
          </Button>
        }
      />
      <ImportBanner
        phase={exportPhase}
        parsingTitle="匯出準備中…"
        total={exportTotal}
        done={exportDone}
        okTitle={`已匯出 ${exportTotal} 筆`}
        okDesc=""
      />

      <FilterBar
        filters={[
          { type: "search", placeholder: "搜尋品號、品名…", value: search, onChange: v => { setSearch(v); resetPage(); }, style: { width: 240 } },
          { type: "chip", label: "批次名稱", value: filterBatch,    options: BATCH_NAMES,    onChange: v => { setFilterBatch(v); resetPage(); },    multi: true },
          { type: "chip", label: "廠商",     value: filterSupplier, options: ALL_SUPPLIERS,   onChange: v => { setFilterSupplier(v); resetPage(); }, multi: true },
          { type: "chip", label: "主類別",   value: filterMainCat,  options: ALL_MAIN_CATS,   onChange: v => { setFilterMainCat(v); resetPage(); },  multi: true },
          { type: "chip", label: "次類別",   value: filterSubCat,   options: ALL_SUB_CATS,    onChange: v => { setFilterSubCat(v); resetPage(); },   multi: true },
          { type: "chip", label: "溫層",     value: filterTemp,     options: ALL_TEMPS,       onChange: v => { setFilterTemp(v); resetPage(); },     multi: true },
          { type: "chip", label: "品項分級", value: filterTier,     options: ALL_TIERS,       onChange: v => { setFilterTier(v); resetPage(); },     multi: true },
          { type: "chip", label: "銷售地區", value: filterRegion,     options: ALL_REGIONS,       onChange: v => { setFilterRegion(v); resetPage(); },     multi: true },
          { type: "chip", label: "販售狀態", value: filterSaleStatus, options: ALL_SALE_STATUSES.map(v => ({ value: v, label: SALE_STATUS_LABELS[v] || v })), onChange: v => { setFilterSaleStatus(v); resetPage(); }, multi: true },
        ]}
        advFilter={{ activeCount: advActiveCount, onClick: () => setAdvDrawerOpen(true) }}
      />

      <FilterTagStrip tags={activeTags} onClearAll={clearAllTags} />

      <div className="card sku-card">
        <SkuToolbar>
          <ModeToggle mode={mode} onChange={setMode} />
          <span style={{ color: "var(--fg-2)", fontSize: 13, whiteSpace: "nowrap" }}>
            共 <b style={{ color: "var(--fg-1)" }}>{filtered.length}</b> 筆
          </span>
        </SkuToolbar>

        <div className="tbl-wrap">
          <table className="tbl" style={{ minWidth: cols.reduce((s, c) => s + c.w, 0) }}>
            <thead>
              <tr className="sku-tbl__thead-r1">
                {PM_buildGroups(cols).map((g, i) => (
                  <th key={i} colSpan={g.colSpan}
                    className={`sku-tbl__th-group th-${['a','b','c','d','e','f','g','h'][i % 8]}`}>
                    {PM_GROUP_LABELS[g.group]}
                  </th>
                ))}
              </tr>
              <tr className="sku-tbl__thead-r2">
                {cols.map(c => (
                  <th key={c.key} style={{ width: c.w, minWidth: c.w }}
                    className={[c.stickyNum ? "stk-l-0 center" : "", c.sticky2nd ? "stk-l-48 stk-shadow" : "", c.num ? "num" : ""].filter(Boolean).join(" ")}>
                    {c.key === "#" ? c.label : <SortHead colKey={c.key} label={c.label} />}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {pageItems.map((raw, idx) => {
                const item = pmWireframeRow(raw);
                const globalIdx = (page - 1) * pageSize + idx;
                return (
                  <tr key={raw.barcode}>
                    {cols.map(c => (
                      <td key={c.key}
                        className={[c.stickyNum ? "stk-l-0 center" : "", c.sticky2nd ? "stk-l-48 stk-shadow" : "", c.num ? "num" : ""].filter(Boolean).join(" ")}>
                        {renderCell(item, c, globalIdx)}
                      </td>
                    ))}
                  </tr>
                );
              })}
              {filtered.length === 0 && (
                <tr><td colSpan={cols.length}>
                  <div className="empty">
                    <div className="empty__icon"><Icon name="inbox" size={56} /></div>
                    <div className="empty__title">查無符合條件的品項</div>
                    <div className="empty__desc">請調整篩選條件後重試。</div>
                  </div>
                </td></tr>
              )}
            </tbody>
          </table>
        </div>

        <Pager total={filtered.length} page={page} pageSize={pageSize} onPageChange={setPage} onSizeChange={s => { setPageSize(s); resetPage(); }} />
      </div>

      <FilterDrawer open={advDrawerOpen} activeCount={advActiveCount} onClose={() => setAdvDrawerOpen(false)} onClear={clearAdv} onApply={applyAdv}>
        <FilterGroup label="基本識別">
          {fdrText("groupId",   "商品組 ID",   "輸入商品組 ID…")}
          {fdrText("groupName", "商品組名稱", "輸入商品組名稱…")}
        </FilterGroup>

        <FilterGroup label="商業資訊">
          {fdrText("supplierNo", "廠商編號", "輸入廠商編號…")}
          {fdrRange("costMin", "costMax", "進價")}
          {fdrRange("listPriceMin", "listPriceMax", "牌價")}
          {fdrRange("suggestPriceMin", "suggestPriceMax", "建議售價")}
          {fdrRange("marginMin", "marginMax", "毛利率 %")}
          {fdrRange("monthRevenueMin", "monthRevenueMax", "預估業績/月")}
          {fdrRange("origCostMin", "origCostMax", "原進價")}
          {fdrRange("promoCostMin", "promoCostMax", "促進進價")}
          {fdrDateRange("promoStartMin", "promoStartMax", "促進開始")}
          {fdrDateRange("promoEndMin", "promoEndMax", "促進結束")}
          {fdrChips("promoType", "促銷類型", ALL_PROMO_TYPES)}
          {fdrText("competitorPrice", "競對價格", "輸入競對價格關鍵字…")}
          {fdrText("altItem", "替代品項", "輸入替代品項關鍵字…")}
          {fdrText("stores", "特定門店", "輸入門店關鍵字…")}
        </FilterGroup>

        <FilterGroup label="品項設定">
          {fdrChips("deliv", "配貨方式", ALL_DELIVS)}
          {fdrYesNo("hold", "暫緩上架")}
          {fdrChips("imported", "進口/台灣", ALL_IMPORTS)}
          {fdrRange("returnDaysMin", "returnDaysMax", "可退天數")}
        </FilterGroup>

        <FilterGroup label="規格">
          {fdrChips("taxRate", "稅率", ALL_TAX_RATES)}
          {fdrRange("shelfDaysMin", "shelfDaysMax", "保存期限（天）")}
          {fdrRange("minOrderMin", "minOrderMax", "最低訂購量")}
          {fdrChips("unit", "單位", ALL_UNITS)}
          {fdrChips("specUnit", "規格單位", ALL_SPEC_UNITS)}
          {fdrChips("expType", "效期類型", ALL_EXP_TYPES)}
          {fdrRange("specNumMin", "specNumMax", "規格數字")}
          {fdrRange("saleCountMin", "saleCountMax", "銷售入數")}
          {fdrRange("packCountMin", "packCountMax", "裝箱數")}
          {fdrRange("lengthCmMin", "lengthCmMax", "長（cm）")}
          {fdrRange("widthCmMin", "widthCmMax", "寬（cm）")}
          {fdrRange("heightCmMin", "heightCmMax", "高（cm）")}
          {fdrRange("weightGMin", "weightGMax", "重量（g）")}
          {fdrText("specSummary", "規格摘要", "輸入規格摘要關鍵字…")}
        </FilterGroup>

        <FilterGroup label="法規">
          {fdrChips("vegType", "蔬食類型", ALL_VEG_TYPES, "目前資料無蔬食品項")}
          {fdrText("meatOrigin", "肉品產地", "輸入肉品產地…")}
          {fdrText("foodBizNo", "食品業者登錄字號", "輸入登錄字號關鍵字…")}
          {fdrText("prodLiability", "產品責任險", "輸入產品責任險關鍵字…")}
          {fdrText("medLicense", "衛署食字號", "輸入許可證字號…")}
          {fdrText("licenseOwner", "許可證持有者", "輸入持有者名稱…")}
        </FilterGroup>

        <FilterGroup label="商品資訊">
          {fdrText("brand", "品牌", "輸入品牌關鍵字…")}
          {fdrText("origin", "產地", "輸入產地關鍵字…")}
          {fdrText("manufacturer", "製造商", "輸入製造商名稱…")}
          {fdrText("series", "系列", "輸入系列名稱…")}
          {fdrText("desc", "商品描述", "輸入描述關鍵字…")}
          {fdrChips("segment1", "大分類(分析用)", ALL_SEGMENTS1)}
          {fdrChips("segment2", "次分類(分析用)", ALL_SEGMENTS2)}
          {fdrChips("segment3", "子分類(分析用)", ALL_SEGMENTS3)}
        </FilterGroup>

        <FilterGroup label="審核">
          {fdrYesNo("checkSku", "SKU 審核")}
          {fdrYesNo("checkCat", "品類審核")}
          {fdrText("reviewComment", "審核備註", "輸入備註關鍵字…")}
        </FilterGroup>

        <FilterGroup label="圖片">
          {[
            ["imageUrl",    "商品圖片連結"],
            ["imgMain",     "商品主圖"],
            ["imgActivity", "活動圖檔"],
            ["imgNutrition","包裝熱量照"],
            ["imgScene1",   "情境圖 1"],
            ["imgScene2",   "情境圖 2"],
            ["imgScene3",   "情境圖 3"],
            ["imgScene4",   "情境圖 4"],
          ].map(([key, label]) => (
            <div key={key} className="fdr-row">
              <label className="fdr-label">{label}</label>
              <div className="fdr-chips">
                {[["has","有圖"],["none","無圖"]].map(([val, lbl]) => (
                  <span key={val} className={"fdr-chip" + (advFilters[key] === val ? " on" : "")}
                    onClick={() => setAdv(key)(advFilters[key] === val ? "" : val)}>{lbl}</span>
                ))}
              </div>
            </div>
          ))}
        </FilterGroup>
      </FilterDrawer>
    </>
  );
};

Object.assign(window, { ProductMasterList });
