import Mock from 'mockjs';

/** 文件职责：商品管理页面 Mock 接口。 */
interface MockRequestOptions {
  body: null | string;
  type: string;
  url: string;
}

type ProductStatus = 'off_shelf' | 'on_sale' | 'sold_out';
type ProductKind = 'combo' | 'single';
type ProductSoldoutMode = 'permanent' | 'timed' | 'today';
type ShelfMode = 'draft' | 'now' | 'scheduled';
type BatchActionType =
  | 'batch_delete'
  | 'batch_off'
  | 'batch_on'
  | 'batch_soldout';

interface CategorySeed {
  id: string;
  name: string;
  sort: number;
}

interface ProductSeed {
  categoryId: string;
  defaultKind?: ProductKind;
  name: string;
  price: number;
  subtitle: string;
  tags?: string[];
}

interface ProductRecord {
  categoryId: string;
  description: string;
  id: string;
  imageUrl: string;
  kind: ProductKind;
  name: string;
  notifyManager: boolean;
  originalPrice: null | number;
  price: number;
  recoverAt: null | string;
  remainStock: number;
  salesMonthly: number;
  soldoutMode: null | ProductSoldoutMode;
  soldoutReason: string;
  spuCode: string;
  status: ProductStatus;
  stock: number;
  storeId: string;
  subtitle: string;
  syncToPlatform: boolean;
  tags: string[];
  timedOnShelfAt: null | string;
  updatedAt: string;
}

interface ProductStoreState {
  nextSeq: number;
  products: ProductRecord[];
}

const CATEGORY_SEEDS: CategorySeed[] = [
  { id: 'cat-hot', name: '热销推荐', sort: 1 },
  { id: 'cat-main', name: '主食', sort: 2 },
  { id: 'cat-snack', name: '小吃凉菜', sort: 3 },
  { id: 'cat-soup', name: '汤羹粥品', sort: 4 },
  { id: 'cat-drink', name: '饮品', sort: 5 },
  { id: 'cat-alcohol', name: '酒水', sort: 6 },
  { id: 'cat-combo', name: '套餐', sort: 7 },
];

const PRODUCT_SEEDS: ProductSeed[] = [
  {
    categoryId: 'cat-main',
    name: '宫保鸡丁',
    price: 32,
    subtitle: '经典川菜，香辣可口',
    tags: ['招牌'],
  },
  {
    categoryId: 'cat-main',
    name: '鱼香肉丝',
    price: 28,
    subtitle: '酸甜开胃，佐饭佳选',
    tags: ['必点'],
  },
  {
    categoryId: 'cat-main',
    name: '麻婆豆腐',
    price: 22,
    subtitle: '麻辣鲜香，口感细腻',
    tags: ['辣'],
  },
  {
    categoryId: 'cat-main',
    name: '蛋炒饭',
    price: 15,
    subtitle: '粒粒分明，锅气十足',
  },
  {
    categoryId: 'cat-main',
    name: '红烧排骨',
    price: 42,
    subtitle: '酱香浓郁，肉质软烂',
    tags: ['招牌'],
  },
  {
    categoryId: 'cat-main',
    name: '土豆烧牛腩',
    price: 38,
    subtitle: '软糯入味，牛腩足量',
  },
  {
    categoryId: 'cat-main',
    name: '黑椒牛柳意面',
    price: 36,
    subtitle: '西式风味，黑椒浓香',
    tags: ['新品'],
  },
  {
    categoryId: 'cat-main',
    name: '照烧鸡腿饭',
    price: 27,
    subtitle: '日式酱香，鸡腿多汁',
  },
  {
    categoryId: 'cat-snack',
    name: '蒜香鸡翅',
    price: 24,
    subtitle: '外酥里嫩，蒜香扑鼻',
    tags: ['热卖'],
  },
  {
    categoryId: 'cat-snack',
    name: '香辣薯条',
    price: 12,
    subtitle: '酥脆爽口，轻微辣感',
  },
  {
    categoryId: 'cat-snack',
    name: '凉拌黄瓜',
    price: 10,
    subtitle: '爽脆开胃，解腻优选',
  },
  {
    categoryId: 'cat-snack',
    name: '口水鸡',
    price: 26,
    subtitle: '麻香鲜辣，肉质嫩滑',
    tags: ['辣'],
  },
  {
    categoryId: 'cat-snack',
    name: '椒盐玉米',
    price: 14,
    subtitle: '外脆内甜，老少皆宜',
  },
  {
    categoryId: 'cat-soup',
    name: '酸辣汤',
    price: 18,
    subtitle: '开胃暖身，酸辣平衡',
  },
  {
    categoryId: 'cat-soup',
    name: '番茄蛋花汤',
    price: 16,
    subtitle: '清爽酸甜，营养丰富',
  },
  {
    categoryId: 'cat-soup',
    name: '皮蛋瘦肉粥',
    price: 19,
    subtitle: '米香浓郁，口感顺滑',
  },
  {
    categoryId: 'cat-soup',
    name: '海带排骨汤',
    price: 21,
    subtitle: '汤鲜味美，口感醇厚',
  },
  {
    categoryId: 'cat-drink',
    name: '柠檬气泡水',
    price: 9,
    subtitle: '清爽解腻，微甜口感',
    tags: ['新品'],
  },
  {
    categoryId: 'cat-drink',
    name: '冰粉',
    price: 8,
    subtitle: '夏日必备，冰凉清甜',
    tags: ['限时'],
  },
  {
    categoryId: 'cat-drink',
    name: '酸梅汤',
    price: 11,
    subtitle: '古法熬制，酸甜适中',
  },
  {
    categoryId: 'cat-drink',
    name: '杨枝甘露',
    price: 16,
    subtitle: '果香浓郁，奶香顺滑',
    tags: ['推荐'],
  },
  {
    categoryId: 'cat-drink',
    name: '鲜榨橙汁',
    price: 13,
    subtitle: '现榨现卖，清新自然',
  },
  {
    categoryId: 'cat-alcohol',
    name: '青岛啤酒 500ml',
    price: 12,
    subtitle: '经典口感，冰镇更佳',
  },
  {
    categoryId: 'cat-alcohol',
    name: '哈尔滨啤酒 500ml',
    price: 11,
    subtitle: '麦香清爽，口感顺滑',
  },
  {
    categoryId: 'cat-alcohol',
    name: '乌苏啤酒 620ml',
    price: 15,
    subtitle: '劲爽畅饮，聚餐优选',
    tags: ['热卖'],
  },
  {
    categoryId: 'cat-combo',
    defaultKind: 'combo',
    name: '双人午市套餐',
    price: 69,
    subtitle: '两荤一素+汤+饮料',
    tags: ['套餐'],
  },
  {
    categoryId: 'cat-combo',
    defaultKind: 'combo',
    name: '单人畅享套餐',
    price: 39,
    subtitle: '主食+小吃+饮品',
    tags: ['套餐'],
  },
  {
    categoryId: 'cat-combo',
    defaultKind: 'combo',
    name: '家庭四人餐',
    price: 168,
    subtitle: '经典大份组合，聚会优选',
    tags: ['套餐', '招牌'],
  },
  {
    categoryId: 'cat-hot',
    name: '招牌牛肉饭',
    price: 34,
    subtitle: '高人气单品，复购率高',
    tags: ['热销'],
  },
  {
    categoryId: 'cat-hot',
    name: '经典鸡排饭',
    price: 26,
    subtitle: '酥脆鸡排，份量十足',
    tags: ['热销'],
  },
  {
    categoryId: 'cat-hot',
    name: '藤椒鸡腿饭',
    price: 29,
    subtitle: '麻香清爽，口味独特',
    tags: ['推荐'],
  },
  {
    categoryId: 'cat-hot',
    name: '番茄牛腩饭',
    price: 33,
    subtitle: '酸甜开胃，牛腩软烂',
  },
  {
    categoryId: 'cat-hot',
    name: '椒麻鸡拌面',
    price: 24,
    subtitle: '清爽拌面，椒麻上头',
    tags: ['新品'],
  },
];

const productStoreMap = new Map<string, ProductStoreState>();
const ENABLE_PRODUCT_CATEGORY_MOCK =
  import.meta.env.VITE_MOCK_PRODUCT_CATEGORY === 'true';

/** 解析 URL 查询参数。 */
function parseUrlParams(url: string) {
  const parsed = new URL(url, 'http://localhost');
  const params: Record<string, string> = {};
  parsed.searchParams.forEach((value, key) => {
    params[key] = value;
  });
  return params;
}

/** 解析请求体 JSON。 */
function parseBody(options: MockRequestOptions) {
  if (!options.body) return {};
  try {
    return JSON.parse(options.body) as Record<string, unknown>;
  } catch (error) {
    console.error('[mock-product] parseBody error:', error);
    return {};
  }
}

/** 统一 yyyy-MM-dd HH:mm:ss。 */
function toDateTimeText(date: Date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hour = String(date.getHours()).padStart(2, '0');
  const minute = String(date.getMinutes()).padStart(2, '0');
  const second = String(date.getSeconds()).padStart(2, '0');
  return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}

/** 归一化数值输入。 */
function normalizeNumber(value: unknown, fallback = 0, min = 0) {
  const parsed = Number(value);
  if (!Number.isFinite(parsed)) return fallback;
  return Math.max(min, parsed);
}

/** 归一化正整数。 */
function normalizeInt(value: unknown, fallback = 0, min = 0) {
  return Math.floor(normalizeNumber(value, fallback, min));
}

/** 归一化文本。 */
function normalizeText(value: unknown, fallback = '') {
  const text = String(value ?? '').trim();
  return text || fallback;
}

/** 归一化状态。 */
function normalizeStatus(
  value: unknown,
  fallback: ProductStatus,
): ProductStatus {
  const next = String(value || '');
  if (next === 'on_sale' || next === 'off_shelf' || next === 'sold_out') {
    return next;
  }
  return fallback;
}

/** 归一化商品类型。 */
function normalizeKind(value: unknown, fallback: ProductKind): ProductKind {
  const next = String(value || '');
  return next === 'combo' || next === 'single' ? next : fallback;
}

/** 归一化沽清模式。 */
function normalizeSoldoutMode(
  value: unknown,
  fallback: ProductSoldoutMode,
): ProductSoldoutMode {
  const next = String(value || '');
  if (next === 'today' || next === 'timed' || next === 'permanent') return next;
  return fallback;
}

/** 标准化标签列表。 */
function normalizeTags(value: unknown) {
  if (!Array.isArray(value)) return [];
  return [
    ...new Set(
      value
        .map((item) => String(item || '').trim())
        .filter(Boolean)
        .slice(0, 8),
    ),
  ];
}

/** 查找分类名。 */
function getCategoryName(categoryId: string) {
  return (
    CATEGORY_SEEDS.find((item) => item.id === categoryId)?.name ??
    CATEGORY_SEEDS[0]?.name ??
    '未分类'
  );
}

/** 生成默认商品池。 */
function createDefaultProducts(storeId: string): ProductRecord[] {
  const now = new Date();
  const list: ProductRecord[] = [];
  let seq = 1;
  for (const seed of PRODUCT_SEEDS) {
    const statusSeed = seq % 9;
    let status: ProductStatus = 'on_sale';
    if (statusSeed === 0) {
      status = 'sold_out';
    } else if (statusSeed === 4 || statusSeed === 7) {
      status = 'off_shelf';
    }

    let stock = 20 + (seq % 120);
    if (status === 'sold_out') {
      stock = 0;
    } else if (status === 'off_shelf') {
      stock = 12 + (seq % 20);
    }
    const price = Number(seed.price.toFixed(2));
    const originalPrice =
      seq % 3 === 0 ? Number((price + (3 + (seq % 8))).toFixed(2)) : null;
    const createdAt = new Date(now);
    createdAt.setDate(now.getDate() - (seq % 30));
    list.push({
      id: `prd-${storeId}-${String(seq).padStart(4, '0')}`,
      storeId,
      spuCode: `SPU2024${String(1000 + seq).padStart(5, '0')}`,
      name: seed.name,
      subtitle: seed.subtitle,
      description: `${seed.name}，${seed.subtitle}。`,
      categoryId: seed.categoryId,
      kind: seed.defaultKind ?? 'single',
      price,
      originalPrice,
      stock,
      salesMonthly: 15 + ((seq * 17) % 260),
      tags: seed.tags ? [...seed.tags] : [],
      status,
      soldoutMode: status === 'sold_out' ? 'today' : null,
      remainStock: stock,
      recoverAt: null,
      soldoutReason: status === 'sold_out' ? '食材用完' : '',
      syncToPlatform: true,
      notifyManager: false,
      timedOnShelfAt: null,
      imageUrl: '',
      updatedAt: toDateTimeText(createdAt),
    });
    seq += 1;
  }
  return list;
}

/** 创建默认门店状态。 */
function createDefaultState(storeId: string): ProductStoreState {
  const products = createDefaultProducts(storeId);
  return {
    products,
    nextSeq: products.length + 1,
  };
}

/** 确保门店状态存在。 */
function ensureStoreState(storeId = '') {
  const key = storeId || 'default';
  let state = productStoreMap.get(key);
  if (!state) {
    state = createDefaultState(key);
    productStoreMap.set(key, state);
  }
  return state;
}

/** 构建分类结果（全量口径，不受筛选影响）。 */
function buildCategoryList(products: ProductRecord[]) {
  const countMap = new Map<string, number>();
  for (const item of products) {
    countMap.set(item.categoryId, (countMap.get(item.categoryId) ?? 0) + 1);
  }
  return CATEGORY_SEEDS.toSorted((a, b) => a.sort - b.sort).map((category) => ({
    id: category.id,
    name: category.name,
    sort: category.sort,
    productCount: countMap.get(category.id) ?? 0,
  }));
}

/** 列表项映射。 */
function toListItem(product: ProductRecord) {
  return {
    id: product.id,
    spuCode: product.spuCode,
    name: product.name,
    subtitle: product.subtitle,
    categoryId: product.categoryId,
    categoryName: getCategoryName(product.categoryId),
    kind: product.kind,
    price: product.price,
    originalPrice: product.originalPrice,
    stock: product.stock,
    salesMonthly: product.salesMonthly,
    tags: [...product.tags],
    status: product.status,
    soldoutMode: product.soldoutMode,
    imageUrl: product.imageUrl,
  };
}

/** 详情映射。 */
function toDetailItem(product: ProductRecord) {
  return {
    ...toListItem(product),
    description: product.description,
    remainStock: product.remainStock,
    soldoutReason: product.soldoutReason,
    recoverAt: product.recoverAt,
    syncToPlatform: product.syncToPlatform,
    notifyManager: product.notifyManager,
  };
}

/** 创建商品 ID。 */
function createProductId(storeId: string, seq: number) {
  return `prd-${storeId}-${String(seq).padStart(4, '0')}`;
}

/** 创建 SPU 编码。 */
function createSpuCode(seq: number) {
  return `SPU2026${String(10_000 + seq).slice(-5)}`;
}

/** 解析上架方式。 */
function resolveStatusByShelfMode(
  mode: ShelfMode,
  fallback: ProductStatus,
): ProductStatus {
  if (mode === 'now') return 'on_sale';
  if (mode === 'draft' || mode === 'scheduled') return 'off_shelf';
  return fallback;
}

/** 获取商品分类（默认走真实 TenantApi，需手动开启才启用 mock）。 */
if (ENABLE_PRODUCT_CATEGORY_MOCK) {
  Mock.mock(
    /\/product\/category\/list(?:\?|$)/,
    'get',
    (options: MockRequestOptions) => {
      const params = parseUrlParams(options.url);
      const storeId = String(params.storeId || '');
      const state = ensureStoreState(storeId);
      return {
        code: 200,
        data: buildCategoryList(state.products),
      };
    },
  );
}

/** 获取商品列表。 */
Mock.mock(/\/product\/list(?:\?|$)/, 'get', (options: MockRequestOptions) => {
  const params = parseUrlParams(options.url);
  const storeId = String(params.storeId || '');
  const state = ensureStoreState(storeId);

  const categoryId = String(params.categoryId || '').trim();
  const keyword = String(params.keyword || '')
    .trim()
    .toLowerCase();
  const status = normalizeStatus(params.status, 'on_sale');
  const kind = normalizeKind(params.kind, 'single');
  const hasStatus = Boolean(params.status);
  const hasKind = Boolean(params.kind);

  const page = Math.max(1, normalizeInt(params.page, 1, 1));
  const pageSize = Math.max(
    1,
    Math.min(200, normalizeInt(params.pageSize, 12, 1)),
  );

  const filtered = state.products.filter((item) => {
    if (categoryId && item.categoryId !== categoryId) return false;
    if (keyword) {
      const hit =
        item.name.toLowerCase().includes(keyword) ||
        item.spuCode.toLowerCase().includes(keyword);
      if (!hit) return false;
    }
    if (hasStatus && item.status !== status) return false;
    if (hasKind && item.kind !== kind) return false;
    return true;
  });

  const ordered = filtered.toSorted((a, b) =>
    b.updatedAt.localeCompare(a.updatedAt),
  );
  const start = (page - 1) * pageSize;
  const items = ordered.slice(start, start + pageSize);
  return {
    code: 200,
    data: {
      items: items.map((item) => toListItem(item)),
      total: ordered.length,
      page,
      pageSize,
    },
  };
});

/** 获取商品详情。 */
Mock.mock(/\/product\/detail(?:\?|$)/, 'get', (options: MockRequestOptions) => {
  const params = parseUrlParams(options.url);
  const storeId = String(params.storeId || '');
  const productId = String(params.productId || '');
  const state = ensureStoreState(storeId);
  const product = state.products.find((item) => item.id === productId);
  if (!product) {
    return {
      code: 404,
      data: null,
      message: '商品不存在',
    };
  }
  return {
    code: 200,
    data: toDetailItem(product),
  };
});

/** 保存商品（新增/编辑）。 */
Mock.mock(/\/product\/save/, 'post', (options: MockRequestOptions) => {
  const body = parseBody(options);
  const storeId = normalizeText(body.storeId);
  if (!storeId) {
    return { code: 400, data: null, message: '门店不能为空' };
  }
  const state = ensureStoreState(storeId);

  const id = normalizeText(body.id);
  const shelfMode = normalizeText(body.shelfMode, 'now') as ShelfMode;
  const existingIndex = state.products.findIndex((item) => item.id === id);
  const fallbackStatus =
    existingIndex === -1 ? 'on_sale' : state.products[existingIndex]?.status;
  const statusFromBody = normalizeStatus(
    body.status,
    fallbackStatus || 'on_sale',
  );
  const nextStatus = resolveStatusByShelfMode(shelfMode, statusFromBody);
  const categoryId = normalizeText(
    body.categoryId,
    CATEGORY_SEEDS[0]?.id ?? 'cat-main',
  );

  const existingProduct =
    existingIndex === -1 ? null : state.products[existingIndex];
  const baseProduct: ProductRecord = existingProduct
    ? { ...existingProduct }
    : {
        id: createProductId(storeId, state.nextSeq),
        storeId,
        spuCode: createSpuCode(state.nextSeq),
        name: '',
        subtitle: '',
        description: '',
        categoryId,
        kind: 'single',
        price: 0,
        originalPrice: null,
        stock: 0,
        salesMonthly: 0,
        tags: [],
        status: 'off_shelf',
        soldoutMode: null,
        remainStock: 0,
        recoverAt: null,
        soldoutReason: '',
        syncToPlatform: true,
        notifyManager: false,
        timedOnShelfAt: null,
        imageUrl: '',
        updatedAt: toDateTimeText(new Date()),
      };

  baseProduct.name = normalizeText(body.name, baseProduct.name);
  baseProduct.subtitle = normalizeText(body.subtitle, baseProduct.subtitle);
  baseProduct.description = normalizeText(
    body.description,
    baseProduct.description || `${baseProduct.name}，${baseProduct.subtitle}`,
  );
  baseProduct.categoryId = CATEGORY_SEEDS.some((item) => item.id === categoryId)
    ? categoryId
    : baseProduct.categoryId;
  baseProduct.kind = normalizeKind(body.kind, baseProduct.kind);
  baseProduct.price = Number(
    normalizeNumber(body.price, baseProduct.price, 0).toFixed(2),
  );
  const originalPrice = normalizeNumber(body.originalPrice, -1, 0);
  baseProduct.originalPrice =
    originalPrice > 0 ? Number(originalPrice.toFixed(2)) : null;
  baseProduct.stock = normalizeInt(body.stock, baseProduct.stock, 0);
  baseProduct.tags = normalizeTags(body.tags);
  baseProduct.status = nextStatus;
  baseProduct.soldoutMode = nextStatus === 'sold_out' ? 'today' : null;
  baseProduct.recoverAt = null;
  baseProduct.soldoutReason = nextStatus === 'sold_out' ? '库存售罄' : '';
  baseProduct.remainStock = baseProduct.stock;
  baseProduct.syncToPlatform = true;
  baseProduct.notifyManager = false;
  baseProduct.timedOnShelfAt =
    shelfMode === 'scheduled' ? normalizeText(body.timedOnShelfAt) : null;
  baseProduct.updatedAt = toDateTimeText(new Date());

  if (!baseProduct.name) {
    return {
      code: 400,
      data: null,
      message: '商品名称不能为空',
    };
  }

  if (existingIndex === -1) {
    state.products.unshift(baseProduct);
    state.nextSeq += 1;
  } else {
    state.products.splice(existingIndex, 1, baseProduct);
  }

  return {
    code: 200,
    data: toDetailItem(baseProduct),
  };
});

/** 删除商品。 */
Mock.mock(/\/product\/delete/, 'post', (options: MockRequestOptions) => {
  const body = parseBody(options);
  const storeId = normalizeText(body.storeId);
  const productId = normalizeText(body.productId);
  if (!storeId || !productId) {
    return { code: 400, data: null, message: '参数不完整' };
  }
  const state = ensureStoreState(storeId);
  state.products = state.products.filter((item) => item.id !== productId);
  return { code: 200, data: null };
});

/** 修改商品状态。 */
Mock.mock(
  /\/product\/status\/change/,
  'post',
  (options: MockRequestOptions) => {
    const body = parseBody(options);
    const storeId = normalizeText(body.storeId);
    const productId = normalizeText(body.productId);
    if (!storeId || !productId) {
      return { code: 400, data: null, message: '参数不完整' };
    }
    const state = ensureStoreState(storeId);
    const product = state.products.find((item) => item.id === productId);
    if (!product) return { code: 404, data: null, message: '商品不存在' };

    const nextStatus = normalizeStatus(body.status, product.status);
    product.status = nextStatus;
    if (nextStatus === 'sold_out') {
      product.soldoutMode = 'today';
      product.soldoutReason = product.soldoutReason || '库存售罄';
      product.remainStock = 0;
      product.stock = 0;
    } else {
      product.soldoutMode = null;
      product.recoverAt = null;
      product.soldoutReason = '';
    }
    product.updatedAt = toDateTimeText(new Date());
    return { code: 200, data: toListItem(product) };
  },
);

/** 商品沽清。 */
Mock.mock(/\/product\/soldout/, 'post', (options: MockRequestOptions) => {
  const body = parseBody(options);
  const storeId = normalizeText(body.storeId);
  const productId = normalizeText(body.productId);
  if (!storeId || !productId) {
    return { code: 400, data: null, message: '参数不完整' };
  }
  const state = ensureStoreState(storeId);
  const product = state.products.find((item) => item.id === productId);
  if (!product) return { code: 404, data: null, message: '商品不存在' };

  const mode = normalizeSoldoutMode(body.mode, 'today');
  const remainStock = normalizeInt(body.remainStock, 0, 0);
  product.status = 'sold_out';
  product.soldoutMode = mode;
  product.remainStock = remainStock;
  product.stock = remainStock;
  product.soldoutReason = normalizeText(body.reason);
  product.recoverAt = mode === 'timed' ? normalizeText(body.recoverAt) : null;
  product.syncToPlatform = Boolean(body.syncToPlatform);
  product.notifyManager = Boolean(body.notifyManager);
  product.updatedAt = toDateTimeText(new Date());
  return { code: 200, data: toDetailItem(product) };
});

/** 批量商品动作。 */
Mock.mock(/\/product\/batch/, 'post', (options: MockRequestOptions) => {
  const body = parseBody(options);
  const storeId = normalizeText(body.storeId);
  const action = normalizeText(body.action) as BatchActionType;
  const productIds = Array.isArray(body.productIds)
    ? body.productIds.map((item) => String(item || '').trim()).filter(Boolean)
    : [];

  if (!storeId || productIds.length === 0) {
    return {
      code: 400,
      data: null,
      message: '批量操作参数不完整',
    };
  }

  const state = ensureStoreState(storeId);
  const idSet = new Set(productIds);
  const targets = state.products.filter((item) => idSet.has(item.id));
  let successCount = 0;

  if (action === 'batch_delete') {
    const before = state.products.length;
    state.products = state.products.filter((item) => !idSet.has(item.id));
    successCount = before - state.products.length;
  } else {
    for (const item of targets) {
      switch (action) {
        case 'batch_off': {
          item.status = 'off_shelf';
          item.soldoutMode = null;
          item.recoverAt = null;
          item.soldoutReason = '';

          break;
        }
        case 'batch_on': {
          item.status = 'on_sale';
          item.soldoutMode = null;
          item.recoverAt = null;
          item.soldoutReason = '';

          break;
        }
        case 'batch_soldout': {
          item.status = 'sold_out';
          item.soldoutMode = normalizeSoldoutMode(body.mode, 'today');
          item.remainStock = normalizeInt(body.remainStock, 0, 0);
          item.stock = item.remainStock;
          item.soldoutReason = normalizeText(body.reason);
          item.recoverAt =
            item.soldoutMode === 'timed' ? normalizeText(body.recoverAt) : null;
          item.syncToPlatform = Boolean(body.syncToPlatform ?? true);
          item.notifyManager = Boolean(body.notifyManager ?? false);

          break;
        }
        // No default
      }
      item.updatedAt = toDateTimeText(new Date());
      successCount += 1;
    }
  }

  const totalCount = productIds.length;
  const failedCount = Math.max(totalCount - successCount, 0);
  return {
    code: 200,
    data: {
      action,
      totalCount,
      successCount,
      failedCount,
    },
  };
});
