// TEMU合规助手 - 后台脚本（照抄大白鹅）

// ========== 全局状态 ==========
const state = {
  mallId: null,
  mallName: null,
  antiContent: null,
  serverAuthToken: null,
  serverAuthUser: null,
  serverAuthAt: 0,
  authUpdatedAt: 0,
  templates: [],
  products: [],
  selectedProducts: [],
  isUploading: false,
  uploadProgress: 0
};

const TEMU_SELLER_HOSTS = [
  'agentseller.temu.com',
  'agentseller-us.temu.com',
  'agentseller-eu.temu.com',
  'seller.temu.com',
  'seller-eu.temu.com',
  'commerce.temu.com',
  'seller.kuajingmaihuo.com'
];

function isTemuSellerUrl(url = '') {
  try {
    const parsed = new URL(String(url || ''));
    const host = parsed.hostname.toLowerCase();
    if (TEMU_SELLER_HOSTS.some(item => host === item || host.endsWith(`.${item}`))) return true;
    return (host === 'www.temu.com' || host === 'temu.com') && parsed.pathname.includes('/mall');
  } catch (_) {
    const text = String(url || '').toLowerCase();
    return TEMU_SELLER_HOSTS.some(item => text.includes(item)) || text.includes('temu.com/mall');
  }
}

function getUrlHostname(url = '') {
  try {
    return new URL(String(url || '')).hostname.toLowerCase();
  } catch (_) {
    return '';
  }
}

function normalizeMallIdValue(value) {
  const text = String(value || '').trim();
  if (!text) return '';
  const match = text.match(/\d{6,}/);
  return match ? match[0] : text.split(',')[0].trim();
}

function normalizeAntiContentValue(value) {
  const text = String(value || '').trim();
  if (!text) return '';
  const parts = text.split(/[,，]/).map(part => part.trim()).filter(Boolean);
  return parts[0] || '';
}

function normalizeAuthRecord(auth = {}) {
  return {
    ...auth,
    mallId: normalizeMallIdValue(auth.mallId),
    antiContent: normalizeAntiContentValue(auth.antiContent)
  };
}

async function persistNormalizedAuth(auth = {}, context = '认证信息清理') {
  const normalized = normalizeAuthRecord(auth);
  if (!normalized.mallId && !normalized.antiContent) return normalized;
  const stored = await chrome.storage.local.get('temuAuth').catch(() => ({}));
  const merged = {
    ...(stored.temuAuth || {}),
    ...auth,
    mallId: normalized.mallId || normalizeMallIdValue(stored.temuAuth?.mallId || ''),
    antiContent: normalized.antiContent || normalizeAntiContentValue(stored.temuAuth?.antiContent || ''),
    mallName: auth.mallName || stored.temuAuth?.mallName || state.mallName || null,
    updatedAt: Date.now()
  };
  await safeStorageSet({
    temuAuth: merged,
    ...(merged.mallId ? { temuLocalMallId: merged.mallId } : {})
  }, context);
  return merged;
}

function getTemplateKey(mallId, templateType = 'compliance') {
  const prefix = String(templateType || 'compliance') === 'qualification'
    ? 'temuQualificationTemplates_'
    : 'temuTemplates_';
  return mallId ? `${prefix}${mallId}` : '';
}

async function resolveComplianceTemplateStorage(mallIdHint = null, templateType = 'compliance') {
  const auth = await getAuth().catch(() => null);
  const mallId = normalizeMallIdValue(mallIdHint || state.mallId || auth?.mallId || '');
  if (!mallId) {
    return { mallId: null, key: null, templates: [] };
  }
  const key = getTemplateKey(mallId, templateType);
  const result = await chrome.storage.local.get([key]);
  const current = Array.isArray(result[key]) ? result[key] : [];
  return {
    mallId,
    key,
    templates: current
  };
}

async function resolveCurrentComplianceMallId() {
  const auth = await getAuth().catch(() => null);
  const mallId = normalizeMallIdValue(state.mallId || auth?.mallId || '');
  return mallId || '';
}

async function findTemuSellerTab(preferredUrl = '') {
  const tabs = await chrome.tabs.query({});
  const candidates = tabs.filter(tab => typeof tab.url === 'string' && isTemuSellerUrl(tab.url));
  if (!candidates.length) return null;
  const preferredHost = getUrlHostname(preferredUrl);
  const scoreTab = (tab) => {
    const host = getUrlHostname(tab.url);
    if (preferredHost && host === preferredHost) return 30;
    if (host.includes('agentseller')) return 20;
    if (host.includes('seller.kuajingmaihuo.com')) return 18;
    if (host.includes('seller.temu.com') || host.includes('commerce.temu.com')) return 15;
    return 10;
  };
  return [...candidates].sort((a, b) => {
    const scoreDiff = scoreTab(b) - scoreTab(a);
    if (scoreDiff) return scoreDiff;
    return (b.lastAccessed || b.id || 0) - (a.lastAccessed || a.id || 0);
  })[0] || null;
}

async function executeTemuPageFetch({ url, method = 'POST', headers = {}, body = null, timeoutMs = 20000, exactUrlOnly = false }) {
  const tab = await findTemuSellerTab(url);
  if (!tab?.id) {
    throw new Error('请先打开 TEMU 卖家后台页面后再重试');
  }

  const [execResult] = await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    world: 'MAIN',
    args: [{ url, method, headers, body, timeoutMs, exactUrlOnly }],
    func: async (request) => {
      const readFirst = (...values) => values.find(value => value !== undefined && value !== null && value !== '') || '';
      const readMallId = () => {
        try {
          const parsed = new URL(location.href);
          const fromUrl = parsed.searchParams.get('mall_id') || parsed.searchParams.get('mallId') || parsed.searchParams.get('mallid');
          if (fromUrl) return String(fromUrl);
        } catch (_) {}
        return String(readFirst(
          localStorage.getItem('agentseller-mall-info-id'),
          localStorage.getItem('seller-mall-info-id'),
          sessionStorage.getItem('agentseller-mall-info-id'),
          sessionStorage.getItem('seller-mall-info-id')
        ) || '');
      };

      const controller = new AbortController();
      const timer = setTimeout(() => controller.abort(new Error('timeout')), Number(request.timeoutMs || 20000));
      try {
        const runtimeAntiContent = (() => {
          try {
            return typeof window.secretKeyAnti === 'function' ? window.secretKeyAnti() : '';
          } catch (_) {
            return '';
          }
        })();
        const antiContent = readFirst(
          runtimeAntiContent,
          localStorage.getItem('anti-content'),
          localStorage.getItem('Anti-Content'),
          sessionStorage.getItem('anti-content'),
          sessionStorage.getItem('Anti-Content')
        );
        const mallId = readMallId();
        const finalHeaders = { 'Content-Type': 'application/json', ...(request.headers || {}) };
        if (antiContent) finalHeaders['anti-content'] = antiContent;
        if (!finalHeaders.mallid && mallId) finalHeaders.mallid = mallId;

        const requestUrls = (() => {
          const urls = [];
          if (!request.exactUrlOnly) {
            try {
              const parsed = new URL(request.url);
              const sameOriginUrl = `${location.origin}${parsed.pathname}${parsed.search}`;
              if (sameOriginUrl && sameOriginUrl !== request.url) urls.push(sameOriginUrl);
            } catch (_) {}
          }
          urls.push(request.url);
          return [...new Set(urls.filter(Boolean))];
        })();

        const parseResponseText = (rawText) => {
          try {
            return rawText ? JSON.parse(rawText) : null;
          } catch (_) {
            return rawText;
          }
        };
        const requestByFetch = async (requestUrl) => {
          const response = await fetch(requestUrl, {
            method: request.method || 'POST',
            headers: finalHeaders,
            body: request.body,
            credentials: 'include',
            signal: controller.signal
          });
          const rawText = await response.text();
          return {
            ok: response.ok,
            status: response.status,
            data: parseResponseText(rawText),
            url: requestUrl
          };
        };
        const requestByXhr = (requestUrl) => new Promise((resolve) => {
          try {
            const xhr = new XMLHttpRequest();
            xhr.open(request.method || 'POST', requestUrl, true);
            xhr.withCredentials = true;
            Object.entries(finalHeaders).forEach(([key, value]) => {
              if (value !== undefined && value !== null && value !== '') {
                xhr.setRequestHeader(key, String(value));
              }
            });
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== 4) return;
              resolve({
                ok: xhr.status >= 200 && xhr.status < 300,
                status: xhr.status,
                data: parseResponseText(xhr.responseText || ''),
                url: requestUrl
              });
            };
            xhr.onerror = () => resolve({
              ok: false,
              status: xhr.status || 0,
              error: 'XMLHttpRequest 请求失败',
              url: requestUrl
            });
            xhr.ontimeout = () => resolve({
              ok: false,
              status: xhr.status || 0,
              error: 'XMLHttpRequest 请求超时',
              url: requestUrl
            });
            xhr.timeout = Number(request.timeoutMs || 20000);
            xhr.send(request.body);
          } catch (error) {
            resolve({
              ok: false,
              status: 0,
              error: error?.message || String(error),
              url: requestUrl
            });
          }
        });

        let lastResult = null;
        let lastError = '';
        for (const requestUrl of requestUrls) {
          try {
            if (typeof fetch === 'function') {
              try {
                lastResult = await requestByFetch(requestUrl);
              } catch (fetchError) {
                lastError = fetchError?.message || String(fetchError);
                if (typeof XMLHttpRequest === 'function') {
                  lastResult = await requestByXhr(requestUrl);
                } else {
                  throw fetchError;
                }
              }
            } else if (typeof XMLHttpRequest === 'function') {
              lastResult = await requestByXhr(requestUrl);
            } else {
              throw new Error('当前 TEMU 页面不支持 fetch/XMLHttpRequest，无法发起后台请求');
            }
            if (lastResult?.ok) return lastResult;
            lastError = lastResult?.error || '';
          } catch (requestError) {
            lastError = requestError?.message || String(requestError);
          }
        }

        return lastResult || {
          ok: false,
          status: 0,
          error: lastError || 'TEMU 后台页面请求失败'
        };
      } catch (error) {
        return {
          ok: false,
          status: 0,
          error: error?.message || String(error)
        };
      } finally {
        clearTimeout(timer);
      }
    }
  });

  const result = execResult?.result;
  if (!result) {
    throw new Error('页面请求执行失败：未返回结果');
  }
  if (result.error && !result.data) {
    throw new Error(result.error);
  }
  if (result.ok === false) {
    const message = getTemuApiMessage(result.data, result.error || `TEMU 后台接口 HTTP ${result.status || 0}`);
    throw new Error(message);
  }
  return result;
}

async function executeTemuPageRequestVariants(variants = [], timeoutMs = 10000) {
  let lastError = '';
  for (const variant of variants) {
    try {
      const pageResult = await executeTemuPageFetch({
        url: variant.url,
        method: variant.method || 'POST',
        headers: variant.headers || {},
        body: variant.body === undefined ? null : JSON.stringify(variant.body),
        timeoutMs
      });
      const payload = variant.extract ? variant.extract(pageResult.data) : pageResult.data;
      if (payload) {
        return { success: true, payload, sourceUrl: variant.url, raw: pageResult.data };
      }
      lastError = '接口未返回可用字段';
    } catch (error) {
      lastError = error?.message || String(error);
    }
  }
  return { success: false, error: lastError || '实时请求失败' };
}

const TEMU_DELIST_TOOL_ID = 2406230000031;
const TEMU_PUBLISH_TOOL_ID = 2406230000016;
const TEMU_DELIST_DEFAULT_REASON = {
  code: 2001,
  desc: '业务调整下架'
};

function normalizeDelistIds(ids = []) {
  return Array.from(new Set(
    ids
      .flat()
      .map(id => String(id || '').trim())
      .filter(id => /^\d+$/.test(id))
  ));
}

function getDelistApiMessage(data = {}, fallback = '接口返回失败') {
  return data?.errorMsg || data?.error_msg || data?.message || data?.msg || data?.error || fallback;
}

function getVerifiedTemuPublishToolId() {
  const toolId = Number(TEMU_PUBLISH_TOOL_ID);
  if (!Number.isFinite(toolId) || toolId <= 0 || toolId === TEMU_DELIST_TOOL_ID) {
    throw new Error('未验证 TEMU「商品发布到站点」官方工具 ID，已阻止批量上架，避免误执行商品下架。请先在 TEMU 官方客服入口抓取发布工具请求后再启用。');
  }
  return toolId;
}

const customizedBatchActionProgressMap = new Map();
const CUSTOMIZED_BATCH_ACTION_PROGRESS_TTL = 10 * 60 * 1000;

function pruneCustomizedBatchActionProgress() {
  const now = Date.now();
  for (const [taskId, task] of customizedBatchActionProgressMap.entries()) {
    const updatedAt = Number(task?.updatedAt || task?.startedAt || 0);
    if (!updatedAt || now - updatedAt > CUSTOMIZED_BATCH_ACTION_PROGRESS_TTL) {
      customizedBatchActionProgressMap.delete(taskId);
    }
  }
}

function updateCustomizedBatchActionProgress(taskId, patch = {}) {
  const id = String(taskId || '').trim();
  if (!id) return null;
  pruneCustomizedBatchActionProgress();
  const previous = customizedBatchActionProgressMap.get(id) || {
    taskId: id,
    status: 'running',
    total: 0,
    completed: 0,
    successCount: 0,
    failCount: 0,
    results: [],
    startedAt: Date.now()
  };
  const next = {
    ...previous,
    ...patch,
    taskId: id,
    updatedAt: Date.now()
  };
  customizedBatchActionProgressMap.set(id, next);
  return next;
}

function readCustomizedBatchActionProgress(taskId) {
  pruneCustomizedBatchActionProgress();
  const id = String(taskId || '').trim();
  if (!id) return { success: false, error: '缺少任务 ID' };
  const task = customizedBatchActionProgressMap.get(id);
  if (!task) return { success: false, error: '任务进度不存在或已过期' };
  return { success: true, task };
}

async function temuSellerPagePost(url, body, auth, timeoutMs = 20000, options = {}) {
  const result = await executeTemuPageFetch({
    url,
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'mallid': auth?.mallId || '',
      'anti-content': auth?.antiContent || ''
    },
    body: JSON.stringify(body),
    timeoutMs,
    exactUrlOnly: !!options.exactUrlOnly
  });
  return result.data;
}

async function temuSellerBackgroundPost(url, body, auth, timeoutMs = 20000) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(new Error('timeout')), Number(timeoutMs || 20000));
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'mallid': auth?.mallId || '',
        'anti-content': auth?.antiContent || ''
      },
      body: JSON.stringify(body),
      credentials: 'include',
      signal: controller.signal
    });
    const rawText = await response.text();
    let data = null;
    try {
      data = rawText ? JSON.parse(rawText) : null;
    } catch (_) {
      data = rawText;
    }
    if (!response.ok) {
      const message = getTemuApiMessage(data, `请求失败 ${response.status}`);
      throw new Error(message);
    }
    return data;
  } finally {
    clearTimeout(timer);
  }
}

async function temuSellerPost(url, body, auth, timeoutMs = 20000) {
  let pageError = '';
  try {
    return await temuSellerPagePost(url, body, auth, timeoutMs);
  } catch (error) {
    pageError = error?.message || String(error);
  }

  try {
    return await temuSellerBackgroundPost(url, body, auth, timeoutMs);
  } catch (error) {
    const backgroundError = error?.message || String(error);
    throw new Error(backgroundError || pageError || 'TEMU 后台接口请求失败');
  }
}

async function temuSellerExactPost(url, body, auth, timeoutMs = 20000) {
  let pageError = '';
  try {
    return await temuSellerPagePost(url, body, auth, timeoutMs, { exactUrlOnly: true });
  } catch (error) {
    pageError = error?.message || String(error);
  }

  try {
    return await temuSellerBackgroundPost(url, body, auth, timeoutMs);
  } catch (error) {
    const backgroundError = error?.message || String(error);
    throw new Error(backgroundError || pageError || 'TEMU 后台接口请求失败');
  }
}

async function batchDelistCustomizedSkc(params = {}) {
  const progressTaskId = String(params.progressTaskId || '').trim();
  const progressAction = 'delist';
  let auth = null;
  try {
    auth = await getAuth();
  } catch (error) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      error: error?.message || String(error)
    });
    return { success: false, error: error?.message || String(error) };
  }
  if (!auth?.mallId) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      error: '请先连接 TEMU 店铺后再下架'
    });
    return { success: false, error: '请先连接 TEMU 店铺后再下架' };
  }

  const skcIds = normalizeDelistIds(params.skcIds || params.ids || []);
  if (!skcIds.length) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      error: '请提供要下架的 SKC ID'
    });
    return { success: false, error: '请提供要下架的 SKC ID' };
  }

  updateCustomizedBatchActionProgress(progressTaskId, {
    action: progressAction,
    status: 'running',
    total: skcIds.length,
    completed: 0,
    successCount: 0,
    failCount: 0,
    results: [],
    message: `准备提交 ${skcIds.length} 个 SKC 下架申请`
  });

  const optionInfo = {
    ...TEMU_DELIST_DEFAULT_REASON,
    ...(params.optionInfo && typeof params.optionInfo === 'object' ? params.optionInfo : {})
  };

  let textResp = null;
  try {
    textResp = await temuSellerPagePost(
      'https://agentseller.temu.com/bg/cute/api/merchantService/chat/sendMessage',
      { content: '商品下架', contentType: 1 },
      auth,
      20000
    );
  } catch (error) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      total: skcIds.length,
      completed: 0,
      successCount: 0,
      failCount: skcIds.length,
      error: error?.message || String(error)
    });
    return { success: false, error: error?.message || String(error) };
  }
  if (!textResp?.success || !textResp?.result?.msgId) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      total: skcIds.length,
      completed: 0,
      successCount: 0,
      failCount: skcIds.length,
      error: getDelistApiMessage(textResp, '客服会话创建失败')
    });
    return {
      success: false,
      error: getDelistApiMessage(textResp, '客服会话创建失败'),
      raw: textResp
    };
  }

  const parentMsgId = textResp.result.msgId;
  const results = [];

  for (const skcId of skcIds) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'running',
      total: skcIds.length,
      completed: results.length,
      successCount: results.filter(item => item.success).length,
      failCount: results.filter(item => !item.success).length,
      currentSkcId: skcId,
      message: `正在提交 SKC ${skcId} 下架申请`
    });
    try {
      await sleep(800);
      const infoResp = await temuSellerPagePost(
        'https://agentseller.temu.com/api/kiana/marvel-supplier/api/ultraman/chat/reception/queryProductSkcBasicInfo',
        {
          productSkcId: Number(skcId),
          toolId: TEMU_DELIST_TOOL_ID
        },
        auth,
        20000
      );
      if (!infoResp?.success || !infoResp?.result) {
        throw new Error(getDelistApiMessage(infoResp, '查询 SKC 基础信息失败'));
      }

      const product = infoResp.result;
      const cardContent = JSON.stringify({
        name: product.productName || `SKC ID: ${skcId}`,
        img: product.productPicture || product.productImage || '',
        dataType: 1,
        dataId: product.productSkcId || Number(skcId),
        toolId: TEMU_DELIST_TOOL_ID,
        optionTitle: '下架原因',
        optionInfo
      });

      await sleep(800);
      const cardResp = await temuSellerPagePost(
        'https://agentseller.temu.com/bg/cute/api/merchantService/chat/sendMessage',
        {
          content: cardContent,
          contentType: 7,
          parentMsgId
        },
        auth,
        20000
      );
      if (!cardResp?.success) {
        throw new Error(getDelistApiMessage(cardResp, '提交下架卡片失败'));
      }

      results.push({
        skcId,
        success: true,
        productName: product.productName || '',
        msgId: cardResp.result?.msgId || null
      });
    } catch (error) {
      results.push({
        skcId,
        success: false,
        error: error?.message || String(error)
      });
    }
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'running',
      total: skcIds.length,
      completed: results.length,
      successCount: results.filter(item => item.success).length,
      failCount: results.filter(item => !item.success).length,
      currentSkcId: skcId,
      results: [...results],
      message: `已处理 ${results.length}/${skcIds.length} 个 SKC`
    });
  }

  const successCount = results.filter(item => item.success).length;
  const failCount = results.length - successCount;
  updateCustomizedBatchActionProgress(progressTaskId, {
    action: progressAction,
    status: successCount > 0 ? 'done' : 'failed',
    total: results.length,
    completed: results.length,
    successCount,
    failCount,
    results,
    message: failCount ? `已提交 ${successCount} 个，失败 ${failCount} 个` : `已提交 ${successCount} 个 SKC 下架申请`
  });
  return {
    success: successCount > 0,
    message: failCount ? `已提交 ${successCount} 个，失败 ${failCount} 个` : `已提交 ${successCount} 个 SKC 下架申请`,
    successCount,
    failCount,
    total: results.length,
    parentMsgId,
    optionInfo,
    results
  };
}

async function batchPublishCustomizedSkc(params = {}) {
  const progressTaskId = String(params.progressTaskId || '').trim();
  const progressAction = 'publish';
  let auth = null;
  try {
    auth = await getAuth();
  } catch (error) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      error: error?.message || String(error)
    });
    return { success: false, error: error?.message || String(error) };
  }
  if (!auth?.mallId) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      error: '请先连接 TEMU 店铺后再上架'
    });
    return { success: false, error: '请先连接 TEMU 店铺后再上架' };
  }

  const skcIds = normalizeDelistIds(params.skcIds || params.ids || []);
  if (!skcIds.length) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      error: '请提供要上架的 SKC ID'
    });
    return { success: false, error: '请提供要上架的 SKC ID' };
  }

  let publishToolId = null;
  try {
    publishToolId = getVerifiedTemuPublishToolId();
  } catch (error) {
    const message = error?.message || String(error);
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      total: skcIds.length,
      completed: 0,
      successCount: 0,
      failCount: skcIds.length,
      error: message,
      message
    });
    return { success: false, error: message, total: skcIds.length, successCount: 0, failCount: skcIds.length };
  }

  updateCustomizedBatchActionProgress(progressTaskId, {
    action: progressAction,
    status: 'running',
    total: skcIds.length,
    completed: 0,
    successCount: 0,
    failCount: 0,
    results: [],
    message: `准备提交 ${skcIds.length} 个 SKC 上架申请`
  });

  let textResp = null;
  try {
    textResp = await temuSellerPagePost(
      'https://agentseller.temu.com/bg/cute/api/merchantService/chat/sendMessage',
      { content: '商品发布到站点', contentType: 1 },
      auth,
      20000
    );
  } catch (error) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      total: skcIds.length,
      completed: 0,
      successCount: 0,
      failCount: skcIds.length,
      error: error?.message || String(error)
    });
    return { success: false, error: error?.message || String(error) };
  }
  if (!textResp?.success || !textResp?.result?.msgId) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'failed',
      total: skcIds.length,
      completed: 0,
      successCount: 0,
      failCount: skcIds.length,
      error: getDelistApiMessage(textResp, '客服会话创建失败')
    });
    return {
      success: false,
      error: getDelistApiMessage(textResp, '客服会话创建失败'),
      raw: textResp
    };
  }

  const parentMsgId = textResp.result.msgId;
  const results = [];

  for (const skcId of skcIds) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'running',
      total: skcIds.length,
      completed: results.length,
      successCount: results.filter(item => item.success).length,
      failCount: results.filter(item => !item.success).length,
      currentSkcId: skcId,
      message: `正在提交 SKC ${skcId} 上架申请`
    });
    try {
      await sleep(800);
      const infoResp = await temuSellerPagePost(
        'https://agentseller.temu.com/api/kiana/marvel-supplier/api/ultraman/chat/reception/queryProductSkcBasicInfo',
        {
          productSkcId: Number(skcId),
          toolId: publishToolId
        },
        auth,
        20000
      );
      if (!infoResp?.success || !infoResp?.result) {
        throw new Error(getDelistApiMessage(infoResp, '查询 SKC 基础信息失败'));
      }

      const product = infoResp.result;
      const cardContent = JSON.stringify({
        name: product.productName || `SKC ID: ${skcId}`,
        img: product.productPicture || product.productImage || '',
        dataType: 1,
        dataId: product.productSkcId || Number(skcId),
        toolId: publishToolId
      });

      await sleep(800);
      const cardResp = await temuSellerPagePost(
        'https://agentseller.temu.com/bg/cute/api/merchantService/chat/sendMessage',
        {
          content: cardContent,
          contentType: 7,
          parentMsgId
        },
        auth,
        20000
      );
      if (!cardResp?.success) {
        throw new Error(getDelistApiMessage(cardResp, '提交上架卡片失败'));
      }

      results.push({
        skcId,
        success: true,
        productName: product.productName || '',
        msgId: cardResp.result?.msgId || null
      });
    } catch (error) {
      results.push({
        skcId,
        success: false,
        error: error?.message || String(error)
      });
    }
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: progressAction,
      status: 'running',
      total: skcIds.length,
      completed: results.length,
      successCount: results.filter(item => item.success).length,
      failCount: results.filter(item => !item.success).length,
      currentSkcId: skcId,
      results: [...results],
      message: `已处理 ${results.length}/${skcIds.length} 个 SKC`
    });
  }

  const successCount = results.filter(item => item.success).length;
  const failCount = results.length - successCount;
  updateCustomizedBatchActionProgress(progressTaskId, {
    action: progressAction,
    status: successCount > 0 ? 'done' : 'failed',
    total: results.length,
    completed: results.length,
    successCount,
    failCount,
    results,
    message: failCount ? `已提交 ${successCount} 个，失败 ${failCount} 个` : `已提交 ${successCount} 个 SKC 上架申请`
  });
  return {
    success: successCount > 0,
    message: failCount ? `已提交 ${successCount} 个，失败 ${failCount} 个` : `已提交 ${successCount} 个 SKC 上架申请`,
    successCount,
    failCount,
    total: results.length,
    parentMsgId,
    results
  };
}

async function clearAuthCache() {
  state.mallId = null;
  state.mallName = null;
  state.antiContent = null;
  state.authUpdatedAt = 0;
  await chrome.storage.local.remove(['temuAuth', 'temuLocalMallId']);
}

const buyerCollectCache = new Map();
let buyerCollectWorkerTabId = null;
let buyerCollectCooldownUntil = 0;

// ========== 合规信息模板保存状态（照抄大白鹅）==========
const complianceState = {
  spuId: '',
  mallId: '',
  name: '',
  type: '',  // 0=普通模板，1=定制模板
  requestListener: null  // 监听器引用
};

function compactComplianceValue(value, depth = 0) {
  if (value === null || value === undefined) return value;
  if (typeof value === 'string') return value.length > 180 ? `${value.slice(0, 180)}…` : value;
  if (typeof value === 'number' || typeof value === 'boolean') return value;
  if (Array.isArray(value)) {
    const maxItems = depth === 0 ? 10 : depth === 1 ? 5 : 3;
    return value.slice(0, maxItems).map(item => compactComplianceValue(item, depth + 1));
  }
  if (typeof value !== 'object') return value;

  const out = {};
  for (const [key, item] of Object.entries(value)) {
    if (/^(raw|html|base64|blob|buffer|file|content)$/i.test(key)) continue;
    if (typeof item === 'function') continue;
    const compacted = compactComplianceValue(item, depth + 1);
    if (compacted !== undefined) out[key] = compacted;
  }
  return out;
}

function compactComplianceTemplateForStorage(template = {}) {
  const data = template.data || {};
  const editList = Array.isArray(data.template_edit_request_list) ? data.template_edit_request_list : [];
  return {
    ...template,
    data: {
      spu_id: data.spu_id,
      goods_id: data.goods_id,
      cat_id: data.cat_id,
      template_edit_request_list: editList.map(item => ({
        task_type: item.task_type,
        task_id: item.task_id,
        task_status: item.task_status,
        template_id: item.template_id,
        task_name: item.task_name,
        is_not_required: item.is_not_required,
        properties: compactComplianceValue(item.properties || {}),
        input_text: compactComplianceValue(item.input_text || {}),
        images: compactComplianceValue(item.images || {}),
        rep_detail_list: compactComplianceValue(item.rep_detail_list || []),
        sku_group_multi_detail_list: compactComplianceValue(item.sku_group_multi_detail_list || [])
      }))
    },
    taskCount: template.taskCount || editList.length,
    taskTypes: template.taskTypes || editList.map(item => item.task_type).filter(Boolean)
  };
}

async function saveComplianceTemplateList(tplKey, templates) {
  if (!tplKey) return;
  const compacted = templates.map(compactComplianceTemplateForStorage);
  try {
    await chrome.storage.local.set({ [tplKey]: compacted });
  } catch (error) {
    console.warn('[TEMU运营助手] 模板数据过大，尝试降级保存:', error);
    const recent = compacted.slice(-20);
    try {
      await chrome.storage.local.set({ [tplKey]: recent });
    } catch (compactError) {
      console.warn('[TEMU运营助手] 模板降级后仍超出配额，仅保留最近10个模板:', compactError);
      await chrome.storage.local.set({ [tplKey]: recent.slice(-10) });
    }
  }
}

async function safeStorageSet(values = {}, context = 'storage') {
  try {
    await chrome.storage.local.set(values);
    return true;
  } catch (error) {
    console.warn(`[TEMU运营助手] ${context} 写入失败:`, error);
    return false;
  }
}

async function saveComplianceTemplateToServer(auth, payload = {}) {
  const body = {
    mallId: auth?.mallId || '',
    templateName: payload.templateName || '',
    configJson: payload.configJson || '',
    isDefault: Number(payload.isDefault ?? 0),
    templateType: Number(payload.templateType ?? 0),
    username: payload.username || auth?.mallName || state.mallName || ''
  };

  const pageResult = await executeTemuPageFetch({
    url: 'https://agentseller.temu.com/professional/compliance/govern/add/package/template',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'mallid': auth?.mallId || '',
      'anti-content': auth?.antiContent || ''
    },
    body: JSON.stringify(body)
  });

  const data = pageResult.data;
  console.log('[TEMU运营助手] 合规模板保存接口响应:', JSON.stringify(data).substring(0, 500));
  if (data?.code === 0 || data?.success) {
    return { success: true, data };
  }
  const errorText = data?.message || data?.error_msg || data?.msg || pageResult.error || '保存模板失败';
  if (/Request Not Allowed|not allowed|forbidden|拒绝|不允许/i.test(String(errorText))) {
    console.warn('[TEMU运营助手] 合规模板远端保存被拒绝:', errorText);
    return { success: false, error: `TEMU 官方旧模板接口已拒绝请求：${errorText}`, data };
  }
  return { success: false, error: errorText };
}

const USER_TEMPLATE_API_BASE = 'https://xiaoqingwa.vip/api';

function normalizeServerAuthTokenValue(value) {
  if (value == null) return '';
  const token = String(value).trim().replace(/^"|"$/g, '');
  return token === 'undefined' || token === 'null' ? '' : token;
}

function normalizeServerAuthAtValue(value) {
  const timestamp = Number(value || 0);
  return Number.isFinite(timestamp) ? timestamp : 0;
}

function normalizeServerAuthUserValue(value) {
  if (!value) return null;
  if (typeof value === 'string') {
    try {
      const parsed = JSON.parse(value);
      return parsed && typeof parsed === 'object' ? parsed : null;
    } catch (_) {
      return null;
    }
  }
  return typeof value === 'object' ? value : null;
}

async function persistUserServerAuth({ token, user = null, authAt = Date.now() } = {}, context = '会员登录态') {
  const normalizedToken = normalizeServerAuthTokenValue(token);
  if (!normalizedToken) return false;
  const normalizedUser = normalizeServerAuthUserValue(user);
  const normalizedAuthAt = normalizeServerAuthAtValue(authAt) || Date.now();
  state.serverAuthToken = normalizedToken;
  state.serverAuthUser = normalizedUser;
  state.serverAuthAt = normalizedAuthAt;
  await safeStorageSet({
    temuServerToken: normalizedToken,
    temuServerUser: normalizedUser,
    temuServerAuthAt: normalizedAuthAt
  }, context);
  return true;
}

function rememberUserServerAuthFromMessage(request = {}) {
  const token = normalizeServerAuthTokenValue(request.serverAuthToken || request.temuServerToken || '');
  if (!token) return;
  state.serverAuthToken = token;
  state.serverAuthUser = normalizeServerAuthUserValue(request.serverAuthUser || request.temuServerUser || null);
  state.serverAuthAt = normalizeServerAuthAtValue(request.serverAuthAt || request.temuServerAuthAt) || Date.now();
  persistUserServerAuth({
    token,
    user: state.serverAuthUser,
    authAt: state.serverAuthAt
  }, '消息会员登录态').catch(error => {
    console.warn('[TEMU运营助手] 同步消息会员登录态失败:', error?.message || error);
  });
}

async function syncUserServerAuthFromWorkbench() {
  const tabs = await chrome.tabs.query({}).catch(() => []);
  const candidates = (tabs || [])
    .filter(tab => tab?.id && /^https:\/\/(www\.)?xiaoqingwa\.vip\/(temu|ozon|$|\?)/i.test(String(tab.url || '')))
    .sort((a, b) => (b.lastAccessed || b.id || 0) - (a.lastAccessed || a.id || 0));

  for (const tab of candidates) {
    try {
      const [execResult] = await chrome.scripting.executeScript({
        target: { tabId: tab.id },
        world: 'MAIN',
        func: () => ({
          token: localStorage.getItem('temuServerToken') || '',
          user: localStorage.getItem('temuServerUser') || '',
          authAt: localStorage.getItem('temuServerAuthAt') || ''
        })
      });
      const result = execResult?.result || {};
      const token = normalizeServerAuthTokenValue(result.token);
      if (!token) continue;
      await persistUserServerAuth({
        token,
        user: result.user || null,
        authAt: result.authAt || Date.now()
      }, '工作台会员登录态');
      return token;
    } catch (error) {
      console.warn('[TEMU运营助手] 从小青蛙工作台同步会员登录态失败:', error?.message || error);
    }
  }
  return '';
}

async function getUserServerToken(options = {}) {
  if (state.serverAuthToken) return state.serverAuthToken;
  const stored = await chrome.storage.local.get(['temuServerToken', 'temuServerUser', 'temuServerAuthAt']);
  const storedToken = normalizeServerAuthTokenValue(stored?.temuServerToken);
  if (storedToken) {
    state.serverAuthToken = storedToken;
    state.serverAuthUser = normalizeServerAuthUserValue(stored?.temuServerUser);
    state.serverAuthAt = normalizeServerAuthAtValue(stored?.temuServerAuthAt);
    return storedToken;
  }
  if (options.skipWorkbenchSync) return '';
  return await syncUserServerAuthFromWorkbench();
}

async function ensureUserTemplateShopBound(token, mallId = '', mallName = '') {
  const cleanMallId = String(mallId || '').trim();
  if (!token || !cleanMallId) return { success: true, skipped: true };
  const cleanMallName = sanitizeShopNameForTemplateBind(mallName || state.mallName || '', cleanMallId);
  try {
    const response = await fetch(`${USER_TEMPLATE_API_BASE}/user/bind-shop`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ mallId: cleanMallId, mallName: cleanMallName })
    });
    const result = await response.json().catch(() => ({}));
    if (response.ok && result.ok !== false) return { success: true, result };
    const errorText = result.error || result.message || `HTTP ${response.status}`;
    return { success: false, error: errorText };
  } catch (error) {
    return { success: false, error: error?.message || String(error) };
  }
}

function looksLikeTemplateName(value = '') {
  const text = String(value || '').trim();
  if (!text) return false;
  return /^模板[-_\s]/.test(text)
    || /合规模板/.test(text)
    || /模板[-_\s]*\d{4,}/.test(text);
}

function sanitizeShopNameForTemplateBind(value = '', mallId = '') {
  const text = String(value || '').trim();
  if (!text || looksLikeTemplateName(text)) return String(mallId || '').trim();
  return text;
}

async function fetchUserTemplatesFromServer(type = '', mallId = '') {
  const token = await getUserServerToken();
  if (!token) return { success: true, templates: [], skipped: true };
  const cleanMallId = String(mallId || '').trim();
  if (!cleanMallId) return { success: true, templates: [], skipped: true };

  const params = new URLSearchParams();
  if (type) params.set('type', type);
  params.set('mallId', cleanMallId);
  const query = params.toString() ? `?${params.toString()}` : '';
  const response = await fetch(`${USER_TEMPLATE_API_BASE}/data/templates${query}`, {
    headers: { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json().catch(() => ({}));
  if (!response.ok || !data.ok) {
    return { success: false, error: data.error || data.message || `HTTP ${response.status}` };
  }
  return { success: true, templates: Array.isArray(data.templates) ? data.templates : [] };
}

async function saveUserTemplateToServerRecord({ name, type, data, mallId = null, shopId = null, isDefault = 0 }) {
  const token = await getUserServerToken();
  if (!token) {
    return {
      success: false,
      error: '请先登录小青蛙会员账号后再保存云端模板；插件已尝试从工作台同步登录态但未找到可用登录'
    };
  }

  const mallKey = String(mallId || shopId || '').trim();
  if (!mallKey) {
    return { success: false, error: '未检测到当前店铺，无法保存模板' };
  }
  const safeMallName = sanitizeShopNameForTemplateBind(data?.mallName || state.mallName || '', mallKey);
  const bindResult = await ensureUserTemplateShopBound(token, mallKey, safeMallName);
  if (!bindResult.success) {
    return {
      success: false,
      error: `当前店铺未完成会员云端绑定：${bindResult.error || '绑定失败'}`
    };
  }

  let response;
  let result = {};
  try {
    response = await fetch(`${USER_TEMPLATE_API_BASE}/data/templates`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ name, type, data, mallId: mallKey || null, isDefault })
    });
    result = await response.json().catch(() => ({}));
  } catch (error) {
    console.warn('[TEMU运营助手] 会员模板云端同步失败:', error?.message || error);
    return {
      success: false,
      error: `会员模板云端同步失败：${error?.message || error}`
    };
  }
  if (!response.ok || !result.ok) {
    const errorText = result.error || result.message || `HTTP ${response.status}`;
    console.warn('[TEMU运营助手] 会员模板云端同步失败:', errorText);
    return {
      success: false,
      error: `会员模板云端未同步：${errorText}`
    };
  }
  let serverId = result.id || result.templateId || result.data?.id || result.template?.id || null;
  if (!serverId) {
    try {
      const queryResult = await fetchUserTemplatesFromServer(type, mallKey);
      const matches = (queryResult.templates || [])
        .filter(item => String(item.name || '') === String(name || '') && (!type || String(item.type || '') === String(type)))
        .sort((a, b) => {
          const at = Date.parse(a.updatedAt || a.createdAt || '') || 0;
          const bt = Date.parse(b.updatedAt || b.createdAt || '') || 0;
          return bt - at || Number(b.id || 0) - Number(a.id || 0);
        });
      serverId = matches[0]?.id || null;
    } catch (lookupError) {
      console.warn('[TEMU运营助手] 保存模板成功但回查服务器ID失败:', lookupError?.message || lookupError);
    }
  }
  return { success: true, id: serverId, result };
}

function getUserTemplateSyncWarning(userServerResult = {}) {
  if (userServerResult?.warning) return userServerResult.warning;
  if (userServerResult?.skipped || userServerResult?.localOnly) {
    return '模板已保存到本地，会员云端暂未同步';
  }
  return userServerResult?.id ? '' : '服务器已保存但未返回模板ID';
}

async function deleteUserTemplateFromServer(serverId, mallId = '') {
  if (!serverId) return { success: true, skipped: true };
  const token = await getUserServerToken();
  if (!token) return { success: true, skipped: true, localOnly: true };

  const cleanMallId = String(mallId || '').trim();
  if (!cleanMallId) return { success: false, error: '未检测到当前店铺，无法删除模板' };

  const params = new URLSearchParams();
  params.set('mallId', cleanMallId);
  const query = params.toString() ? `?${params.toString()}` : '';
  const response = await fetch(`${USER_TEMPLATE_API_BASE}/data/templates/${encodeURIComponent(serverId)}${query}`, {
    method: 'DELETE',
    headers: { 'Authorization': `Bearer ${token}` }
  });
  const result = await response.json().catch(() => ({}));
  if (!response.ok || !result.ok) {
    return { success: false, error: result.error || result.message || `HTTP ${response.status}` };
  }
  return { success: true };
}

function normalizeServerComplianceTemplate(row = {}) {
  const rawData = row.data || {};
  const template = rawData?.data && rawData?.name
    ? { ...rawData }
    : {
        id: `server_compliance_${row.id}`,
        name: row.name || '未命名模板',
        data: rawData,
        createdAt: row.createdAt || row.updatedAt || new Date().toISOString(),
        taskCount: Array.isArray(rawData.template_edit_request_list) ? rawData.template_edit_request_list.length : 0,
        taskTypes: Array.isArray(rawData.template_edit_request_list) ? rawData.template_edit_request_list.map(item => item.task_type).filter(Boolean) : []
      };

  const editList = Array.isArray(template?.data?.template_edit_request_list)
    ? template.data.template_edit_request_list
    : [];
  return {
    ...template,
    id: String(template.id || `server_compliance_${row.id}`),
    name: template.name || row.name || '未命名模板',
    serverId: row.id,
    source: template.source || 'user_server',
    createdAt: template.createdAt || row.createdAt || row.updatedAt || '',
    taskCount: template.taskCount || editList.length,
    taskTypes: template.taskTypes || editList.map(item => item.task_type).filter(Boolean)
  };
}

function mergeTemplateRecords(...lists) {
  const merged = new Map();
  lists.flat().forEach(item => {
    if (!item || typeof item !== 'object') return;
    const key = item.serverId ? `server:${item.serverId}` : `local:${item.id || item.name || Math.random()}`;
    merged.set(String(key), item);
  });
  return Array.from(merged.values());
}

// ========== 拦截 edit_compliance 请求，自动提示保存模板 ==========
// 当用户在合规中心提交合规信息时，自动拦截请求并提示保存为模板
// 拦截到的请求体是 TEMU 实际接受的完整数据，无需重新构建
let pendingSaveData = null; // 暂存待保存的请求体

chrome.webRequest.onBeforeRequest.addListener(
  (details) => {
    if (details.method !== 'POST' || !details.requestBody?.raw?.length) return;

    try {
      const rawBody = new Uint8Array(details.requestBody.raw[0].bytes);
      const bodyText = new TextDecoder('utf-8').decode(rawBody);
      const bodyData = JSON.parse(bodyText);

      const spuId = bodyData.spu_id;
      const taskCount = bodyData.template_edit_request_list?.length || 0;

      console.log('[TEMU运营助手] 🎯 拦截到 edit_compliance 请求, SPU:', spuId, '合规项:', taskCount);

      if (spuId && taskCount > 0) {
        // 暂存请求体，等待用户确认
        pendingSaveData = {
          body: bodyData,
          tabId: details.tabId,
          timestamp: Date.now()
        };

        // 通知 content script 显示保存提示
        chrome.tabs.sendMessage(details.tabId, {
          action: 'showSaveToast',
          spuId: String(spuId),
          taskCount: taskCount
        }).catch(err => {
          console.log('[TEMU运营助手] 无法通知 content script:', err.message);
        });
      }
    } catch (error) {
      console.error('[TEMU运营助手] 解析 edit_compliance 请求体失败:', error);
    }
  },
  {
    urls: ['https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/edit_compliance']
  },
  ['requestBody']
);

// ========== 初始化 ==========
console.log('[TEMU运营助手] 后台脚本已加载');

// ========== 启动时不再自动创建默认模板，由用户手动保存 ==========

// ========== 辅助函数：获取当前页面的 mallId ==========
async function getCurrentMallId() {
  try {
    const tabs = await chrome.tabs.query({});
    const temuTabs = tabs.filter(tab => typeof tab.url === 'string' && isTemuSellerUrl(tab.url));

    const sortedTabs = [...temuTabs].sort((a, b) => {
      const aTime = a.lastAccessed || a.id || 0;
      const bTime = b.lastAccessed || b.id || 0;
      return bTime - aTime;
    });

    for (const tab of sortedTabs) {
      if (!tab?.id) continue;
      try {
        const result = await readAuthFromTemuTab(tab.id);
        if (result && result.mallId) {
          return result;
        }
      } catch (tabError) {
        console.warn('[TEMU运营助手] 尝试读取 mallId 失败:', tab?.url, tabError?.message || tabError);
      }
    }
    return { mallId: null };
  } catch (error) {
    console.error('[TEMU运营助手] 获取当前 mallId 失败:', error);
    return { mallId: null };
  }
}

async function readAuthFromTemuTab(tabId) {
  if (!tabId) return null;
  const [result] = await chrome.scripting.executeScript({
    target: { tabId },
    func: () => {
      const normalizeMallName = value => {
        const text = String(value || '').trim();
        if (!text || text === '当前店铺' || text === '当前店铺 ') return null;
        return text;
      };

      const readJson = key => {
        try {
          return JSON.parse(localStorage.getItem(key) || sessionStorage.getItem(key) || 'null');
        } catch (_) {
          return null;
        }
      };

      const queryMallId = () => {
        try {
          const url = new URL(location.href);
          const raw = url.searchParams.get('mall_id') || url.searchParams.get('mallId') || url.searchParams.get('mallid');
          const match = String(raw || '').match(/\d{6,}/);
          return match ? match[0] : raw;
        } catch (_) {
          return null;
        }
      };

      const readMallNameFromDom = () => {
        const selectors = [
          'div[class^="account-info_mallInfo_"]',
          'div[class*="account-info_mallInfo_"]',
          '[class*="mallInfo"]',
          '[class*="mall-info"]'
        ];
        for (const selector of selectors) {
          const el = document.querySelector(selector);
          if (!el) continue;
          const text = String(el.innerText || el.textContent || '').trim();
          if (!text) continue;
          const firstLine = text.split(/\n+/).map(item => item.trim()).filter(Boolean)[0];
          if (firstLine) return firstLine;
        }
        return null;
      };

      const globalMallId = (() => {
        const candidates = [
          window.__INITIAL_STATE__,
          window.__NUXT__?.state,
          window.__STORE__?.state,
          window.__NEXT_DATA__?.props?.pageProps,
          window.__DATA__,
          window.__INITIAL_DATA__
        ];
        for (const obj of candidates) {
          if (!obj || typeof obj !== 'object') continue;
          const values = [
            obj.mallId,
            obj.mall_id,
            obj.mallID,
            obj.shopId,
            obj.shop_id,
            obj.merchantId,
            obj.merchant_id
          ];
          for (const value of values) {
            if (value) return value;
          }
        }
        return null;
      })();

      const mallInfo = readJson('agentseller-mall-info') || readJson('seller-mall-info') || {};
      const urlMallId = queryMallId();
      const storageMallId = localStorage.getItem('agentseller-mall-info-id')
        || localStorage.getItem('seller-mall-info-id')
        || sessionStorage.getItem('agentseller-mall-info-id')
        || sessionStorage.getItem('seller-mall-info-id')
        || null;
      const mallInfoMallId = mallInfo.mallId || mallInfo.mall_id || null;
      const mallIdCandidates = [
        { value: urlMallId, source: 'url' },
        { value: globalMallId, source: 'global' },
        { value: mallInfoMallId, source: 'mallInfo' },
        { value: storageMallId, source: 'storage' }
      ];
      const selectedMallId = mallIdCandidates.find(item => item.value);
      const mallId = selectedMallId?.value || null;
      const mallIdSource = selectedMallId?.source || '';

      const mallName = normalizeMallName(readMallNameFromDom())
        || normalizeMallName(localStorage.getItem('agentseller-mall-info-name'))
        || normalizeMallName(localStorage.getItem('seller-mall-info-name'))
        || normalizeMallName(sessionStorage.getItem('agentseller-mall-info-name'))
        || normalizeMallName(sessionStorage.getItem('seller-mall-info-name'))
        || normalizeMallName(mallInfo.mallName)
        || normalizeMallName(mallInfo.mall_name)
        || normalizeMallName(mallInfo.name)
        || null;

      const normalizedMallId = (() => {
        const text = String(mallId || '').trim();
        const match = text.match(/\d{6,}/);
        return match ? match[0] : (text.split(',')[0]?.trim() || null);
      })();
      const normalizedAntiContent = (() => {
        const runtimeAntiContent = (() => {
          try {
            return typeof window.secretKeyAnti === 'function' ? window.secretKeyAnti() : '';
          } catch (_) {
            return '';
          }
        })();
        const text = String(runtimeAntiContent || localStorage.getItem('anti-content') || localStorage.getItem('Anti-Content') || sessionStorage.getItem('anti-content') || sessionStorage.getItem('Anti-Content') || '').trim();
        return text.split(',').map(item => item.trim()).filter(Boolean)[0] || null;
      })();

      return {
        mallId: normalizedMallId,
        mallName,
        mallIdSource,
        urlMallId,
        storageMallId,
        lsMallId: localStorage.getItem('agentseller-mall-info-id') || localStorage.getItem('seller-mall-info-id') || null,
        antiContent: normalizedAntiContent
      };
    }
  });
  const auth = result?.result || null;
  return auth ? normalizeAuthRecord(auth) : null;
}

async function saveAuth(mallId, antiContent, mallName = null) {
  const updatedAt = Date.now();
  const stored = await chrome.storage.local.get('temuAuth');
  const resolvedMallName = mallName || state.mallName || stored.temuAuth?.mallName || null;
  const normalized = normalizeAuthRecord({ mallId, antiContent });
  state.mallId = normalized.mallId;
  state.mallName = resolvedMallName;
  state.antiContent = normalized.antiContent;
  state.authUpdatedAt = updatedAt;
  await safeStorageSet({
    temuAuth: {
      mallId: state.mallId,
      antiContent: state.antiContent,
      mallName: resolvedMallName,
      updatedAt
    }
  }, '认证信息');

  await safeStorageSet({
    temuLocalMallId: state.mallId
  }, '店铺ID');
}

async function getAuth() {
  if (state.mallId && state.antiContent) {
    const normalized = normalizeAuthRecord(state);
    const dirty = state.mallId !== normalized.mallId || state.antiContent !== normalized.antiContent;
    state.mallId = normalized.mallId;
    state.antiContent = normalized.antiContent;
    if (dirty) {
      await persistNormalizedAuth({
        mallId: state.mallId,
        antiContent: state.antiContent,
        mallName: state.mallName || null
      }, '内存认证信息清理');
    }
    return {
      mallId: state.mallId,
      antiContent: state.antiContent,
      mallName: state.mallName || null
    };
  }

  const result = await chrome.storage.local.get('temuAuth');
  if (result.temuAuth?.mallId && result.temuAuth?.antiContent) {
    const normalized = normalizeAuthRecord(result.temuAuth);
    state.mallId = normalized.mallId;
    state.antiContent = normalized.antiContent;
    state.mallName = result.temuAuth.mallName || state.mallName || null;
    state.authUpdatedAt = Number(result.temuAuth.updatedAt || Date.now());
    if (result.temuAuth.mallId !== state.mallId || result.temuAuth.antiContent !== state.antiContent) {
      await persistNormalizedAuth({
        ...result.temuAuth,
        mallId: state.mallId,
        antiContent: state.antiContent,
        mallName: state.mallName || null
      }, '认证信息清理');
    }
    return {
      mallId: state.mallId,
      antiContent: state.antiContent,
      mallName: state.mallName || null
    };
  }

  if (typeof DEFAULT_MALL_ID !== 'undefined' && DEFAULT_MALL_ID) {
    state.mallId = normalizeMallIdValue(DEFAULT_MALL_ID);
    state.antiContent = typeof DEFAULT_ANTI_CONTENT !== 'undefined' ? normalizeAntiContentValue(DEFAULT_ANTI_CONTENT) : '';
    return {
      mallId: DEFAULT_MALL_ID,
      antiContent: state.antiContent,
      mallName: state.mallName || null
    };
  }

  return null;
}

function pickReminderField(source, keys = []) {
  if (!source || typeof source !== 'object') return null;
  for (const key of keys) {
    const value = source[key];
    if (value !== undefined && value !== null && value !== '') return value;
  }
  return null;
}

function pickReminderNestedField(source, keys = [], maxDepth = 4) {
  const seen = new Set();
  const queue = [{ value: source, depth: 0 }];
  while (queue.length) {
    const { value, depth } = queue.shift();
    if (!value || typeof value !== 'object' || seen.has(value)) continue;
    seen.add(value);
    const direct = pickReminderField(value, keys);
    if (direct !== undefined && direct !== null && direct !== '') return direct;
    if (depth >= maxDepth) continue;
    for (const child of Object.values(value)) {
      if (!child || typeof child !== 'object') continue;
      if (Array.isArray(child)) {
        child.slice(0, 30).forEach(item => queue.push({ value: item, depth: depth + 1 }));
      } else {
        queue.push({ value: child, depth: depth + 1 });
      }
    }
  }
  return null;
}

function parseReminderTimestamp(value) {
  if (value === null || value === undefined || value === '') return null;
  if (value instanceof Date) {
    const time = value.getTime();
    return Number.isNaN(time) ? null : time;
  }
  if (typeof value === 'number' && Number.isFinite(value)) {
    return value > 1e12 ? value : value * 1000;
  }
  const text = String(value).trim();
  if (!text) return null;
  const numeric = Number(text);
  if (Number.isFinite(numeric)) {
    return numeric > 1e12 ? numeric : numeric * 1000;
  }
  let parsed = new Date(text);
  let time = parsed.getTime();
  if (Number.isNaN(time)) {
    parsed = new Date(text.replace(/-/g, '/'));
    time = parsed.getTime();
  }
  return Number.isNaN(time) ? null : time;
}

function buildReminderOrderEntry(row, type, deadline, thresholdHours) {
  const remainingMs = deadline - Date.now();
  const orderSn = pickReminderField(row, ['subPurchaseOrderSn', 'subOrderSn', 'purchaseOrderSn', 'orderSn']) || '—';
  const skcId = pickReminderField(row, ['productSkcId', 'skcId', 'skc', 'skuId']) || '—';
  const statusText = readStockReminderStatusText(row);
  return {
    id: `${type}:${orderSn}:${skcId}:${deadline}`,
    type,
    productName: pickReminderField(row, ['productName', 'goodsName', 'productTitle', 'productSkcName', 'title']) || '备货单',
    skcId,
    orderSn,
    statusText,
    image: pickReminderField(row, ['productSkcPicture', 'img', 'imageUrl', 'mainImage']) || '',
    deadline,
    deadlineText: new Date(deadline).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }),
    remainingMs,
    thresholdHours
  };
}

function readStockReminderStatusText(row = {}) {
  const value = pickReminderField(row, [
    'orderStatusName',
    'statusName',
    'subOrderStatusName',
    'purchaseStatusName',
    'productStatusName',
    'orderStatus',
    'subOrderStatus',
    'purchaseStatus',
    'status',
    'state'
  ]);
  return normalizeCustomizedStockStatus(value);
}

function isStockReminderFinishedStatus(statusText = '') {
  return /已收货|已验收|已入库|已作废|已取消|取消|作废|关闭|完结|完成/.test(String(statusText || ''));
}

function isStockReminderShippingStatus(row = {}) {
  const statusText = readStockReminderStatusText(row);
  return /待发货|待送货|待揽收|待履约/.test(statusText);
}

function isStockReminderArrivalStatus(row = {}) {
  const statusText = readStockReminderStatusText(row);
  if (isStockReminderFinishedStatus(statusText)) return false;
  if (!statusText) return false;
  return /待收货|待到货|运输中|配送中|已发货|已送货|送货中/.test(statusText);
}

async function fetchStockReminderPages(auth, pageNo = 1, pageSize = 100, orderByParam = 'expectLatestDeliverTime') {
  return await temuSellerPost(
    'https://agentseller.temu.com/mms/venom/api/supplier/purchase/manager/querySubOrderList',
    {
    pageNo,
    pageSize,
    urgencyType: 0,
    isCustomGoods: false,
    oneDimensionSort: {
      firstOrderByParam: orderByParam,
      firstOrderByDesc: 0
    }
    },
    auth,
    25000
  );
}

async function loadStockReminderData(auth) {
  const shipping = [];
  const arrival = [];
  const shippingIds = new Set();
  const arrivalIds = new Set();
  const pageSize = 100;
  const maxPages = 5;
  let seen = 0;
  const sortFields = ['expectLatestDeliverTime', 'expectLatestArriveTime', 'expectLatestReceiveTime'];
  const seenRows = new Set();

  for (const sortField of sortFields) {
    for (let pageNo = 1; pageNo <= maxPages; pageNo++) {
      const resp = await fetchStockReminderPages(auth, pageNo, pageSize, sortField);
      const result = resp?.result || {};
      const list = result.subOrderForSupplierList || result.list || result.rows || result.data?.list || result.data || result.dataList || [];
      if (!Array.isArray(list) || list.length === 0) break;
      seen += list.length;

      for (const row of list) {
        const rowKey = String(pickReminderField(row, ['subPurchaseOrderSn', 'subOrderSn', 'purchaseOrderSn', 'orderSn']) || JSON.stringify(row).slice(0, 200));
        seenRows.add(rowKey);
        const shippingDeadline = parseReminderTimestamp(pickReminderField(row, [
          'expectLatestDeliverTime',
          'expectLatestDeliveryTime',
          'latestDeliverTime',
          'deliverDeadline',
          'deliveryDeadline'
        ]));
        if (shippingDeadline) {
          const remaining = shippingDeadline - Date.now();
          if (remaining > 0 && remaining <= 24 * 3600000 && isStockReminderShippingStatus(row)) {
            const entry = buildReminderOrderEntry(row, 'shipping', shippingDeadline, 24);
            if (!shippingIds.has(entry.id)) {
              shippingIds.add(entry.id);
              shipping.push(entry);
            }
          }
        }

        const arrivalDeadline = parseReminderTimestamp(pickReminderField(row, [
          'expectLatestArriveTime',
          'expectLatestReceiveTime',
          'latestArriveTime',
          'arriveDeadline',
          'receiveDeadline'
        ]));
        if (arrivalDeadline) {
          const remaining = arrivalDeadline - Date.now();
          if (remaining > 0 && remaining <= 48 * 3600000 && isStockReminderArrivalStatus(row)) {
            const entry = buildReminderOrderEntry(row, 'arrival', arrivalDeadline, 48);
            if (!arrivalIds.has(entry.id)) {
              arrivalIds.add(entry.id);
              arrival.push(entry);
            }
          }
        }
      }

      if (list.length < pageSize) break;
    }
  }

  const sorter = (a, b) => a.remainingMs - b.remainingMs || String(a.productName).localeCompare(String(b.productName), 'zh-Hans-CN');
  shipping.sort(sorter);
  arrival.sort(sorter);
  return {
    success: true,
    shipping,
    arrival,
    updatedAt: Date.now(),
    total: seenRows.size || seen,
    message: shipping.length || arrival.length ? '' : '暂无即将超时的备货单'
  };
}



function normalizeCustomizedStockStatus(value) {
  if (value === null || value === undefined || value === '') return '';
  const text = String(value).trim();
  if (!text) return '';
  if (!/^-?\d+$/.test(text)) return text;
  const statusLabelMap = {
    0: '待创建',
    1: '待发货',
    2: '已送货',
    3: '已收货',
    4: '抽检全部退回',
    5: '已验收',
    6: '已验收',
    7: '已入库',
    8: '已作废',
    9: '已超时',
    10: '已取消'
  };
  return statusLabelMap[Number(text)] || text;
}



const customizedPreviewImageDataUrlCache = new Map();

function normalizeTemuImageFetchUrl(value = '') {
  const text = String(value || '').trim();
  if (!text) return '';
  if (text.startsWith('data:image/')) return text;
  if (text.startsWith('//')) return `https:${text}`;
  if (text.startsWith('http://')) return `https://${text.slice(7)}`;
  return text;
}

function arrayBufferToBase64(buffer) {
  const bytes = new Uint8Array(buffer);
  const chunkSize = 0x8000;
  let binary = '';
  for (let offset = 0; offset < bytes.length; offset += chunkSize) {
    binary += String.fromCharCode.apply(null, bytes.subarray(offset, offset + chunkSize));
  }
  return btoa(binary);
}

async function createPreviewImageDataUrl(buffer, mimeType = 'image/jpeg') {
  const safeMimeType = /^image\//i.test(mimeType || '') ? mimeType : 'image/jpeg';
  // Keep the original image bytes. Excel display size is controlled in drawing XML;
  // downscaling here makes custom preview details unreadable.
  return `data:${safeMimeType};base64,${arrayBufferToBase64(buffer)}`;
}

async function fetchPreviewImageAsDataUrl(url, timeoutMs = 30000) {
  const normalizedUrl = normalizeTemuImageFetchUrl(url);
  if (!normalizedUrl) return '';
  if (/^data:image\//i.test(normalizedUrl)) return normalizedUrl;
  if (!/^https?:\/\//i.test(normalizedUrl)) return '';
  if (customizedPreviewImageDataUrlCache.has(normalizedUrl)) {
    return customizedPreviewImageDataUrlCache.get(normalizedUrl);
  }

  const attempts = [
    { credentials: 'include', cache: 'default' },
    { credentials: 'omit', cache: 'reload' },
    { credentials: 'include', cache: 'no-store' }
  ];
  let lastError = null;

  for (const attempt of attempts) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(new Error('timeout')), Number(timeoutMs || 30000));
    try {
      const response = await fetch(normalizedUrl, {
        method: 'GET',
        credentials: attempt.credentials,
        cache: attempt.cache,
        mode: 'cors',
        referrerPolicy: 'no-referrer-when-downgrade',
        headers: {
          Accept: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'
        },
        signal: controller.signal
      });
      if (!response.ok) throw new Error(`图片请求失败 ${response.status}`);
      const contentType = response.headers.get('content-type') || 'image/jpeg';
      if (!/^image\//i.test(contentType)) throw new Error(`图片响应类型异常 ${contentType}`);
      const buffer = await response.arrayBuffer();
      if (!buffer || !buffer.byteLength) throw new Error('图片响应为空');
      const dataUrl = await createPreviewImageDataUrl(buffer, contentType);
      customizedPreviewImageDataUrlCache.set(normalizedUrl, dataUrl);
      return dataUrl;
    } catch (error) {
      lastError = error;
    } finally {
      clearTimeout(timer);
    }
  }

  console.warn('[TEMU运营助手] 图片转数据失败:', normalizedUrl, lastError);
  return '';
}



async function embedTemuImageUrls(rows = [], imageKeys = []) {
  const keys = Array.from(new Set((Array.isArray(imageKeys) ? imageKeys : [])
    .map(key => String(key || '').trim())
    .filter(Boolean)));
  if (!keys.length) {
    return { success: true, rows, embeddedCount: 0, failedCount: 0 };
  }
  const uniqueUrls = Array.from(new Set(rows.flatMap(row => keys
    .map(key => normalizeTemuImageFetchUrl(row?.[key] || ''))
    .filter(url => /^https?:\/\//i.test(url)))));
  if (!uniqueUrls.length) {
    return { success: true, rows, embeddedCount: 0, failedCount: 0 };
  }

  const dataUrlMap = new Map();
  let cursor = 0;
  const workerCount = Math.min(4, uniqueUrls.length);
  const workers = Array.from({ length: workerCount }, async () => {
    while (cursor < uniqueUrls.length) {
      const url = uniqueUrls[cursor++];
      dataUrlMap.set(url, await fetchPreviewImageAsDataUrl(url));
    }
  });
  await Promise.all(workers);

  let embeddedCount = 0;
  let failedCount = 0;
  const enrichedRows = rows.map(row => {
    const nextRow = { ...row };
    for (const key of keys) {
      const normalizedUrl = normalizeTemuImageFetchUrl(row?.[key] || '');
      const dataUrl = dataUrlMap.get(normalizedUrl);
      if (/^data:image\//i.test(dataUrl || '')) {
        nextRow[key] = dataUrl;
        nextRow[`${key}Url`] = normalizedUrl;
        nextRow[`${key}Status`] = '已嵌入';
        embeddedCount += 1;
      } else if (normalizedUrl) {
        nextRow[`${key}Url`] = normalizedUrl;
        nextRow[`${key}Status`] = '图片抓取失败，已保留URL';
        failedCount += 1;
      }
    }
    return nextRow;
  });

  return { success: true, rows: enrichedRows, embeddedCount, failedCount };
}

async function embedCustomizedProductExportImages(rows = []) {
  return embedTemuImageUrls(rows, ['skcImage', 'skuImage']);
}

async function queryTemuCustomizedContentPage(params = {}) {
  const page = Math.max(1, Number(params.page || 1) || 1);
  const pageSize = Math.max(1, Number(params.pageSize || 500) || 500);
  const body = params.body && typeof params.body === 'object'
    ? { ...params.body, page, pageSize }
    : { page, pageSize };
  const result = await executeTemuPageFetch({
    url: 'https://agentseller.temu.com/bg-luna-agent-seller/product/customizeSku/pageQuery',
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
    timeoutMs: Math.max(20000, Number(params.timeoutMs || 45000) || 45000)
  });
  const data = result.data;
  if (data?.success !== true || Number(data?.errorCode) !== 1000000) {
    throw new Error(getTemuApiMessage(data, '定制商品内容列表查询失败'));
  }
  return {
    success: true,
    data,
    page,
    pageSize,
    total: Number(data?.result?.total || 0) || 0,
    pageItems: Array.isArray(data?.result?.pageItems) ? data.result.pageItems : []
  };
}

async function clearTemuSessionData() {
  try {
    await chrome.browsingData.remove(
      {
        origins: [
          'https://www.temu.com',
          'https://commerce.temu.com',
          'https://agentseller.temu.com',
          'https://seller.kuajingmaihuo.com'
        ]
      },
      {
        cookies: true,
        cache: true,
        localStorage: true,
        indexedDB: true,
        serviceWorkers: true,
        webSQL: true,
        fileSystems: true
      }
    );
  } catch (error) {
    console.warn('[TEMU运营助手] browsingData 清理失败，改用 cookie 清理:', error?.message || error);
  }

  const domains = ['temu.com', '.temu.com', 'kuajingmaihuo.com', '.kuajingmaihuo.com'];
  const cookies = [];
  for (const domain of domains) {
    try {
      const found = await chrome.cookies.getAll({ domain });
      cookies.push(...found);
    } catch (error) {
      console.warn('[TEMU运营助手] 获取 cookie 失败:', domain, error?.message || error);
    }
  }

  const uniq = new Map();
  for (const cookie of cookies) {
    const key = `${cookie.domain}|${cookie.path}|${cookie.name}|${cookie.storeId}`;
    if (!uniq.has(key)) uniq.set(key, cookie);
  }

  let removed = 0;
  for (const cookie of uniq.values()) {
    const scheme = cookie.secure ? 'https://' : 'http://';
    const host = cookie.domain.startsWith('.') ? cookie.domain.slice(1) : cookie.domain;
    const url = `${scheme}${host}${cookie.path || '/'}`;
    try {
      const result = await chrome.cookies.remove({
        url,
        name: cookie.name,
        storeId: cookie.storeId
      });
      if (result) removed += 1;
    } catch (error) {
      console.warn('[TEMU运营助手] 删除 cookie 失败:', cookie.name, error?.message || error);
    }
  }

  return { success: true, removed };
}

async function autoDetectAuth(options = {}) {
  const forceRefresh = options?.forceRefresh === true;
  const cached = await chrome.storage.local.get('temuAuth');
  const cachedNormalized = normalizeAuthRecord(cached.temuAuth || {});
  const cachedAuth = cachedNormalized.mallId && cachedNormalized.antiContent ? {
    success: true,
    fromCache: true,
    mallId: cachedNormalized.mallId,
    mallName: cached.temuAuth.mallName || null,
    antiContent: cachedNormalized.antiContent
  } : null;
  if (!forceRefresh && cachedNormalized.mallId && cachedNormalized.antiContent) {
    state.mallId = cachedNormalized.mallId;
    state.antiContent = cachedNormalized.antiContent;
    state.mallName = cached.temuAuth.mallName || null;
    state.authUpdatedAt = Number(cached.temuAuth.updatedAt || Date.now());
    if (cached.temuAuth.mallId !== state.mallId || cached.temuAuth.antiContent !== state.antiContent) {
      await safeStorageSet({
        temuAuth: { ...cached.temuAuth, mallId: state.mallId, antiContent: state.antiContent, updatedAt: Date.now() },
        temuLocalMallId: state.mallId
      }, '认证信息清理');
    }
    if (state.mallName) return { ...cachedAuth, mallName: state.mallName };
  }

  const tabs = await chrome.tabs.query({});
  const temuTabs = tabs.filter(tab => typeof tab.url === 'string' && (
    isTemuSellerUrl(tab.url) ||
    tab.url.includes('seller.kuajingmaihuo.com') ||
    tab.url.includes('temu.com/mall') ||
    tab.url.includes('temu.com')
  ));
  temuTabs.sort((a, b) => (b.lastAccessed || b.id || 0) - (a.lastAccessed || a.id || 0));

  let pageAuth = { mallId: null, mallName: null, antiContent: null };
  for (const temuTab of temuTabs) {
    if (!temuTab?.id) continue;
    try {
      const result = await readAuthFromTemuTab(temuTab.id);
      pageAuth = result || pageAuth;
      if (pageAuth.mallId && pageAuth.antiContent) break;
    } catch (tabError) {
      console.warn('[TEMU运营助手] 自动检测尝试失败:', temuTab?.url, tabError?.message || tabError);
    }
  }

  let antiContent = pageAuth.antiContent || null;
  if (!antiContent) {
    const domains = ['.temu.com', 'temu.com', '.kuajingmaihuo.com', 'kuajingmaihuo.com'];
    for (const domain of domains) {
      const cookies = await chrome.cookies.getAll({ domain });
      const beeCookie = cookies.find(cookie => cookie.name === '_bee');
      if (beeCookie?.value) {
        antiContent = beeCookie.value;
        break;
      }
    }
  }

  if (antiContent) {
    let mallId = normalizeMallIdValue(pageAuth.mallId);
    let mallName = pageAuth.mallName || null;
    antiContent = normalizeAntiContentValue(antiContent);
    let mallList = [];

    try {
      const userInfoData = await temuSellerPost(
        'https://agentseller.temu.com/api/seller/auth/userInfo',
        {},
        { mallId, antiContent },
        12000
      );
      mallList = Array.isArray(userInfoData?.result?.mallList) ? userInfoData.result.mallList : [];
      if (mallList.length > 0) {
        const normalizedPageMallId = normalizeMallIdValue(mallId || pageAuth.lsMallId || '');
        const matchedById = normalizedPageMallId
          ? mallList.find(mall => String(mall.mallId || mall.mall_id || '').trim() === String(normalizedPageMallId))
          : null;
        const matchedByName = !matchedById && mallName
          ? mallList.find(mall => String(mall.mallName || mall.mall_name || mall.name || '').trim().toLowerCase() === String(mallName).trim().toLowerCase())
          : null;
        const forceCurrentPageName = forceRefresh && mallName && (!normalizedPageMallId || pageAuth.mallIdSource === 'storage');
        const selectedMall = forceCurrentPageName
          ? (matchedByName || matchedById || mallList[0])
          : (matchedById || matchedByName || mallList[0]);
        if (selectedMall) {
          mallId = normalizeMallIdValue(selectedMall.mallId || selectedMall.mall_id || selectedMall.id || mallId);
          mallName = selectedMall.mallName || selectedMall.mall_name || selectedMall.name || mallName;
        }
      }
    } catch (apiError) {
      console.warn('[TEMU运营助手] userInfo API 调用失败，回退页面识别结果:', apiError?.message || apiError);
    }

    if (!mallId) {
      return {
        ...(!forceRefresh && cachedAuth
          ? cachedAuth
          : {
              success: false,
              mallId: null,
              error: '已获取 TEMU 登录态，但未识别到店铺 mallId',
              diagnostics: {
                hasTemuTab: temuTabs.length > 0,
                hasMallId: false,
                hasAntiContent: Boolean(antiContent),
                mallListCount: mallList.length
              }
            })
      };
    }

    state.mallId = mallId;
    state.mallName = mallName || null;
    state.antiContent = antiContent;
    await saveAuth(state.mallId, state.antiContent, state.mallName);
    return {
      success: true,
      fromCache: false,
      mallId: state.mallId,
      mallName: state.mallName || pageAuth.mallName || null,
      antiContent: state.antiContent
    };
  }

  return {
    ...(!forceRefresh && cachedAuth && (!pageAuth.mallId || !antiContent)
      ? cachedAuth
      : {
          success: false,
          mallId: pageAuth.mallId || null,
          error: pageAuth.mallId ? '未获取到 anti-content' : '未找到可用的 TEMU 店铺 mallId',
          diagnostics: {
            hasTemuTab: temuTabs.length > 0,
            hasMallId: Boolean(pageAuth.mallId),
            hasAntiContent: Boolean(antiContent)
          }
        })
  };
}

// ========== 点击图标打开后台页面 ==========
chrome.action.onClicked.addListener(() => {
  const targetUrl = 'https://xiaoqingwa.vip/?platform=temu';
  chrome.tabs.query({}, (tabs) => {
    const existing = (tabs || []).find((tab) => {
      const url = String(tab.url || '');
      return url === targetUrl || url.startsWith(`${targetUrl}?`) || url.startsWith(`${targetUrl}#`);
    });
    if (existing?.id) {
      chrome.tabs.update(existing.id, { active: true });
      return;
    }
    chrome.tabs.create({ url: targetUrl });
  });
});

// ========== 消息处理 ==========
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  const action = request.action || request.type;
  console.log('[TEMU运营助手] 收到消息:', action);
  rememberUserServerAuthFromMessage(request);
  
  switch (action) {
    case 'setServerAuth':
      persistUserServerAuth({
        token: request.token || request.serverAuthToken || request.temuServerToken || '',
        user: request.user || request.serverAuthUser || request.temuServerUser || null,
        authAt: request.authAt || request.serverAuthAt || request.temuServerAuthAt || Date.now()
      }, '主动会员登录态')
        .then(success => sendResponse({ success, error: success ? '' : '会员登录 token 为空' }))
        .catch(err => sendResponse({ success: false, error: err?.message || String(err) }));
      return true;

    case 'getServerAuth':
      getUserServerToken()
        .then(token => sendResponse({
          success: Boolean(token),
          token,
          user: state.serverAuthUser || null,
          authAt: state.serverAuthAt || 0,
          error: token ? '' : '未找到会员登录态'
        }))
        .catch(err => sendResponse({ success: false, error: err?.message || String(err) }));
      return true;

    case 'getCurrentMallId':
      // 从当前活动标签页获取 mallId
      getCurrentMallId().then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] getCurrentMallId 出错:', err);
        sendResponse({ error: err.message });
      });
      return true; // 保持消息通道开启
      
    case 'setAuth':
      state.mallId = normalizeMallIdValue(request.mallId);
      state.antiContent = normalizeAntiContentValue(request.antiContent);
      state.mallName = request.mallName || state.mallName || null;
      saveAuth(state.mallId, state.antiContent, request.mallName || state.mallName || null)
        .then(() => sendResponse({ success: true, mallId: state.mallId, antiContent: state.antiContent, mallName: state.mallName || null }))
        .catch(err => sendResponse({ success: false, error: err?.message || String(err) }));
      return true;

    case 'clearAuth':
      clearAuthCache().then(() => {
        sendResponse({ success: true });
      }).catch(err => {
        console.error('[TEMU运营助手] clearAuth 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'saveAntiContent':
      // 从 content script 保存 anti-content
      state.antiContent = normalizeAntiContentValue(request.antiContent);
      console.log('[TEMU运营助手] 从 content script 保存 anti-content:', request.antiContent ? '有值' : '无值');
      // 同时保存到 storage
      if (state.mallId) {
        saveAuth(state.mallId, state.antiContent, state.mallName || null)
          .then(() => sendResponse({ success: true, antiContent: state.antiContent }))
          .catch(err => sendResponse({ success: false, error: err?.message || String(err) }));
      } else {
        // 只保存 anti-content
        chrome.storage.local.get('temuAuth', (result) => {
          const auth = result.temuAuth || {};
          persistNormalizedAuth({
            ...auth,
            antiContent: state.antiContent,
            mallName: auth.mallName || state.mallName || null
          }, 'anti-content').then(() => {
            sendResponse({ success: true, antiContent: state.antiContent });
          }).catch(err => {
            sendResponse({ success: false, error: err?.message || String(err) });
          });
        });
      }
      return true;
      
    case 'getAuth':
      getAuth().then(auth => {
        sendResponse(auth);
      }).catch(err => {
        console.error('[TEMU运营助手] getAuth 出错:', err);
        sendResponse({ error: err.message });
      });
      return true; // 异步响应

    case 'getStockReminderData':
      (async () => {
        try {
          const auth = await getAuth();
          const mallId = request.data?.mallId || auth?.mallId;
          if (!mallId) {
            sendResponse({ success: false, error: '请先连接店铺后再加载备货单提醒' });
            return;
          }
          const result = await loadStockReminderData({ ...(auth || {}), mallId });
          sendResponse(result);
        } catch (error) {
          console.error('[TEMU运营助手] getStockReminderData 出错:', error);
          sendResponse({ success: false, error: error?.message || String(error) });
        }
      })();
      return true;

    case 'embedCustomizedProductExportImages':
      embedCustomizedProductExportImages(request.rows || [])
        .then(result => sendResponse(result))
        .catch(error => {
          console.error('[TEMU运营助手] embedCustomizedProductExportImages 出错:', error);
          sendResponse({ success: false, error: error?.message || String(error), rows: request.rows || [] });
        });
      return true;

    case 'embedTemuImageUrls':
      embedTemuImageUrls(request.rows || [], request.imageKeys || [])
        .then(result => sendResponse(result))
        .catch(error => {
          console.error('[TEMU运营助手] embedTemuImageUrls 出错:', error);
          sendResponse({ success: false, error: error?.message || String(error), rows: request.rows || [] });
        });
      return true;

    case 'queryTemuCustomizedContentPage':
      queryTemuCustomizedContentPage(request.params || {})
        .then(result => sendResponse(result))
        .catch(error => {
          console.error('[TEMU运营助手] queryTemuCustomizedContentPage 出错:', error);
          sendResponse({ success: false, error: error?.message || String(error) });
        });
      return true;

    case 'getDashboardHomeSales':
      (async () => {
        try {
          const auth = await getAuth();
          const result = await getDashboardHomeSales(auth);
          sendResponse(result);
        } catch (error) {
          console.error('[TEMU运营助手] getDashboardHomeSales 出错:', error);
          sendResponse({ success: false, error: error?.message || String(error) });
        }
      })();
      return true;

    case 'clearTemuSession':
      clearTemuSessionData().then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] clearTemuSession 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'fetchProductList':
      fetchProductList(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchProductList 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'FETCH_MOVE_SOURCE_PRODUCTS':
      fetchCustomizedProductList({
        pageNo: request.params?.pageNo || request.params?.pageNum || 1,
        pageSize: request.params?.pageSize || 100
      }).then(result => {
        if (result?.success) {
          sendResponse({
            ...result,
            products: Array.isArray(result.products) ? result.products : []
          });
        } else {
          sendResponse(result || { success: false, error: '加载源店商品失败' });
        }
      }).catch(err => {
        console.error('[TEMU运营助手] FETCH_MOVE_SOURCE_PRODUCTS 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'COLLECT_PRODUCT':
      collectProductFromBuyerUrl(request.url).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] COLLECT_PRODUCT 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'fetchComplianceList':
      fetchComplianceList(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchComplianceList 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'fetchProductDetail':
      // 获取商品详情（用于保存为模板）
      fetchComplianceList({ spuId: request.spuId }).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchProductDetail 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'addTask':
      addTask(request.task).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] addTask 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'getTaskStatus':
      getTaskStatus().then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] getTaskStatus 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'autoDetectAuth':
      autoDetectAuth({ forceRefresh: request.forceRefresh === true }).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] autoDetectAuth 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'saveComplianceAsTemplate':
      // 从 query_detail 缓存数据保存为模板
      (async () => {
        try {
          const templateName = request.data?.name || `模板-${new Date().toLocaleString()}`;
          const queryResult = request.data?.queryDetailResult || request.data?.complianceData;
          const auth = await getAuth();

          if (!queryResult) {
            sendResponse({ success: false, error: '未收到合规数据' });
            return;
          }

          let templateData;
          let taskCount = 0;
          let taskTypes = [];

          // 如果是 query_detail 的 result，提取模板数据
          if (queryResult.wait_task_dtolist) {
            const waitTaskList = queryResult.wait_task_dtolist;
            const catId = queryResult.cat_id;
            const templateEditRequestList = [];

            for (const task of waitTaskList) {
              const item = { task_type: task.task_type };
              if (task.task_id) item.task_id = task.task_id;
              if (task.task_status !== undefined) item.task_status = task.task_status;
              if (task.template_id) item.template_id = task.template_id;
              if (task.properties) item.properties = task.properties;
              if (task.input_text) item.input_text = task.input_text;
              if (task.images) item.images = task.images;
              if (task.rep_detail_list) {
                item.rep_detail_list = task.rep_detail_list;
                if (task.is_not_required !== undefined) item.is_not_required = task.is_not_required;
                if (task.task_name !== undefined) item.task_name = task.task_name;
                if (task.status !== undefined) item.status = task.status;
                if (task.punish_time !== undefined) item.punish_time = task.punish_time;
              }
              if (task.sku_group_multi_detail_list) {
                item.sku_group_multi_detail_list = task.sku_group_multi_detail_list;
              }
              templateEditRequestList.push(item);
            }

            taskCount = templateEditRequestList.length;
            taskTypes = templateEditRequestList.map(t => t.task_type);

            templateData = {
              cat_id: catId,
              template_edit_request_list: templateEditRequestList
            };
          }
          // 如果是直接拦截的 edit_compliance 请求体，直接用
          else if (queryResult.template_edit_request_list) {
            templateData = queryResult;
            taskCount = queryResult.template_edit_request_list.length;
            taskTypes = queryResult.template_edit_request_list.map(t => t.task_type);
          }
          // 兼容旧格式
          else {
            templateData = queryResult;
            taskCount = 0;
          }

          const template = {
            id: Date.now().toString(),
            name: templateName,
            data: templateData,
            mallId: auth.mallId || state.mallId || null,
            createdAt: new Date().toISOString(),
            taskCount,
            taskTypes
          };

          const userServerResult = await saveUserTemplateToServerRecord({
            name: templateName,
            type: 'compliance',
            data: template,
            mallId: auth.mallId || state.mallId || null,
            isDefault: 0
          });
          if (!userServerResult.success) {
            sendResponse({ success: false, error: userServerResult.error || '服务器模板保存失败' });
            return;
          }
          if (userServerResult.success && (userServerResult.id || userServerResult.result?.id)) {
            template.serverId = userServerResult.id || userServerResult.result.id;
          }

          const { key: tplKey, templates } = await resolveComplianceTemplateStorage(auth.mallId || state.mallId || null);
          templates.push(template);
          await saveComplianceTemplateList(tplKey, templates);

          console.log('[TEMU运营助手] ✅ 模板保存成功:', templateName, '合规项:', taskCount);
          sendResponse({
            success: true,
            message: '云端保存成功',
            templateName,
            taskCount,
            taskTypes,
            cloudSaved: true,
            localOnly: false,
            warning: getUserTemplateSyncWarning(userServerResult)
          });
        } catch (error) {
          console.error('[TEMU运营助手] 保存模板失败:', error);
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'saveAsTemplateDirect':
      // 直接调用 API 保存模板（不使用监听/拦截）
      (async () => {
        try {
          const { spuId, templateName } = request.data;
          console.log('[TEMU运营助手] 开始保存模板（API方式）, spuId:', spuId, 'name:', templateName);

          const auth = await getAuth();
          if (!auth || !auth.mallId) {
            sendResponse({ success: false, error: '请先设置认证信息' });
            return;
          }

          // 步骤1：通过 page_query 获取 goodsId 和 wait_task_list（不过滤，直接拉取匹配）
          const pageQueryData = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/page_query', {
              page_num: 1,
              page_size: 50,
              spu_id: spuId
            }, auth, 25000);
          if (!pageQueryData.success || !pageQueryData.result?.data?.length) {
            console.error('[TEMU运营助手] page_query 无结果, spuId:', spuId, 'response:', JSON.stringify(pageQueryData).substring(0, 200));
            sendResponse({ success: false, error: '未找到商品（spu_id: ' + spuId + '），请确认该商品在合规列表中' });
            return;
          }

          // 匹配：先按 spu_id，再按 goods_id
          const productItem = pageQueryData.result.data.find(item =>
            String(item.spu_id) === String(spuId)
          ) || pageQueryData.result.data.find(item =>
            String(item.goods_id) === String(spuId)
          );

          if (!productItem) {
            console.error('[TEMU运营助手] page_query 返回了数据但未匹配, spuId:', spuId,
              '返回的 spu_ids:', pageQueryData.result.data.map(i => i.spu_id).join(', '));
            sendResponse({ success: false, error: '未匹配到商品（spu_id: ' + spuId + '），列表中没有该商品' });
            return;
          }

          const goodsId = productItem.goods_id;
          const catId = productItem.cat_id;
          const realSpuId = productItem.spu_id;
          const waitTaskList = productItem.wait_task_dtolist || [];
          console.log('[TEMU运营助手] page_query 成功, spuId:', realSpuId, 'goodsId:', goodsId, 'waitTaskList:', waitTaskList.length, '项');

          // 步骤2：通过 query_detail 获取完整的合规详情
          const detailData = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/query_detail', {
              goods_id: goodsId,
              spu_id: realSpuId,
              wait_task_list: waitTaskList
            }, auth, 25000);
          if (!detailData.success || !detailData.result) {
            sendResponse({ success: false, error: '获取合规详情失败: ' + (detailData.error_msg || '未知错误') });
            return;
          }

          console.log('[TEMU运营助手] query_detail 成功, 数据结构:', Object.keys(detailData.result));

          // 步骤3：从 query_detail 响应中提取模板数据
          // query_detail 返回的数据结构中包含每个合规任务的详情
          // 我们需要把它转换成 template_edit_request_list 格式
          const result = detailData.result;
          const templateEditRequestList = [];

          // 从 query_detail 的 result 中提取合规项数据
          // result 可能包含 wait_task_dtolist（带已填写值的完整任务列表）
          if (result.wait_task_dtolist) {
            for (const task of result.wait_task_dtolist) {
              const item = { task_type: task.task_type };
              if (task.task_id) item.task_id = task.task_id;
              if (task.template_id) item.template_id = task.template_id;
              if (task.properties) item.properties = task.properties;
              if (task.input_text) item.input_text = task.input_text;
              if (task.images) item.images = task.images;
              if (task.rep_detail_list) item.rep_detail_list = task.rep_detail_list;
              if (task.sku_group_multi_detail_list) {
                item.sku_group_multi_detail_list = task.sku_group_multi_detail_list.map(skuGroup => ({
                  sku_multi_detail: skuGroup.sku_multi_detail
                }));
              }
              // 保留其他可能的字段
              if (task.task_name) item.task_name = task.task_name;
              if (task.is_not_required !== undefined) item.is_not_required = task.is_not_required;
              templateEditRequestList.push(item);
            }
          }

          // 如果 wait_task_dtolist 没有数据，尝试从原始 wait_task_list 提取
          if (templateEditRequestList.length === 0) {
            for (const task of waitTaskList) {
              const item = { task_type: task.task_type };
              if (task.task_id) item.task_id = task.task_id;
              if (task.template_id) item.template_id = task.template_id;
              if (task.properties) item.properties = task.properties;
              if (task.input_text) item.input_text = task.input_text;
              if (task.rep_detail_list) item.rep_detail_list = task.rep_detail_list;
              if (task.sku_group_multi_detail_list) {
                item.sku_group_multi_detail_list = task.sku_group_multi_detail_list.map(skuGroup => ({
                  sku_multi_detail: skuGroup.sku_multi_detail
                }));
              }
              templateEditRequestList.push(item);
            }
          }

          console.log('[TEMU运营助手] 提取到模板数据, 合规项数:', templateEditRequestList.length,
            'task_types:', templateEditRequestList.map(t => t.task_type));

          if (templateEditRequestList.length === 0) {
            sendResponse({ success: false, error: '该 SPU 没有合规项数据可保存' });
            return;
          }

          // 步骤4：保存模板
          const template = {
            id: Date.now().toString(),
            name: templateName,
            data: {
              cat_id: catId,
              template_edit_request_list: templateEditRequestList
            },
            catId: catId,
            spuId: spuId,
            mallId: auth.mallId || state.mallId || null,
            createdAt: new Date().toISOString(),
            source: 'api_direct',
            taskCount: templateEditRequestList.length,
            taskTypes: templateEditRequestList.map(t => t.task_type)
          };

          const userServerResult = await saveUserTemplateToServerRecord({
            name: templateName,
            type: 'compliance',
            data: template,
            mallId: auth.mallId || state.mallId || null,
            isDefault: 0
          });
          if (!userServerResult.success) {
            sendResponse({ success: false, error: userServerResult.error || '服务器模板保存失败' });
            return;
          }
          if (userServerResult.success && (userServerResult.id || userServerResult.result?.id)) {
            template.serverId = userServerResult.id || userServerResult.result.id;
          }

          const { key: tplKey, templates } = await resolveComplianceTemplateStorage(auth.mallId || state.mallId || null);
          templates.push(template);
          await saveComplianceTemplateList(tplKey, templates);

          console.log('[TEMU运营助手] 模板保存成功:', template.name, '合规项数:', template.taskCount);

          sendResponse({
            success: true, 
            message: '云端保存成功',
            templateName: template.name,
            taskCount: template.taskCount,
            taskTypes: template.taskTypes,
            template: template,
            cloudSaved: true,
            localOnly: false,
            warning: getUserTemplateSyncWarning(userServerResult)
          });
        } catch (error) {
          console.error('[TEMU运营助手] 保存模板失败:', error);
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'getTemplates':
      // 获取模板列表
      (async () => {
        try {
          const mallId = await resolveCurrentComplianceMallId();
          if (!mallId) {
            sendResponse({ success: true, templates: [] });
            return;
          }
          const { key: tplKey, templates: localTemplates } = await resolveComplianceTemplateStorage(mallId);
          const serverResult = await fetchUserTemplatesFromServer('compliance', mallId);
          const serverTemplates = serverResult.success
            ? serverResult.templates.map(normalizeServerComplianceTemplate)
            : [];
          const templates = mergeTemplateRecords(serverTemplates, localTemplates);
          if (serverTemplates.length) await saveComplianceTemplateList(tplKey, templates);
          sendResponse({ success: true, templates, warning: serverResult.success ? '' : serverResult.error });
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'deleteTemplate':
      // 删除模板
      (async () => {
        try {
          const mallId = await resolveCurrentComplianceMallId();
          if (!mallId) {
            sendResponse({ success: false, error: '未检测到当前店铺，无法删除模板' });
            return;
          }
          const { key: tplKey, templates } = await resolveComplianceTemplateStorage(mallId);
          const target = templates.find(t => String(t.id) === String(request.templateId));
          if (target?.serverId) await deleteUserTemplateFromServer(target.serverId, target.mallId || mallId);
          const newTemplates = templates.filter(t => String(t.id) !== String(request.templateId));
          await saveComplianceTemplateList(tplKey, newTemplates);
          sendResponse({ success: true });
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'checkCookies':
      // 检查 cookie（用于诊断）
      (async () => {
        try {
          const domains = [
            '.kuajingmaihuo.com',
            '.temu.com',
            'kuajingmaihuo.com',
            'temu.com'
          ];
          
          let allCookies = [];
          let antiContent = null;
          
          for (const domain of domains) {
            try {
              const cookies = await chrome.cookies.getAll({ domain });
              allCookies = allCookies.concat(cookies);
              
              // 查找 _bee cookie
              const beeCookie = cookies.find(c => c.name === '_bee');
              if (beeCookie && beeCookie.value) {
                antiContent = beeCookie.value;
              }
            } catch (e) {
              console.log(`[TEMU运营助手] 获取 ${domain} 的 cookie 失败:`, e);
            }
          }
          
          sendResponse({ 
            success: true, 
            count: allCookies.length,
            antiContent: antiContent
          });
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    // ========== 从 toast 确认保存模板（webRequest 拦截方式）==========
    case 'confirmSaveFromToast':
      (async () => {
        if (!pendingSaveData) {
          sendResponse({ success: false, error: '没有待保存的数据（可能已超时）' });
          return;
        }

        const bodyData = pendingSaveData.body || {};
        const auth = await getAuth().catch(() => null);
        const mallId = String(bodyData.mall_id || bodyData.mallId || auth?.mallId || state.mallId || '').trim();
        if (!mallId) {
          sendResponse({ success: false, error: '未检测到店铺 ID，请先重新连接店铺后再保存模板' });
          return;
        }

        const taskTypes = (bodyData.template_edit_request_list || []).map(t => t.task_type);
        const templateName = request.templateName || ('模板-' + bodyData.spu_id);

        const template = {
          id: Date.now().toString(),
          name: templateName,
          data: bodyData,
          spuId: String(bodyData.spu_id || ''),
          goodsId: String(bodyData.goods_id || ''),
          catId: bodyData.cat_id,
          mallId,
          createdAt: new Date().toISOString(),
          source: 'webRequest_intercept',
          taskCount: taskTypes.length,
          taskTypes
        };

        const userServerResult = await saveUserTemplateToServerRecord({
          name: templateName,
          type: 'compliance',
          data: template,
          mallId,
          isDefault: 0
        });
        if (!userServerResult.success) {
          sendResponse({ success: false, error: userServerResult.error || '服务器模板保存失败' });
          return;
        }
        if (userServerResult.success && (userServerResult.id || userServerResult.result?.id)) {
          template.serverId = userServerResult.id || userServerResult.result.id;
        }

        const { key: tplKey, templates } = await resolveComplianceTemplateStorage(mallId);
        templates.push(template);
        await saveComplianceTemplateList(tplKey, templates);
        if (!state.mallId) state.mallId = mallId;

        pendingSaveData = null;
        console.log('[TEMU运营助手] ✅ 模板保存成功（webRequest拦截）:', template.name, '合规项:', taskTypes.length, 'storageKey:', tplKey);
        sendResponse({
          success: true,
          message: '云端保存成功',
          templateName: template.name,
          taskCount: taskTypes.length,
          cloudSaved: true,
          localOnly: false,
          warning: getUserTemplateSyncWarning(userServerResult)
        });
      })().catch(error => {
        console.error('[TEMU运营助手] 模板保存失败（webRequest拦截）:', error);
        sendResponse({ success: false, error: error.message || '保存模板失败' });
      });
      return true;

    // ========== 自动模板保存已移除（改用 webRequest 拦截 + toast 确认方式）==========
    // 不同SPU的合规项数量和种类不同，模板应由用户手动通过"保存为模板"按钮保存
    // 相关的 MT_TEMU_LISTEN_GOVERN_REQUEST 和 MT_TEMU_SAVE_COMPLIANVE_INFORMATION_MODE 已删除
      
    // ========== 实拍图上传 ==========
    case 'uploadLivePhoto':
      // 上传实拍图
      (async () => {
        try {
          const result = await uploadLivePhoto(request.params);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'uploadLivePhotosBatch':
      // 批量上传实拍图（多张图片一次性提交）
      (async () => {
        try {
          const result = await uploadLivePhotosBatch(request.params);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'getLivePhotoList':
      // 获取实拍图列表
      (async () => {
        try {
          const result = await getLivePhotoList(request.params);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    // ========== 自动核价 ==========
    case 'getPricingList':
      (async () => {
        try {
          const result = await getPricingList(request.params);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;

    case 'diagnosePricingReference':
      (async () => {
        try {
          const result = await collectPricingDiagnostics();
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error?.message || String(error) });
        }
      })();
      return true;
      
    case 'getMinPrice':
      (async () => {
        try {
          const result = await getMinPrice(request.params.skuIds);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'batchSaveMinPrice':
      (async () => {
        try {
          const result = await batchSaveMinPrice(request.params.items);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'approvePricing':
      (async () => {
        try {
          const result = await approvePricing(request.params.priceOrderId, request.params.items, request.params.customPrices);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;

    case 'resubmitPricing':
      (async () => {
        try {
          const result = await resubmitPricing(request.params.priceOrderId, request.params.items, request.params.customPrices);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'rejectPricing':
      (async () => {
        try {
          const result = await rejectPricing(request.params.priceOrderId, request.params.items);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;
      
    case 'voidPricing':
      (async () => {
        try {
          const result = await voidPricing(request.params.priceOrderId);
          sendResponse(result);
        } catch (error) {
          sendResponse({ success: false, error: error.message });
        }
      })();
      return true;

    case 'fetchSalesData':
      fetchSalesData(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchSalesData 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchSalesDataAll':
      // 获取所有页面数据，用于仪表盘汇总（照抄大白鹅逻辑：逐页加载汇总）
      fetchSalesDataAll(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchSalesDataAll 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchCustomizedProductList':
      fetchCustomizedProductList(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchCustomizedProductList 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchCustomizedProductsFromTemuListPage':
      fetchCustomizedProductList(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchCustomizedProductsFromTemuListPage 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchCustomizedProductStatusCount':
      fetchCustomizedProductStatusCount(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchCustomizedProductStatusCount 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'getCustomizedBatchActionProgress':
      sendResponse(readCustomizedBatchActionProgress(request.taskId || request.params?.taskId || ''));
      return true;

    case 'batchDelistCustomizedSkc':
      batchDelistCustomizedSkc(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] batchDelistCustomizedSkc 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'batchPublishCustomizedSkc':
      batchPublishCustomizedSkc(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] batchPublishCustomizedSkc 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchActivityList':
      fetchActivityList(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchActivityList 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'scrollMatchActivity':
      scrollMatchActivity(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] scrollMatchActivity 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'enrollActivity':
      enrollActivity(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] enrollActivity 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchQualificationPool':
      fetchQualificationPool(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchQualificationPool 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchQualificationDetail':
      fetchQualificationDetail(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchQualificationDetail 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'buildQualificationTemplateFromSpu':
      buildQualificationTemplateFromSpu(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] buildQualificationTemplateFromSpu 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'createQualificationBatchTask':
      createQualificationBatchTask(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] createQualificationBatchTask 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'fetchQualificationCertInfo':
      fetchQualificationCertInfo(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchQualificationCertInfo 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;
      
    case 'submitQualificationAudit':
      submitQualificationAudit(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] submitQualificationAudit 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'queryQualificationSubmitStatus':
      queryQualificationSubmitStatus(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] queryQualificationSubmitStatus 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'uploadQualification':
      uploadQualification(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] uploadQualification 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'uploadQualificationBatch':
      uploadQualificationBatch(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] uploadQualificationBatch 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'fetchCustomizedTemplateData':
      fetchCustomizedTemplateData(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] fetchCustomizedTemplateData 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'applyCustomizedTemplateToSkus':
      applyCustomizedTemplateToSkus(request.params).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] applyCustomizedTemplateToSkus 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'ping':
      // 心跳检测，用于唤醒 Service Worker
      sendResponse({ success: true, timestamp: Date.now() });
      break;

    case 'getExtensionInfo':
      sendResponse({
        success: true,
        version: chrome.runtime.getManifest?.().version || '2.3.9',
        name: chrome.runtime.getManifest?.().name || '小青蛙电商助手'
      });
      break;

    case 'COLLECT_CURRENT_TEMU_GOODS':
      {
        const tabId = sender?.tab?.id;
        const url = request.url || sender?.tab?.url || '';
        if (!tabId) {
          sendResponse({ success: false, error: '未找到当前标签页，无法采集' });
          break;
        }
        collectProductFromCurrentTab(tabId, url).then(sendResponse).catch(err => {
          console.error('[TEMU运营助手] COLLECT_CURRENT_TEMU_GOODS 出错:', err);
          sendResponse({ success: false, error: err.message });
        });
        return true;
      }

    case 'GET_FINANCE_DATA':
      getAuth().then(auth => {
        return getFinanceData(auth.mallId, auth.antiContent);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] GET_FINANCE_DATA 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'GET_FINANCE_HISTORY':
      getAuth().then(auth => {
        return getFinanceHistory(auth.mallId, auth.antiContent, request.startDate, request.endDate, request.page, request.pageSize);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] GET_FINANCE_HISTORY 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'CREATE_UPLOAD_LOT':
      getAuth().then(auth => {
        return createUploadLot(auth.mallId, auth.antiContent);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] CREATE_UPLOAD_LOT 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'SAVE_COLLECTION_DATA':
      getAuth().then(auth => {
        return saveCollectionData(request.lotId, request.productData, auth.mallId, auth.antiContent);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] SAVE_COLLECTION_DATA 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'GET_GOODS_METADATA':
      getAuth().then(auth => {
        return getGoodsMetadata(request.goodsId, auth.mallId, auth.antiContent);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] GET_GOODS_METADATA 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'FETCH_MOVE_PRODUCT_DETAIL':
      getAuth().then(auth => {
        return fetchMoveProductDetailForTemplate(request, auth);
      }).then(result => {
        sendResponse(result);
      }).catch(err => {
        console.error('[TEMU运营助手] FETCH_MOVE_PRODUCT_DETAIL 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'GET_RECOMMENDED_CATEGORY':
      getAuth().then(auth => {
        return getRecommendedCategory(request.imageUrl, auth.mallId, auth.antiContent);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] GET_RECOMMENDED_CATEGORY 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'CREATE_PRODUCT_DRAFT':
      getAuth().then(auth => {
        return createProductDraft(request.draftData, auth.mallId, auth.antiContent);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] CREATE_PRODUCT_DRAFT 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'COPY_MOVE_PRODUCT_TO_DRAFT':
      getAuth().then(auth => {
        return createProductDraft(request.productData || request.draftData || {}, auth.mallId, auth.antiContent);
      }).then(result => {
        const data = result?.result || result?.data || result || {};
        sendResponse({
          success: result?.success !== false && result?.code !== -1,
          data,
          productDraftId: data.productDraftId || data.draftId || data.id || '',
          editUrl: data.editUrl || data.url || ''
        });
      }).catch(err => {
        console.error('[TEMU运营助手] COPY_MOVE_PRODUCT_TO_DRAFT 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'CREATE_TEMU_UPLOAD_PRODUCT_DRAFT':
      getAuth().then(auth => {
        return createTemuUploadProductDraft(request.payload || {}, auth);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] CREATE_TEMU_UPLOAD_PRODUCT_DRAFT 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'BATCH_PUBLISH_TEMU_DRAFTS':
      getAuth().then(auth => {
        return batchPublishTemuDrafts(request.params || {}, auth);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] BATCH_PUBLISH_TEMU_DRAFTS 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    case 'SUBMIT_PRODUCT':
      getAuth().then(auth => {
        return submitProduct(request.productData, auth.mallId, auth.antiContent);
      }).then(sendResponse).catch(err => {
        console.error('[TEMU运营助手] SUBMIT_PRODUCT 出错:', err);
        sendResponse({ success: false, error: err.message });
      });
      return true;

    default:
      sendResponse({ error: 'Unknown action' });
  }
});


// ========== Restored shared TEMU APIs ==========
const taskQueue = [];

async function addTask(task) {
  taskQueue.push({ ...task, status: 'pending', createdAt: Date.now() });
  processTasks();
  return { success: true, taskId: taskQueue.length - 1 };
}

async function getTaskStatus() {
  return { success: true, queue: taskQueue };
}

async function processTasks() {
  if (taskQueue.length === 0) return;
  const task = taskQueue.find(t => t.status === 'pending');
  if (!task) return;
  task.status = 'processing';
  try {
    if (task.type === 'batchUpload') await processBatchUpload(task);
    task.status = 'completed';
  } catch (error) {
    task.status = 'failed';
    task.error = error.message;
  }
  processTasks();
}

function readComplianceTaskStatusText(task = {}) {
  return String(
    task.statusText
    || task.statusLabel
    || task.status_name
    || task.statusName
    || task.status_desc
    || task.statusDesc
    || task.task_status_name
    || task.taskStatusName
    || task.task_status_desc
    || task.taskStatusDesc
    || ''
  ).trim();
}

function readComplianceTaskStatusCode(task = {}) {
  const code = Number(
    task.status
    ?? task.task_status
    ?? task.statusCode
    ?? task.taskStatus
    ?? task.status_code
    ?? task.task_status_code
  );
  return Number.isFinite(code) ? code : null;
}

function getComplianceTaskStatusMeta(task = {}) {
  const text = readComplianceTaskStatusText(task);
  const code = readComplianceTaskStatusCode(task);
  const normalized = text.toLowerCase();

  if (/完成|已上传|已完成|成功|通过|审核通过|uploaded|passed|success|done|approved|complete/i.test(text)) {
    return { state: 'completed', label: text || '上传成功', code, text };
  }
  if (/审核中|待审|待审核|审核|review|processing|in\s*review|reviewing|pending\s*review/i.test(text)) {
    return { state: 'reviewing', label: text || '审核中', code, text };
  }
  if (/待上传|未上传|待处理|待补充|未开始|缺失|缺少|waiting|to\s*upload|missing|required|pending/i.test(text) || /waiting|missing|required|pending/.test(normalized)) {
    return { state: 'pending', label: text || '待上传', code, text };
  }
  if (/废弃|失效|作废|expired|abandoned|closed/i.test(text)) {
    return { state: 'closed', label: text || '已失效', code, text };
  }
  if (code === 3) {
    return { state: 'completed', label: '上传成功', code, text };
  }
  return { state: 'pending', label: text || (code !== null ? `待确认状态 ${code}` : '待上传'), code, text };
}

function getComplianceTasksForUpload(waitTaskList = []) {
  return Array.isArray(waitTaskList) ? waitTaskList : [];
}

function readComplianceTaskSubmitStatus(task = {}) {
  const status = task.status ?? task.task_status ?? task.taskStatus ?? task.status_code ?? task.task_status_code ?? task.statusCode;
  return status === undefined || status === null || status === '' ? undefined : status;
}

function hasComplianceListValue(value) {
  return Array.isArray(value) && value.length > 0;
}

function buildComplianceSubmitDebugSummary(requestBody = {}, responseData = {}) {
  const editList = Array.isArray(requestBody.template_edit_request_list) ? requestBody.template_edit_request_list : [];
  return {
    spuId: requestBody.spu_id,
    goodsId: requestBody.goods_id,
    catId: requestBody.cat_id,
    taskCount: editList.length,
    tasks: editList.map(item => ({
      task_type: item.task_type,
      task_id: item.task_id,
      task_status: item.task_status,
      status: item.status,
      template_id: item.template_id,
      hasProperties: !!item.properties && Object.keys(item.properties || {}).length > 0,
      hasImages: !!item.images && Object.keys(item.images || {}).length > 0,
      hasInputText: !!item.input_text && Object.keys(item.input_text || {}).length > 0,
      repDetailCount: Array.isArray(item.rep_detail_list) ? item.rep_detail_list.length : undefined,
      skuGroupCount: Array.isArray(item.sku_group_multi_detail_list) ? item.sku_group_multi_detail_list.length : undefined,
      skuGroupSkuCounts: Array.isArray(item.sku_group_multi_detail_list)
        ? item.sku_group_multi_detail_list.map(group => Array.isArray(group.sku_ids) ? group.sku_ids.length : 0)
        : undefined
    })),
    response: {
      success: responseData?.success,
      error_code: responseData?.error_code,
      error_msg: responseData?.error_msg,
      message: responseData?.message
    }
  };
}

function stripComplianceTaskUiFields(task = {}) {
  const cleanTask = { ...task };
  delete cleanTask.statusText;
  delete cleanTask.statusState;
  delete cleanTask.statusCode;
  delete cleanTask.status_state;
  return cleanTask;
}

function stripComplianceWaitTaskList(waitTaskList = []) {
  return (Array.isArray(waitTaskList) ? waitTaskList : []).map(stripComplianceTaskUiFields);
}

function buildComplianceProductFromListItem(item = {}) {
  const waitTaskList = Array.isArray(item.wait_task_dtolist) ? item.wait_task_dtolist : [];
  const enhancedWaitTaskList = [];
  const requiredTasks = [];
  const optionalTasks = [];
  const completedTasks = [];
  const reviewingTasks = [];
  const closedTasks = [];

  waitTaskList.forEach(task => {
    const meta = getComplianceTaskStatusMeta(task);
    const taskInfo = {
      name: task.task_name || `任务${task.task_type}`,
      type: task.task_type,
      required: !task.is_not_required,
      taskStatus: readComplianceTaskStatusCode(task),
      statusText: meta.label,
      statusState: meta.state
    };
    enhancedWaitTaskList.push({
      ...task,
      statusText: meta.label,
      statusState: meta.state,
      statusCode: meta.code
    });

    if (meta.state === 'completed') {
      completedTasks.push(taskInfo);
    } else if (meta.state === 'reviewing') {
      reviewingTasks.push(taskInfo);
    } else if (meta.state === 'closed') {
      closedTasks.push(taskInfo);
    } else if (task.is_not_required) {
      optionalTasks.push(taskInfo);
    } else {
      requiredTasks.push(taskInfo);
    }
  });

  const status = requiredTasks.length > 0 || optionalTasks.length > 0 ? 'pending' : 'completed';
  const details = [];
  if (requiredTasks.length > 0) details.push(`必需: ${requiredTasks.length}项`);
  if (optionalTasks.length > 0) details.push(`可选: ${optionalTasks.length}项`);
  if (reviewingTasks.length > 0) details.push(`审核中: ${reviewingTasks.length}项`);
  if (completedTasks.length > 0) details.push(`已完成: ${completedTasks.length}项`);
  if (closedTasks.length > 0) details.push(`已失效: ${closedTasks.length}项`);

  return {
    spuId: item.spu_id,
    goodsId: item.goods_id,
    catId: item.cat_id,
    spuName: item.spu_name,
    status,
    statusDetail: details.length > 0 ? details.join(' | ') : '合规信息已完整',
    requiredTasks,
    optionalTasks,
    completedTasks,
    reviewingTasks,
    closedTasks,
    waitTaskList: enhancedWaitTaskList,
    mainImage: item.main_image || item.image_url || item.goods_img || item.thumb_url || item.preview_img || item.spu_image || item.product_image || '',
    _raw: item
  };
}

async function fetchProductList(params = {}) {
  const auth = await getAuth();
  
  // 不再强制要求认证信息，直接尝试调用 API
  // 如果没有认证信息，API 会返回具体的错误
  
  try {
    const pageNum = params.pageNum || 1;
    const pageSize = params.pageSize || 50;
    const fetchAll = params.fetchAll || false;
    
    // 如果需要获取所有商品
    if (fetchAll) {
      return await fetchAllProducts(auth, pageSize);
    }
    
    const data = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/page_query', {
        page_num: pageNum,
        page_size: pageSize,
        type: 2
      }, auth, 25000);
    
    console.log('[TEMU运营助手] API 响应:', data);
    
    if (data.success) {
      // 输出第一条数据的结构，帮助调试
      if (data.result.data.length > 0) {
        const firstItem = data.result.data[0];
        console.log('[TEMU运营助手] 第一条商品数据:', {
          spu_id: firstItem.spu_id,
          spu_name: firstItem.spu_name,
          goods_id: firstItem.goods_id,
          wait_task_dtolist: firstItem.wait_task_dtolist,
          status: firstItem.status,
          audit_status: firstItem.audit_status,
          compliance_status: firstItem.compliance_status,
          // 输出所有字段名，帮助调试
          allFields: Object.keys(firstItem)
        });
      }
      
      const products = data.result.data.map(buildComplianceProductFromListItem);
      
      const total = data.result.total;
      const totalPages = Math.ceil(total / pageSize);

      // 如果商品没有主图，尝试通过商品信息 API 补充
      const spuIds = products.filter(p => !p.mainImage).map(p => p.spuId);
      if (spuIds.length > 0) {
        try {
          console.log('[TEMU运营助手] 尝试获取主图，SPU 数量:', spuIds.length);
          
          // 方案1: 通过 listWarehouse 获取主图（最可靠）
          const warehouseData = await temuSellerPost('https://agentseller.temu.com/mms/venom/api/supplier/goods/manage/listWarehouse', { pageNo: 1, pageSize: 200, isLack: 0 }, auth, 25000);
          if (warehouseData?.success && warehouseData?.result) {
            const warehouseList = warehouseData.result.subOrderList || warehouseData.result.productList || warehouseData.result.list || [];
            const imgMap = {};
            warehouseList.forEach(item => {
              const pid = item.productId || item.product_id || item.spuId || '';
              const img = item.productSkcPicture || item.mainImage || item.main_image
                || item.imageUrl || item.image_url || item.thumbUrl || item.goodsImg || '';
              if (img && pid) imgMap[pid] = img;
              // 也用 goods_id 和 skc_id 匹配
              const gid = item.goodsId || item.goods_id || '';
              if (img && gid) imgMap[gid] = img;
            });
            products.forEach(p => {
              if (!p.mainImage) {
                p.mainImage = imgMap[p.spuId] || imgMap[p.goodsId] || '';
              }
            });
            console.log('[TEMU运营助手] listWarehouse主图补充完成，仓库商品数:', warehouseList.length);
          }
          
          // 方案2: 如果还有商品没主图，再通过商品信息API
          const stillNoImg = products.filter(p => !p.mainImage).map(p => p.spuId);
          if (stillNoImg.length > 0) {
            const imgData = await temuSellerPost('https://agentseller.temu.com/professional/goods/info/query/goods/by/product/spu/ids', { spuIds: stillNoImg.slice(0, 50) }, auth, 25000);
            if (imgData && imgData.detail && imgData.detail.items) {
              const imgMap2 = {};
              imgData.detail.items.forEach(item => {
                console.log('[TEMU运营助手] 商品图片数据字段:', Object.keys(item));
                const img = item.main_image || item.mainImage || item.thumb_url || item.goods_img
                  || item.previewImgUrl || item.productImgUrl || item.skuPreviewImage
                  || item.imageUrl || item.image_url || item.goodsImage || item.goods_image
                  || (item.previewImgUrlList && item.previewImgUrlList[0])
                  || (item.imageList && item.imageList[0]) || '';
                if (img && item.product_id) imgMap2[item.product_id] = img;
                if (img && item.goods_id) imgMap2[item.goods_id] = img;
              });
              products.forEach(p => {
                if (!p.mainImage) {
                  p.mainImage = imgMap2[p.spuId] || imgMap2[p.goodsId] || '';
                }
              });
              console.log('[TEMU运营助手] 商品信息API主图补充完成，成功:', Object.keys(imgMap2).length, '个');
            }
          }
        } catch (e) {
          console.warn('[TEMU运营助手] 获取主图失败:', e.message);
        }
      }
      
      return { 
        success: true, 
        products, 
        total,
        pageNum,
        pageSize,
        totalPages
      };
    } else {
      return { success: false, error: data.error_msg || '获取商品列表失败', errorCode: data.error_code };
    }
  } catch (error) {
    console.error('[TEMU运营助手] API 调用失败:', error);
    return { success: false, error: error.message };
  }
}

async function fetchAllProducts(auth, pageSize = 200) {
  console.log('[TEMU运营助手] 开始获取所有商品...');
  
  let allProducts = [];
  let pageNum = 1;
  let total = 0;
  let totalPages = 0;
  
  while (true) {
    console.log(`[TEMU运营助手] 获取第 ${pageNum} 页...`);
    
    const data = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/page_query', {
        page_num: pageNum,
        page_size: pageSize,
        type: 2
      }, auth, 25000);
    
    if (!data.success) {
      return { success: false, error: data.error_msg || '获取商品列表失败' };
    }
    
    const products = data.result.data.map(buildComplianceProductFromListItem);
    
    allProducts = allProducts.concat(products);
    
    if (pageNum === 1) {
      total = data.result.total;
      totalPages = Math.ceil(total / pageSize);
      console.log(`[TEMU运营助手] 总共 ${total} 条商品，${totalPages} 页`);
    }
    
    // 如果当前页的数据少于 pageSize，说明已经是最后一页
    if (products.length < pageSize) {
      break;
    }
    
    pageNum++;
    
    // 安全限制：最多获取 100 页
    if (pageNum > 100) {
      console.log('[TEMU运营助手] 达到最大页数限制（100页）');
      break;
    }
  }
  
  console.log(`[TEMU运营助手] 获取完成，共 ${allProducts.length} 条商品`);
  
  return {
    success: true,
    products: allProducts,
    total: allProducts.length,
    pageNum: 1,
    pageSize: allProducts.length,
    totalPages: 1,
    fetchedAll: true
  };
}

async function fetchComplianceList(params = {}) {
  const auth = await getAuth();
  if (!auth || !auth.mallId) {
    return { success: false, error: '请先设置认证信息' };
  }
  
  try {
    const data = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/query_detail', {
        goods_id: params.goodsId,
        spu_id: params.spuId,
        wait_task_list: stripComplianceWaitTaskList(params.waitTaskList || [])
      }, auth, 25000);
    
    if (data.success) {
      return { success: true, data: data.result };
    } else {
      return { success: false, error: data.error_msg || '获取合规详情失败' };
    }
  } catch (error) {
    console.error('[TEMU运营助手] API 调用失败:', error);
    return { success: false, error: error.message };
  }
}

async function processBatchUpload(task) {
  const { products, template } = task.params;
  const auth = await getAuth();
  
  console.log('[TEMU运营助手] 开始批量上传，商品数:', products.length, '模板:', template?.name);
  
  // 更新进度
  task.progress = {
    total: products.length,
    completed: 0,
    failed: 0,
    currentSpuId: null,
    currentSpuName: null,
    status: 'processing',
    details: []
  };
  
  for (let i = 0; i < products.length; i++) {
    const product = products[i];
    task.progress.currentSpuId = product.spuId;
    task.progress.currentSpuName = product.spuName;
    
    console.log(`[TEMU运营助手] 处理商品 ${i + 1}/${products.length}:`, product.spuId, product.spuName);
    
    try {
      const uploadProduct = await resolveComplianceProductForUpload(product, auth);
      const uploadTaskList = getComplianceTasksForUpload(uploadProduct.waitTaskList || []);
      const hasProductIdentity = !!(uploadProduct.spuId && uploadProduct.goodsId);

      // 不按合规状态拦截：只要能定位到目标 SPU，就交给 TEMU 官方 query_detail/edit_compliance 判断能否重传。
      if (uploadProduct.resolveError && uploadTaskList.length === 0 && !hasProductIdentity) {
        console.warn('[TEMU运营助手] 商品缺少官方合规任务，未上传:', product.spuId, uploadProduct.resolveError);
        task.progress.failed++;
        task.progress.details.push({
          spuId: uploadProduct.spuId || product.spuId,
          spuName: uploadProduct.spuName || product.spuName,
          status: 'failed',
          message: uploadProduct.resolveError
        });
        continue;
      }
      
      // 提交合规信息（使用模板数据）。所有官方返回的合规状态都允许进入重传流程。
      const submitResult = await submitComplianceInfo({
        auth,
        spuId: uploadProduct.spuId,
        goodsId: uploadProduct.goodsId,
        catId: uploadProduct.catId,
        template: template,
        waitTaskList: uploadTaskList
      });
      
      if (submitResult.success) {
        console.log('[TEMU运营助手] 提交成功:', product.spuId);
        task.progress.completed++;
        task.progress.details.push({
          spuId: uploadProduct.spuId,
          spuName: uploadProduct.spuName,
          status: 'success',
          message: '上传成功'
        });
      } else {
        console.error('[TEMU运营助手] 提交失败:', product.spuId, submitResult.error);
        task.progress.failed++;
        task.progress.details.push({
          spuId: uploadProduct.spuId,
          spuName: uploadProduct.spuName,
          status: 'failed',
          message: submitResult.error,
          debugSummary: submitResult.debugSummary || null
        });
      }
      
      // 延迟，避免请求过快
      const delay = task.params.interval || 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
      
    } catch (error) {
      console.error('[TEMU运营助手] 处理商品失败:', product.spuId, error);
      task.progress.failed++;
      task.progress.details.push({
        spuId: product.spuId,
        spuName: product.spuName,
        status: 'failed',
        message: error.message
      });
    }
  }
  
  task.progress.status = 'completed';
  console.log('[TEMU运营助手] 批量上传完成:', {
    total: task.progress.total,
    completed: task.progress.completed,
    failed: task.progress.failed
  });
}

function normalizeComplianceProductForUpload(product = {}) {
  const raw = product._raw || product.raw || product;
  return {
    ...product,
    spuId: product.spuId || product.spu_id || raw.spu_id || raw.product_id || raw.productId || '',
    goodsId: product.goodsId || product.goods_id || raw.goods_id || raw.goodsId || '',
    catId: product.catId || product.cat_id || raw.cat_id || raw.catId || '',
    spuName: product.spuName || product.spu_name || raw.spu_name || raw.goods_name || raw.goodsName || '',
    waitTaskList: product.waitTaskList || product.wait_task_dtolist || raw.wait_task_dtolist || raw.waitTaskList || []
  };
}

async function resolveComplianceProductForUpload(product = {}, auth = {}) {
  const normalized = normalizeComplianceProductForUpload(product);
  if (normalized.goodsId && Array.isArray(normalized.waitTaskList) && normalized.waitTaskList.length > 0) {
    return normalized;
  }

  const spuId = String(normalized.spuId || '').trim();
  if (!spuId) {
    return { ...normalized, resolveError: '缺少 SPU ID，无法查询合规任务' };
  }

  try {
    const requestBodies = [
      {
        page_num: 1,
        page_size: 50,
        spu_id: spuId,
        type: 2
      },
      {
        page_num: 1,
        page_size: 50,
        spu_id: spuId
      }
    ];

    let data = null;
    let item = null;
    for (const requestBody of requestBodies) {
      data = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/page_query', requestBody, auth, 25000);
      const list = data?.result?.data || data?.result?.list || data?.data || [];
      if (!data?.success || !Array.isArray(list) || list.length === 0) {
        continue;
      }

      item = list.find(row => String(row?.spu_id || row?.product_id || '').trim() === spuId)
        || list.find(row => String(row?.goods_id || row?.goodsId || '').trim() === spuId)
        || list[0];
      if (item) break;
    }

    if (!item) {
      return { ...normalized, resolveError: getTemuApiMessage(data, `未在合规列表找到 SPU ${spuId}`) };
    }

    return normalizeComplianceProductForUpload({
      ...normalized,
      _raw: item,
      spuId: item.spu_id || normalized.spuId,
      goodsId: item.goods_id || normalized.goodsId,
      catId: item.cat_id || normalized.catId,
      spuName: item.spu_name || normalized.spuName,
      waitTaskList: item.wait_task_dtolist || normalized.waitTaskList || []
    });
  } catch (error) {
    return { ...normalized, resolveError: error?.message || `查询 SPU ${spuId} 合规任务失败` };
  }
}

async function submitComplianceInfo({ auth, spuId, goodsId, catId, template, waitTaskList }) {
  console.log('[TEMU运营助手] ========== 开始提交合规信息 ==========');
  console.log('[TEMU运营助手] 参数:', {
    spuId,
    goodsId,
    catId,
    templateName: template?.name,
    templateId: template?.id,
    hasData: !!template?.data,
    waitTaskList: waitTaskList?.length,
    waitTaskTypes: waitTaskList?.map(t => t.task_type)
  });
  
  try {
    // 从模板获取保存的请求数据
    const templateData = template?.data;
    
    console.log('[TEMU运营助手] 模板数据:', {
      hasTemplateData: !!templateData,
      templateSpuId: templateData?.spu_id,
      templateGoodsId: templateData?.goods_id,
      templateCatId: templateData?.cat_id,
      templateEditListLength: templateData?.template_edit_request_list?.length,
      templateEditListTypes: templateData?.template_edit_request_list?.map(t => t.task_type)
    });
    
    if (!templateData) {
      console.error('[TEMU运营助手] 模板数据为空！');
      return { success: false, error: '模板数据为空' };
    }
    
    if (!templateData.template_edit_request_list || templateData.template_edit_request_list.length === 0) {
      console.error('[TEMU运营助手] 模板的 template_edit_request_list 为空！');
      return { success: false, error: '模板数据不完整：缺少 template_edit_request_list' };
    }
    
    // 构建请求体
    // 关键：只取 waitTaskList 的必要字段，叠加模板数据，不污染请求体
    console.log('[TEMU运营助手] 开始构建 requestBody...');
    console.log('[TEMU运营助手] waitTaskList:', JSON.stringify(waitTaskList, null, 2));
    console.log('[TEMU运营助手] template_edit_request_list:', JSON.stringify(templateData.template_edit_request_list, null, 2));
    
    // 先获取目标 SPU 的 sku_ids（用于包装材料任务）。
    // 提交结构保持原先验证可用的 edit_compliance 结构，只是不再按“待处理状态”过滤任务。
    let targetSkuIds = [];
    let detailWaitTaskList = [];
    try {
      const detailData = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/query_detail', {
          goods_id: goodsId,
          spu_id: spuId,
          wait_task_list: stripComplianceWaitTaskList(waitTaskList)
        }, auth, 25000);
      if (detailData.success && detailData.result?.sku_info_list) {
        targetSkuIds = detailData.result.sku_info_list.map(sku => sku.sku_id).filter(Boolean);
        console.log('[TEMU运营助手] 获取到目标 SPU sku_ids:', targetSkuIds);
      }
      if (detailData.success && Array.isArray(detailData.result?.wait_task_dtolist)) {
        detailWaitTaskList = detailData.result.wait_task_dtolist;
      }
    } catch (e) {
      console.error('[TEMU运营助手] 获取 sku_ids 失败:', e);
    }

    const sourceTaskList = getComplianceTasksForUpload(waitTaskList || []);
    const detailTaskList = getComplianceTasksForUpload(detailWaitTaskList);
    const effectiveWaitTaskList = detailTaskList.length > 0 ? detailTaskList : sourceTaskList;
    
    const skippedTemplateTaskTypes = [];
    const missingTargetSkuTaskTypes = [];
    const missingTargetTaskIdTypes = [];
    const templateEditRequestList = (effectiveWaitTaskList || []).map(task => {
      // 从模板中找到对应任务类型的数据。目标商品多出的官方任务不阻断上传，直接跳过。
      const taskType = task.task_type ?? task.taskType;
      const taskStatus = readComplianceTaskSubmitStatus(task);
      const templateItem = templateData.template_edit_request_list?.find(
        t => String(t.task_type) === String(taskType)
      );

      if (!templateItem) {
        skippedTemplateTaskTypes.push(taskType);
        return null;
      }

      if (!task.task_id) {
        missingTargetTaskIdTypes.push(task.task_type);
        return null;
      }

      // ====== 根据 cURL 抓包分析，三种任务类型结构完全不同 ======

      // 类型A：rep 类任务（25=土代, 60=制造商, 84=欧代）
      // 特点：有 rep_detail_list，没有 template_id/properties/images/input_text
      if (hasComplianceListValue(templateItem.rep_detail_list)) {
        return {
          task_id: task.task_id,
          task_type: taskType,
          is_not_required: task.is_not_required,
          task_name: task.task_name,
          status: taskStatus,
          punish_time: task.punish_time,
          task_status: taskStatus,
          rep_detail_list: templateItem.rep_detail_list
        };
      }

      // 类型B：包装材料任务（166=包装材料信息）
      // 特点：有 sku_group_multi_detail_list，没有 properties/images/input_text
      if (hasComplianceListValue(templateItem.sku_group_multi_detail_list)) {
        if (!targetSkuIds.length) {
          missingTargetSkuTaskTypes.push(taskType);
          return null;
        }
        return {
          task_id: task.task_id,
          task_status: taskStatus,
          task_type: taskType,
          template_id: templateItem.template_id,
          sku_group_multi_detail_list: templateItem.sku_group_multi_detail_list.map(group => ({
            sku_ids: targetSkuIds,
            sku_multi_detail: group.sku_multi_detail
          }))
        };
      }

      // 类型C：普通属性任务（4/33/35/37/41/42/61 等）
      // 特点：有 template_id、properties，始终有 images:{} 和 input_text:{}
      return {
        task_id: task.task_id,
        task_status: taskStatus,
        task_type: taskType,
        template_id: templateItem.template_id,
        properties: templateItem.properties || {},
        images: templateItem.images !== undefined ? templateItem.images : {},
        input_text: templateItem.input_text !== undefined ? templateItem.input_text : {}
      };
    }).filter(item => item !== null);
    
    console.log('[TEMU运营助手] 构建的 template_edit_request_list 长度:', templateEditRequestList.length);
    if (skippedTemplateTaskTypes.length > 0) {
      console.warn('[TEMU运营助手] 目标商品存在模板未覆盖的官方合规任务，已跳过:', [...new Set(skippedTemplateTaskTypes)].join(', '));
    }

    if (missingTargetTaskIdTypes.length > 0) {
      const missingText = [...new Set(missingTargetTaskIdTypes)].join(', ');
      console.error('[TEMU运营助手] 目标商品官方任务缺少 task_id，停止上传:', missingText);
      return { success: false, error: `TEMU 官方任务缺少 task_id，无法安全重传 task_type=${missingText}` };
    }

    if (missingTargetSkuTaskTypes.length > 0) {
      const missingText = [...new Set(missingTargetSkuTaskTypes)].join(', ');
      console.error('[TEMU运营助手] 目标商品缺少包装材料任务所需 SKU 列表，停止上传:', missingText);
      return { success: false, error: `TEMU query_detail 未返回目标 SKU，包装材料任务 task_type=${missingText} 未提交` };
    }
    
    if (templateEditRequestList.length === 0) {
      console.error('[TEMU运营助手] 构建的 template_edit_request_list 为空！');
      return { success: false, error: '目标商品没有与模板匹配的官方合规任务，本商品未上传' };
    }
    
    const requestBody = {
      spu_id: spuId,
      goods_id: goodsId,
      cat_id: catId || templateData.cat_id,
      group_sku_by_same_info: true,
      template_edit_request_list: templateEditRequestList
    };
    
    console.log('[TEMU运营助手] 最终请求体:', JSON.stringify(requestBody, null, 2));
    
    // 调用 TEMU API（使用 edit_compliance 接口）
    console.log('[TEMU运营助手] 调用 API...');
    console.log('[TEMU运营助手] API URL: https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/edit_compliance');
    console.log('[TEMU运营助手] Headers:', {
      'Content-Type': 'application/json',
      'mallid': auth.mallId,
      'anti-content': auth.antiContent ? '有值' : '无值'
    });
    
    const data = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/edit_compliance', requestBody, auth, 30000);
    
    console.log('[TEMU运营助手] API 响应数据:', JSON.stringify(data, null, 2));
    
    if (data.success) {
      console.log('[TEMU运营助手] ✅ 提交成功！');
      return { success: true, data: data.result };
    } else {
      console.error('[TEMU运营助手] ❌ 提交失败:', data.error_msg || data.message);
      console.error('[TEMU运营助手] 错误代码:', data.error_code);
      const debugSummary = buildComplianceSubmitDebugSummary(requestBody, data);
      console.error('[TEMU运营助手] 提交失败诊断摘要:', JSON.stringify(debugSummary, null, 2));
      return {
        success: false,
        error: data.error_msg || data.message || '提交失败',
        errorCode: data.error_code,
        debugSummary
      };
    }
    
  } catch (error) {
    console.error('[TEMU运营助手] 提交合规信息失败:', error);
    return { success: false, error: error.message };
  }
}

function buildLivePhotoListRequestBody(params = {}) {
  const pageNum = Number(params.pageNum || params.page || 1) || 1;
  const pageSize = Number(params.pageSize || params.page_size || 50) || 50;
  const spuId = normalizeTemuIdText(params.spuId);
  const goodsId = normalizeTemuIdText(params.goodsId);
  const productId = normalizeTemuIdText(params.productId || params.spuId);
  const idField = params.idField || '';
  const requestBody = params.requestBody && typeof params.requestBody === 'object'
    ? { ...params.requestBody }
    : {
      page: pageNum,
      page_size: pageSize
    };

  if (!params.requestBody) {
    if (Array.isArray(params.spuIdList) && params.spuIdList.length) {
      requestBody.spu_id_list = params.spuIdList.map(value => normalizeTemuIdText(value)).filter(Boolean);
    } else if (Array.isArray(params.productIds) && params.productIds.length) {
      requestBody.spu_id_list = params.productIds.map(value => normalizeTemuIdText(value)).filter(Boolean);
    } else if (idField === 'spu_id_list' && spuId) {
      requestBody.spu_id_list = [spuId].filter(Boolean);
    } else if (idField === 'goods_id' && goodsId) {
      requestBody.goods_id = goodsId;
    } else if (idField === 'product_id' && productId) {
      requestBody.product_id = productId;
    } else if (spuId) {
      requestBody.spu_id = spuId;
    }
  }

  return requestBody;
}

async function requestLivePhotoList(requestBody, auth) {
  console.log('[TEMU运营助手] getLivePhotoList 请求参数:', JSON.stringify(requestBody), 'auth:', auth?.mallId ? '有mallId' : '无mallId', auth?.antiContent ? '有antiContent' : '无antiContent');
  const data = await temuSellerPost('https://agentseller.temu.com/api/flash/real_picture/list', requestBody, auth, 25000);
  console.log('[TEMU运营助手] 实拍图列表 API 响应:', data);
  const list = extractTemuListFromPayload(data);
  const total = extractTemuTotalFromPayload(data, list.length);
  console.log('[TEMU运营助手] 实拍图列表条数:', list.length, '| total:', total);
  if (isTemuApiSuccess(data)) {
    return {
      success: true,
      list,
      total,
      requestBody
    };
  }
  return {
    success: false,
    list: [],
    total: 0,
    requestBody,
    error: getTemuApiMessage(data, data?.error_msg || data?.message || '获取实拍图列表失败'),
    errorCode: data?.error_code || data?.errorCode || data?.code
  };
}

function normalizeLivePhotoSearchKeyword(value = '') {
  return String(value || '').trim().toLowerCase();
}

function getLivePhotoItemSearchText(item = {}) {
  const ids = getLivePhotoItemIds(item);
  const name = readFirstTemuValueByKeys(item, [
    'spu_name',
    'spuName',
    'goods_name',
    'goodsName',
    'product_name',
    'productName',
    'title',
    'name'
  ], 4);
  return [...ids, name].map(value => String(value || '').toLowerCase()).join(' ');
}

function livePhotoItemMatchesKeyword(item = {}, keyword = '') {
  const query = normalizeLivePhotoSearchKeyword(keyword);
  if (!query) return true;
  const terms = query.split(/[\s,，\n]+/).filter(Boolean);
  if (!terms.length) return true;
  const haystack = getLivePhotoItemSearchText(item);
  return terms.every(term => haystack.includes(term));
}

function getLivePhotoUniqueItemKey(item = {}) {
  return getLivePhotoItemIds(item)[0] || JSON.stringify(getTemuKeysPreview(item));
}

function appendUniqueLivePhotoItems(target = [], items = []) {
  const seen = new Set(target.map(getLivePhotoUniqueItemKey).filter(Boolean));
  for (const item of Array.isArray(items) ? items : []) {
    const key = getLivePhotoUniqueItemKey(item);
    if (key && seen.has(key)) continue;
    if (key) seen.add(key);
    target.push(item);
  }
  return target;
}

async function searchLivePhotoListByKeyword(params = {}, auth, keyword = '') {
  const pageNum = Math.max(1, Number(params.pageNum || 1) || 1);
  const pageSize = Math.max(1, Number(params.pageSize || 10) || 10);
  const scanPageSize = Math.max(50, Number(params.scanPageSize || 100) || 100);
  const matched = [];
  let scannedPages = 0;
  let sourceTotal = 0;
  let firstError = '';
  const requestedSpuIds = Array.isArray(params.spuIdList) && params.spuIdList.length
    ? params.spuIdList.map(normalizeTemuIdText).filter(Boolean)
    : (Array.isArray(params.productIds) && params.productIds.length ? params.productIds.map(normalizeTemuIdText).filter(Boolean) : []);

  if (requestedSpuIds.length) {
    const resp = await requestLivePhotoList(buildLivePhotoListRequestBody({
      pageNum: 1,
      pageSize: Math.max(scanPageSize, requestedSpuIds.length),
      spuIdList: requestedSpuIds
    }), auth);
    if (resp.success) {
      appendUniqueLivePhotoItems(matched, resp.list.filter(item => {
        const ids = getLivePhotoItemIds(item).map(value => String(value || '').trim());
        return requestedSpuIds.some(spuId => ids.includes(spuId));
      }));
      const start = (pageNum - 1) * pageSize;
      return {
        success: true,
        list: matched.slice(start, start + pageSize),
        total: matched.length,
        keyword,
        searchedBy: 'spu_id_list'
      };
    }
    firstError = resp.error || '';
  }

  const numericKeyword = /^\d{6,}$/.test(String(keyword || '').trim()) ? String(keyword).trim() : '';
  if (numericKeyword) {
    const targetedRequests = [
      { pageNum: 1, pageSize: scanPageSize, spuId: numericKeyword, idField: 'spu_id_list' },
      { pageNum: 1, pageSize: scanPageSize, spuId: numericKeyword },
      { pageNum: 1, pageSize: scanPageSize, productId: numericKeyword, idField: 'product_id' },
      { pageNum: 1, pageSize: scanPageSize, goodsId: numericKeyword, idField: 'goods_id' }
    ];
    for (const requestParams of targetedRequests) {
      const resp = await requestLivePhotoList(buildLivePhotoListRequestBody(requestParams), auth);
      if (!resp.success) {
        firstError = firstError || resp.error || '';
        continue;
      }
      appendUniqueLivePhotoItems(matched, resp.list.filter(item => livePhotoItemMatchesKeyword(item, keyword)));
    }
    if (matched.length) {
      const start = (pageNum - 1) * pageSize;
      return {
        success: true,
        list: matched.slice(start, start + pageSize),
        total: matched.length,
        keyword,
        scannedPages: 0,
        searchedBy: 'targeted'
      };
    }
  }

  for (let page = 1; ; page += 1) {
    const resp = await requestLivePhotoList({ page, page_size: scanPageSize }, auth);
    scannedPages = page;
    if (!resp.success) {
      firstError = firstError || resp.error || '';
      if (page === 1) {
        return {
          success: false,
          error: firstError || '跨页筛选实拍图列表失败',
          keyword,
          scannedPages
        };
      }
      break;
    }
    sourceTotal = sourceTotal || Number(resp.total || 0) || 0;
    appendUniqueLivePhotoItems(matched, resp.list.filter(item => livePhotoItemMatchesKeyword(item, keyword)));

    const expectedPages = sourceTotal ? Math.ceil(sourceTotal / scanPageSize) : 0;
    if (expectedPages && page >= expectedPages) break;
    if (!expectedPages && resp.list.length < scanPageSize) break;
    if (resp.list.length === 0) break;
  }

  const start = (pageNum - 1) * pageSize;
  return {
    success: true,
    list: matched.slice(start, start + pageSize),
    total: matched.length,
    keyword,
    scannedPages,
    scannedTotal: sourceTotal,
    searchedBy: 'paged'
  };
}

async function getLivePhotoList(params = {}) {
  const auth = await getAuth();
  try {
    const keyword = normalizeLivePhotoSearchKeyword(params.keyword || params.search || '');
    if (keyword) {
      return await searchLivePhotoListByKeyword(params, auth, keyword);
    }
    return await requestLivePhotoList(buildLivePhotoListRequestBody(params), auth);
  } catch (error) {
    console.error('[TEMU运营助手] 获取实拍图列表失败:', error);
    return { success: false, error: error.message };
  }
}

async function getCapturedLivePhotoSnapshot() {
  try {
    const stored = await chrome.storage.local.get(['temuCapturedLivePhotoList']);
    const captured = stored?.temuCapturedLivePhotoList || {};
    return {
      items: Array.isArray(captured.items) ? captured.items : [],
      total: Number(captured.total || 0) || 0,
      capturedAt: captured.capturedAt || 0,
      requestBody: captured.requestBody && typeof captured.requestBody === 'object' ? captured.requestBody : null,
      url: captured.url || ''
    };
  } catch (error) {
    console.warn('[TEMU运营助手] 读取已捕获实拍图缓存失败:', error);
    return { items: [], total: 0, capturedAt: 0, requestBody: null, url: '' };
  }
}

function buildCapturedLivePhotoRequestBodies(captured = {}) {
  const base = captured?.requestBody && typeof captured.requestBody === 'object'
    ? captured.requestBody
    : null;
  if (!base) return [];

  const bodies = [];
  const seen = new Set();
  const pushBody = (body) => {
    if (!body || typeof body !== 'object') return;
    const key = JSON.stringify(body);
    if (seen.has(key)) return;
    seen.add(key);
    bodies.push(body);
  };

  pushBody({ ...base });
  const pageSize = Number(base.page_size || base.pageSize || base.size || base.limit || 0) || 100;
  const pageKeys = ['page', 'page_num', 'pageNum', 'currentPage'];
  for (const pageKey of pageKeys) {
    if (base[pageKey] !== undefined) {
      pushBody({ ...base, [pageKey]: 1 });
      pushBody({ ...base, [pageKey]: 1, page_size: pageSize });
      pushBody({ ...base, [pageKey]: 1, pageSize });
    }
  }
  return bodies.slice(0, 8);
}

async function uploadLivePhoto(params = {}) {
  const auth = await getAuth();
  
  try {
    const { spuId, imageData, filename } = params;
    
    if (!spuId) {
      return { success: false, error: '缺少 SPU ID' };
    }
    
    if (!imageData) {
      return { success: false, error: '缺少图片数据' };
    }
    
    console.log('[TEMU运营助手] 上传实拍图:', { spuId, filename });
    
    // 步骤0：通过 spuId 获取 goodsId 和 skuId
    const productInfo = await getProductInfoForPhoto(spuId, auth, params.productInfo || params.product || null);
    if (!productInfo) {
      return { success: false, error: `获取商品信息失败：TEMU 实拍图列表未返回 SPU ${spuId} 的 goods_id`, spuId };
    }
    
    console.log('[TEMU运营助手] 获取到商品信息:', {
      goodsId: productInfo.goodsId,
      skuCount: productInfo.skuList.length
    });
    
    // 步骤1：上传图片到 TEMU 图片服务器（signature → store_image）
    const imageUrl = await uploadImageToTemuAndGetUrl(imageData, filename, auth);
    
    if (!imageUrl) {
      return { success: false, error: '图片上传失败', spuId };
    }
    
    console.log('[TEMU运营助手] 图片上传成功，URL:', imageUrl);
    
    // 步骤2：构造实拍图数据（同时上传到 商品主体 + 商品外包装）
    const realPictureInfoList = [
      {
        position: 1,  // 商品主体实拍图
        is_same_sku: productInfo.skuList.length > 0 ? 1 : 0,
        sku_photo_info_list: productInfo.skuList.map(sku => ({
          sku_id: sku.skuId,
          image_list: [{ image_url: imageUrl }]
        }))
      },
      {
        position: 2,  // 商品外包装实拍图
        is_same_sku: productInfo.skuList.length > 0 ? 1 : 0,
        sku_photo_info_list: productInfo.skuList.map(sku => ({
          sku_id: sku.skuId,
          image_list: [{ image_url: imageUrl }]
        }))
      }
    ];
    
    const requestBody = {
      spu_id: spuId,
      goods_id: productInfo.goodsId,
      real_picture_info_list: realPictureInfoList
    };
    
    console.log('[TEMU运营助手] 实拍图请求体:', JSON.stringify(requestBody, null, 2));
    
    // 步骤3：预验证（pre_verification）
    const verifyData = await temuSellerPost('https://agentseller.temu.com/api/flash/real_picture/pre_verification', requestBody, auth, 25000);
    console.log('[TEMU运营助手] 预验证 API 响应:', verifyData);
    
    if (!verifyData.success) {
      console.warn('[TEMU运营助手] 预验证失败:', verifyData.error_msg);
      return { success: false, error: '预验证失败: ' + verifyData.error_msg, spuId };
    }
    
    // 步骤4：正式提交（upload_new）
    const data = await temuSellerPost('https://agentseller.temu.com/api/flash/real_picture/upload_new', {
      confirm_type: 4,
      ...requestBody
    }, auth, 30000);
    console.log('[TEMU运营助手] 上传实拍图 API 响应:', data);
    
    if (data.success) {
      return { success: true, spuId, imageUrl };
    } else {
      return { success: false, error: data.error_msg || '上传实拍图失败', errorCode: data.error_code, spuId };
    }
  } catch (error) {
    console.error('[TEMU运营助手] 上传实拍图失败:', error);
    return { success: false, error: error.message, spuId: params.spuId };
  }
}

async function uploadLivePhotosBatch(params = {}) {
  const auth = await getAuth();
  
  try {
    const { spuId, images } = params; // images: [{imageData: base64, filename: 'xxx.jpg'}, ...]
    
    if (!spuId) {
      return { success: false, error: '缺少 SPU ID' };
    }
    
    if (!images || images.length === 0) {
      return { success: false, error: '缺少图片数据' };
    }
    
    console.log('[TEMU运营助手] 批量上传实拍图:', { spuId, imageCount: images.length });
    
    // 步骤0：获取商品信息
    const productInfo = await getProductInfoForPhoto(spuId, auth, params.productInfo || params.product || null);
    if (!productInfo) {
      return { success: false, error: `获取商品信息失败：TEMU 实拍图列表未返回 SPU ${spuId} 的 goods_id`, spuId };
    }
    
    // 步骤1：上传所有图片到 store_image，收集所有 URL
    const imageUrls = [];
    for (let i = 0; i < images.length; i++) {
      const url = await uploadImageToTemuAndGetUrl(images[i].imageData, images[i].filename, auth);
      if (url) {
        imageUrls.push(url);
        console.log(`[TEMU运营助手] 图片 ${i + 1}/${images.length} 上传成功`);
      } else {
        console.error(`[TEMU运营助手] 图片 ${i + 1}/${images.length} 上传失败`);
      }
    }
    
    if (imageUrls.length === 0) {
      return { success: false, error: '所有图片上传失败', spuId };
    }
    
    console.log('[TEMU运营助手] 全部图片上传完成，共', imageUrls.length, '张');
    
    // 步骤2：构造请求体（所有图片放到 image_list 里）
    const imageList = imageUrls.map(url => ({ image_url: url }));
    
    const realPictureInfoList = [
      {
        position: 1,
        is_same_sku: productInfo.skuList.length > 0 ? 1 : 0,
        sku_photo_info_list: productInfo.skuList.map(sku => ({
          sku_id: sku.skuId,
          image_list: imageList
        }))
      },
      {
        position: 2,
        is_same_sku: productInfo.skuList.length > 0 ? 1 : 0,
        sku_photo_info_list: productInfo.skuList.map(sku => ({
          sku_id: sku.skuId,
          image_list: imageList
        }))
      }
    ];
    
    const requestBody = {
      spu_id: spuId,
      goods_id: productInfo.goodsId,
      real_picture_info_list: realPictureInfoList
    };
    
    console.log('[TEMU运营助手] 提交实拍图:', imageUrls.length, '张图 x position 1+2');
    
    // 步骤3：预验证
    const verifyData = await temuSellerPost('https://agentseller.temu.com/api/flash/real_picture/pre_verification', requestBody, auth, 25000);
    console.log('[TEMU运营助手] 预验证响应:', verifyData);
    
    if (!verifyData.success) {
      return { success: false, error: '预验证失败: ' + verifyData.error_msg, spuId };
    }
    
    // 步骤4：正式提交
    const data = await temuSellerPost('https://agentseller.temu.com/api/flash/real_picture/upload_new', {
      confirm_type: 4,
      ...requestBody
    }, auth, 30000);
    console.log('[TEMU运营助手] 上传实拍图响应:', data);
    
    if (data.success) {
      return { success: true, spuId, imageCount: imageUrls.length };
    } else {
      return { success: false, error: data.error_msg || '上传失败', errorCode: data.error_code, spuId };
    }
  } catch (error) {
    console.error('[TEMU运营助手] 批量上传实拍图失败:', error);
    return { success: false, error: error.message, spuId: params.spuId };
  }
}

async function applyLivePhotoUrlsToProduct(spuId, livePhotoFiles = [], productHint = null) {
  const auth = await getAuth();
  const imageUrls = (Array.isArray(livePhotoFiles) ? livePhotoFiles : [])
    .map(item => String(item?.imageUrl || item?.url || item?.fileUrl || '').trim())
    .filter(Boolean)
    .slice(0, 5);
  if (!spuId || !imageUrls.length) {
    return { success: true, skipped: true, imageCount: 0 };
  }

  const productInfo = await getProductInfoForPhoto(spuId, auth, productHint);
  if (!productInfo) {
    return { success: false, error: '获取商品信息失败（无法获取 goodsId/skuId）', spuId };
  }

  const realPictureInfoList = buildRealPictureInfoListForProduct(productInfo, imageUrls);
  const requestBody = {
    spu_id: spuId,
    goods_id: productInfo.goodsId,
    real_picture_info_list: realPictureInfoList
  };

  const verifyData = await temuSellerPost('https://agentseller.temu.com/api/flash/real_picture/pre_verification', requestBody, auth, 25000);
  if (!verifyData?.success) {
    return { success: false, error: '实拍图预验证失败: ' + getTemuApiMessage(verifyData, verifyData?.error_msg || '未知错误'), spuId };
  }

  const data = await temuSellerPost('https://agentseller.temu.com/api/flash/real_picture/upload_new', {
    confirm_type: 4,
    ...requestBody
  }, auth, 30000);
  return data?.success
    ? { success: true, spuId, imageCount: imageUrls.length }
    : { success: false, error: data?.error_msg || data?.message || '上传实拍图失败', errorCode: data?.error_code, spuId };
}

function normalizeTemuIdText(value) {
  const text = String(value ?? '').trim();
  return text && text !== 'null' && text !== 'undefined' ? text : '';
}

function collectTemuValuesByKeys(source, keys, maxDepth = 5) {
  const wanted = new Set(keys);
  const values = [];
  const seenObjects = new WeakSet();
  const walk = (node, depth = 0) => {
    if (!node || depth > maxDepth) return;
    if (Array.isArray(node)) {
      node.forEach(item => walk(item, depth + 1));
      return;
    }
    if (typeof node !== 'object') return;
    if (seenObjects.has(node)) return;
    seenObjects.add(node);
    for (const [key, value] of Object.entries(node)) {
      if (wanted.has(key)) {
        const text = normalizeTemuIdText(value);
        if (text) values.push(text);
      }
      if (value && typeof value === 'object') walk(value, depth + 1);
    }
  };
  walk(source);
  return values;
}

function readFirstTemuValueByKeys(source, keys, maxDepth = 5) {
  return collectTemuValuesByKeys(source, keys, maxDepth)[0] || '';
}

function getTemuKeysPreview(item = {}) {
  return item && typeof item === 'object' && !Array.isArray(item)
    ? Object.keys(item).slice(0, 40)
    : [];
}

function extractLivePhotoGoodsId(item = {}) {
  return readFirstTemuValueByKeys(item, ['goods_id', 'goodsId', 'good_id', 'goodId']);
}

function extractLivePhotoSpuId(item = {}) {
  return readFirstTemuValueByKeys(item, ['spu_id', 'spuId', 'product_id', 'productId']);
}

function extractLivePhotoSkuList(item = {}) {
  const skuIds = collectTemuValuesByKeys(item, [
    'sku_id',
    'skuId',
    'goods_sku_id',
    'goodsSkuId',
    'product_sku_id',
    'productSkuId',
    'productSkuIdStr',
    'skuIdStr'
  ]);
  const seen = new Set();
  return skuIds
    .map(normalizeTemuIdText)
    .filter(Boolean)
    .filter(skuId => {
      if (seen.has(skuId)) return false;
      seen.add(skuId);
      return true;
    })
    .map(skuId => ({ skuId }));
}

function normalizeLivePhotoLabelImageGroups(item = {}) {
  const groups = { 1: [], 2: [], 3: [], 5: [] };
  const rawList = Array.isArray(item?.label_image_list)
    ? item.label_image_list
    : (Array.isArray(item?.labelImageList) ? item.labelImageList : []);
  for (const image of rawList) {
    const position = Number(image?.position ?? image?.positionType ?? image?.position_type);
    const imageUrl = String(image?.image || image?.image_url || image?.imageUrl || image?.url || '').trim();
    if (!Number.isFinite(position) || !imageUrl) continue;
    if (!groups[position]) groups[position] = [];
    groups[position].push({ image_url: imageUrl });
  }
  return groups;
}

function normalizeLivePhotoProductInfo(item = {}, requestedSpuId = '', source = '') {
  if (!item || typeof item !== 'object') return null;
  const goodsId = extractLivePhotoGoodsId(item);
  const skuList = extractLivePhotoSkuList(item);
  const labelImageGroups = normalizeLivePhotoLabelImageGroups(item);
  return {
    source,
    spuId: extractLivePhotoSpuId(item) || normalizeTemuIdText(requestedSpuId),
    goodsId,
    skuList,
    labelImageGroups,
    rawItem: item,
    firstKeys: getTemuKeysPreview(item)
  };
}

function buildRealPictureInfoListForProduct(productInfo = {}, imageUrls = []) {
  const fallbackImageList = imageUrls.map(url => ({ image_url: url }));
  const labelGroups = productInfo.labelImageGroups || {};
  const getImagesForPosition = (position) => {
    const images = Array.isArray(labelGroups[position]) && labelGroups[position].length
      ? labelGroups[position]
      : fallbackImageList;
    return images.slice(0, 5).map(item => ({
      image_url: item.image_url || item.imageUrl || item.url
    })).filter(item => item.image_url);
  };
  const skuList = Array.isArray(productInfo.skuList) ? productInfo.skuList : [];
  const rawItem = productInfo.rawItem || {};
  const hasGuideRequirement = rawItem?.guide_file_info?.hit_guide_file || rawItem?.guideFileInfo?.hitGuideFile;
  const ruleList = Array.isArray(rawItem?.rule_check_result_list)
    ? rawItem.rule_check_result_list
    : (Array.isArray(rawItem?.ruleCheckResultList) ? rawItem.ruleCheckResultList : []);
  const hasEuDocRequirement = ruleList.some(rule => String(rule?.rule_name || rule?.ruleName || '').includes('EU DoC'));
  const buildPosition = (position) => {
    const imageList = getImagesForPosition(position);
    return {
      position,
      is_same_sku: skuList.length > 0 ? 1 : 0,
      sku_photo_info_list: skuList.map(sku => ({
        sku_id: sku.skuId,
        image_list: imageList
      }))
    };
  };
  const list = [buildPosition(1), buildPosition(2)];
  const hasGuideImages = hasGuideRequirement && Array.isArray(labelGroups[3]) && labelGroups[3].length > 0;
  const hasDocImages = hasEuDocRequirement && Array.isArray(labelGroups[5]) && labelGroups[5].length > 0;
  if (hasGuideImages) list.push(buildPosition(3));
  if (hasDocImages) {
    const docImages = getImagesForPosition(5).flatMap(item => ([
      { ...item, position_type: 2 },
      { ...item, position_type: 5 }
    ]));
    list.push({
      position: 5,
      is_same_sku: skuList.length > 0 ? 1 : 0,
      sku_photo_info_list: skuList.map(sku => ({
        sku_id: sku.skuId,
        image_list: docImages
      }))
    });
  }
  return list;
}

function buildLivePhotoProductInfoReturn(info = {}) {
  return {
    goodsId: info.goodsId,
    skuList: Array.isArray(info.skuList) ? info.skuList : [],
    labelImageGroups: info.labelImageGroups || {},
    source: info.source || '',
    rawItem: info.rawItem || null
  };
}

function findLivePhotoItemForSpu(list = [], spuId = '') {
  const ids = normalizeQualificationIdSet(spuId);
  return (Array.isArray(list) ? list : []).find(item => livePhotoItemMatchesIds(item, ids)) || null;
}

function buildLivePhotoLookupError(spuId, attempts = []) {
  const matchedMissingGoods = attempts.find(item => item.matched && !item.goodsId);
  if (matchedMissingGoods) {
    return `SPU ${spuId} 已在 TEMU 实拍图列表中找到，但返回数据没有 goods_id，无法按实拍图上传接口提交。字段：${(matchedMissingGoods.firstKeys || []).join(', ') || '未返回字段'}`;
  }
  const details = attempts
    .slice(-6)
    .map(item => `${item.source || 'unknown'}: ${item.success ? '成功' : '失败'} / ${item.count ?? 0}条${item.error ? ` / ${item.error}` : ''}`)
    .join('；');
  return `TEMU 实拍图列表未返回 SPU ${spuId} 的可上传商品信息，请确认该 SPU 在实拍图任务列表中并点击刷新后重试${details ? `。查询记录：${details}` : ''}`;
}

async function fetchPhotoProductInfoFromGoodsApi(spuId, auth, attempts) {
  const numericSpuId = Number(spuId);
  const spuValue = Number.isFinite(numericSpuId) ? numericSpuId : spuId;
  const requests = [
    {
      source: 'goods_by_spu_ids',
      url: 'https://agentseller.temu.com/professional/goods/info/query/goods/by/product/spu/ids',
      body: { spuIds: [spuValue] }
    },
    {
      source: 'goods_find_all_pageable',
      url: 'https://agentseller.temu.com/professional/goods/info/find/all/pageable/spu/by/multiple/params',
      body: {
        currentPage: 1,
        pageSize: 20,
        filter: {
          mallId: auth?.mallId || '',
          goodSpuList: [spuValue]
        }
      }
    }
  ];

  for (const request of requests) {
    try {
      const data = await temuSellerPost(request.url, request.body, auth, 25000);
      const list = extractTemuListFromPayload(data);
      const item = findLivePhotoItemForSpu(list, spuId) || (list.length === 1 ? list[0] : null);
      const info = item ? normalizeLivePhotoProductInfo(item, spuId, request.source) : null;
      attempts.push({
        source: request.source,
        success: isTemuApiSuccess(data) || data?.code === 0 || data?.success === true,
        count: list.length,
        matched: !!item,
        goodsId: info?.goodsId || '',
        skuCount: info?.skuList?.length || 0,
        firstKeys: getTemuKeysPreview(item || list[0] || {})
      });
      if (info?.goodsId) return info;
    } catch (error) {
      attempts.push({
        source: request.source,
        success: false,
        count: 0,
        error: error?.message || String(error)
      });
    }
  }
  return null;
}

async function findLivePhotoProductInfoByPaging(spuId, auth, attempts, options = {}) {
  const normalizedSpuId = normalizeTemuIdText(spuId);
  if (!normalizedSpuId) return null;
  const pageSize = Math.max(50, Number(options.pageSize || 100) || 100);
  let total = 0;

  for (let page = 1; ; page += 1) {
    const resp = await requestLivePhotoList({ page, page_size: pageSize }, auth);
    const list = Array.isArray(resp?.list) ? resp.list : [];
    total = total || Number(resp?.total || 0) || 0;
    const item = findLivePhotoItemForSpu(list, normalizedSpuId);
    const info = item ? normalizeLivePhotoProductInfo(item, normalizedSpuId, 'real_picture_list_paged_scan') : null;
    attempts.push({
      source: `real_picture_list_paged_scan page=${page}`,
      success: !!resp?.success,
      count: list.length,
      total: total || '',
      matched: !!item,
      goodsId: info?.goodsId || '',
      skuCount: info?.skuList?.length || 0,
      firstKeys: getTemuKeysPreview(item || list[0] || {}),
      error: resp?.error || ''
    });
    if (info?.goodsId) return info;
    if (!resp?.success) break;
    const expectedPages = total ? Math.ceil(total / pageSize) : 0;
    if (expectedPages && page >= expectedPages) break;
    if (!expectedPages && list.length < pageSize) break;
    if (list.length === 0) break;
  }

  return null;
}

async function getProductInfoForPhoto(spuId, auth, productHint = null) {
  const normalizedSpuId = normalizeTemuIdText(spuId);
  const attempts = [];
  let bestInfo = null;

  const rememberInfo = (info) => {
    if (!info?.goodsId) return false;
    if (!bestInfo || ((info.skuList?.length || 0) > (bestInfo.skuList?.length || 0))) {
      bestInfo = info;
    }
    return (info.skuList?.length || 0) > 0;
  };

  try {
    if (productHint && typeof productHint === 'object') {
      const hintSource = productHint.__livePhotoLookupSource || productHint._livePhotoLookupSource || 'selected_real_picture_row';
      const hintInfo = normalizeLivePhotoProductInfo(productHint, normalizedSpuId, hintSource);
      attempts.push({
        source: hintInfo.source,
        success: true,
        count: 1,
        matched: livePhotoItemMatchesIds(productHint, normalizeQualificationIdSet(normalizedSpuId)),
        goodsId: hintInfo.goodsId,
        skuCount: hintInfo.skuList.length,
        firstKeys: hintInfo.firstKeys
      });
      if (rememberInfo(hintInfo)) {
        console.log('[TEMU运营助手] 实拍图商品信息来自商品提示:', {
          source: hintInfo.source,
          spuId: normalizedSpuId,
          goodsId: hintInfo.goodsId,
          skuCount: hintInfo.skuList.length
        });
        return buildLivePhotoProductInfoReturn(hintInfo);
      }
    }

    const capturedSnapshot = await getCapturedLivePhotoSnapshot();
    const capturedItems = capturedSnapshot.items;
    if (capturedItems.length) {
      const capturedItem = findLivePhotoItemForSpu(capturedItems, normalizedSpuId);
      const capturedInfo = capturedItem ? normalizeLivePhotoProductInfo(capturedItem, normalizedSpuId, 'captured_real_picture_list') : null;
      attempts.push({
        source: 'captured_real_picture_list',
        success: true,
        count: capturedItems.length,
        matched: !!capturedItem,
        goodsId: capturedInfo?.goodsId || '',
        skuCount: capturedInfo?.skuList?.length || 0,
        firstKeys: getTemuKeysPreview(capturedItem || capturedItems[0] || {})
      });
      if (rememberInfo(capturedInfo)) {
        console.log('[TEMU运营助手] 实拍图商品信息来自页面缓存:', {
          spuId: normalizedSpuId,
          goodsId: capturedInfo.goodsId,
          skuCount: capturedInfo.skuList.length
        });
        return buildLivePhotoProductInfoReturn(capturedInfo);
      }
    }

    const capturedRequestBodies = buildCapturedLivePhotoRequestBodies(capturedSnapshot);
    for (const requestBody of capturedRequestBodies) {
      const resp = await getLivePhotoList({ requestBody });
      const list = Array.isArray(resp?.list) ? resp.list : [];
      const item = findLivePhotoItemForSpu(list, normalizedSpuId);
      const info = item ? normalizeLivePhotoProductInfo(item, normalizedSpuId, 'captured_real_picture_request') : null;
      attempts.push({
        source: `captured_real_picture_request ${JSON.stringify(resp?.requestBody || requestBody)}`,
        success: !!resp?.success,
        count: list.length,
        matched: !!item,
        goodsId: info?.goodsId || '',
        skuCount: info?.skuList?.length || 0,
        firstKeys: getTemuKeysPreview(item || list[0] || {}),
        error: resp?.error || ''
      });
      if (rememberInfo(info)) {
        console.log('[TEMU运营助手] 实拍图商品信息来自页面真实请求体:', {
          spuId: normalizedSpuId,
          goodsId: info.goodsId,
          skuCount: info.skuList.length
        });
        return buildLivePhotoProductInfoReturn(info);
      }
    }

    const realPictureRequests = [
      { pageNum: 1, pageSize: 100, spuId: normalizedSpuId, idField: 'spu_id_list' },
      { pageNum: 1, pageSize: 100, spuId: normalizedSpuId },
      { pageNum: 1, pageSize: 100, productId: normalizedSpuId, idField: 'product_id' },
      { pageNum: 1, pageSize: 100, goodsId: normalizedSpuId, idField: 'goods_id' }
    ];
    for (const requestParams of realPictureRequests) {
      const resp = await getLivePhotoList(requestParams);
      const list = Array.isArray(resp?.list) ? resp.list : [];
      const item = findLivePhotoItemForSpu(list, normalizedSpuId);
      const info = item ? normalizeLivePhotoProductInfo(item, normalizedSpuId, 'real_picture_list_api') : null;
      attempts.push({
        source: `real_picture_list_api ${JSON.stringify(resp?.requestBody || requestParams)}`,
        success: !!resp?.success,
        count: list.length,
        matched: !!item,
        goodsId: info?.goodsId || '',
        skuCount: info?.skuList?.length || 0,
        firstKeys: getTemuKeysPreview(item || list[0] || {}),
        error: resp?.error || ''
      });
      if (rememberInfo(info)) {
        console.log('[TEMU运营助手] 实拍图商品信息来自 real_picture/list:', {
          spuId: normalizedSpuId,
          goodsId: info.goodsId,
          skuCount: info.skuList.length
        });
        return buildLivePhotoProductInfoReturn(info);
      }
    }

    const pagedInfo = await findLivePhotoProductInfoByPaging(normalizedSpuId, auth, attempts);
    if (pagedInfo?.goodsId) {
      console.log('[TEMU运营助手] 实拍图商品信息来自 real_picture/list 跨页扫描:', {
        source: pagedInfo.source,
        spuId: normalizedSpuId,
        goodsId: pagedInfo.goodsId,
        skuCount: pagedInfo.skuList.length
      });
      return buildLivePhotoProductInfoReturn(pagedInfo);
    }

    const goodsInfo = await fetchPhotoProductInfoFromGoodsApi(normalizedSpuId, auth, attempts);
    if (goodsInfo?.goodsId) {
      console.log('[TEMU运营助手] 实拍图商品信息来自商品信息接口:', {
        source: goodsInfo.source,
        spuId: normalizedSpuId,
        goodsId: goodsInfo.goodsId,
        skuCount: goodsInfo.skuList.length
      });
      return buildLivePhotoProductInfoReturn(goodsInfo);
    }

    if (bestInfo?.goodsId) {
      console.warn('[TEMU运营助手] 实拍图商品信息缺少 SKU，继续使用 TEMU 返回的 goods_id 交给预验证判断:', {
        source: bestInfo.source,
        spuId: normalizedSpuId,
        goodsId: bestInfo.goodsId,
        firstKeys: bestInfo.firstKeys
      });
      return buildLivePhotoProductInfoReturn({ ...bestInfo, skuList: [] });
    }

    const message = buildLivePhotoLookupError(normalizedSpuId, attempts);
    console.error('[TEMU运营助手] 获取实拍图商品信息失败:', message, attempts);
    throw new Error(message);
  } catch (error) {
    console.error('[TEMU运营助手] 获取商品信息失败:', error);
    throw error;
  }
}

async function getUploadSign(auth) {
  const data = await temuSellerPost('https://agentseller.temu.com/ms/bg-flux-ms/compliance_property/signature', { tag: 'flash-tag' }, auth, 25000);
  
  if (data.success && data.result) {
    console.log('[TEMU运营助手] 获取 upload_sign 成功');
    return data.result; // 返回签名字符串
  } else {
    console.error('[TEMU运营助手] 获取 upload_sign 失败:', data);
    return null;
  }
}

async function storeImageAndGetUrl(imageData, filename, auth) {
  // 获取上传签名
  const uploadSign = await getUploadSign(auth);
  if (!uploadSign) {
    throw new Error('获取 upload_sign 失败');
  }
  
  // 将 base64 转换为 Blob
  const base64Data = imageData.split(',')[1] || imageData;
  const byteCharacters = atob(base64Data);
  const byteNumbers = new Array(byteCharacters.length);
  for (let i = 0; i < byteCharacters.length; i++) {
    byteNumbers[i] = byteCharacters.charCodeAt(i);
  }
  const byteArray = new Uint8Array(byteNumbers);
  const blob = new Blob([byteArray], { type: 'image/jpeg' });
  
  // 构建 multipart/form-data（不能用 FormData，因为需要精确控制字段顺序和 boundary）
  // TEMU 的 store_image 需要三个字段：image, upload_sign, url_width_height
  const boundary = '----OpenClawFormBoundary' + Date.now();
  const CRLF = '\r\n';
  
  let body = '';
  
  // 字段1: url_width_height
  body += '--' + boundary + CRLF;
  body += 'Content-Disposition: form-data; name="url_width_height"' + CRLF;
  body += CRLF;
  body += 'true' + CRLF;
  
  // 字段2: image（图片文件）
  body += '--' + boundary + CRLF;
  body += 'Content-Disposition: form-data; name="image"; filename="' + (filename || 'image.jpg') + '"' + CRLF;
  body += 'Content-Type: image/jpeg' + CRLF;
  body += CRLF;
  
  // 将文本部分和二进制部分合并为 ArrayBuffer
  const textEncoder = new TextEncoder();
  const textPart = textEncoder.encode(body);
  const binaryPart = byteArray;
  const endPart = textEncoder.encode(CRLF + '--' + boundary + '--' + CRLF);
  
  const totalLength = textPart.length + binaryPart.length + endPart.length;
  const combined = new Uint8Array(totalLength);
  combined.set(textPart, 0);
  combined.set(binaryPart, textPart.length);
  combined.set(endPart, textPart.length + binaryPart.length);
  
  // 字段3: upload_sign（追加到末尾，在 boundary 之前）
  // 需要重新构建，因为签名在 image 之后
  const signField = '--' + boundary + CRLF +
    'Content-Disposition: form-data; name="upload_sign"' + CRLF +
    CRLF +
    uploadSign + CRLF;
  const signBytes = textEncoder.encode(signField);
  const finalEnd = textEncoder.encode('--' + boundary + '--' + CRLF);
  
  // 重新构建：url_width_height + image + upload_sign + end
  const beforeSign = textEncoder.encode(
    '--' + boundary + CRLF +
    'Content-Disposition: form-data; name="url_width_height"' + CRLF +
    CRLF +
    'true' + CRLF +
    '--' + boundary + CRLF +
    'Content-Disposition: form-data; name="image"; filename="' + (filename || 'image.jpg') + '"' + CRLF +
    'Content-Type: image/jpeg' + CRLF +
    CRLF
  );
  
  const finalBody = new Uint8Array(beforeSign.length + binaryPart.length + CRLF.length + signBytes.length + finalEnd.length);
  let offset = 0;
  finalBody.set(beforeSign, offset); offset += beforeSign.length;
  finalBody.set(binaryPart, offset); offset += binaryPart.length;
  finalBody.set(textEncoder.encode(CRLF), offset); offset += CRLF.length;
  finalBody.set(signBytes, offset); offset += signBytes.length;
  finalBody.set(finalEnd, offset);
  
  const response = await fetch(
    'https://agentseller.temu.com/api/galerie/v3/store_image?sdk_version=js-0.0.40&tag_name=flash-tag',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'multipart/form-data; boundary=' + boundary,
        'mallid': auth?.mallId || '',
        'anti-content': auth?.antiContent || ''
      },
      body: finalBody
    }
  );
  
  const data = await response.json();
  
  // store_image 响应直接返回数据对象（无 success/result 包装）
  const imageUrl = data.url || data.result?.url || data.result?.image_url || (typeof data.result === 'string' ? data.result : null);
  
  if (imageUrl) {
    console.log('[TEMU运营助手] 图片上传成功, URL:', imageUrl);
    return imageUrl;
  } else {
    console.error('[TEMU运营助手] 图片上传失败，未找到 URL:', data);
    return null;
  }
}

const TEMU_PRODUCT_IMAGE_UPLOAD_TAG = 'product-material-tag';

function getTemuProductImageMimeType(imageData = '', filename = '') {
  const dataUrlMatch = String(imageData || '').match(/^data:([^;,]+)[;,]/i);
  if (dataUrlMatch?.[1]) return dataUrlMatch[1];
  const lowerName = String(filename || '').toLowerCase();
  if (lowerName.endsWith('.png')) return 'image/png';
  if (lowerName.endsWith('.webp')) return 'image/webp';
  if (lowerName.endsWith('.gif')) return 'image/gif';
  return 'image/jpeg';
}

async function uploadProductImageToTemuAndGetUrl(imageData, filename, auth, tag = TEMU_PRODUCT_IMAGE_UPLOAD_TAG) {
  const cleanImageData = String(imageData || '');
  if (!cleanImageData) throw new Error('缺少待上传图片数据');

  const tab = await findTemuSellerTab('https://agentseller.temu.com/goods/edit');
  if (!tab?.id) {
    throw new Error('请先打开并登录 TEMU 卖家后台页面后再上传商品图片');
  }

  const [execResult] = await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    world: 'MAIN',
    args: [{
      imageData: cleanImageData,
      filename: filename || 'image.jpg',
      tag,
      mallId: auth?.mallId || '',
      timeoutMs: 180000
    }],
    func: async (request) => {
      const readFirst = (...values) => values.find(value => value !== undefined && value !== null && value !== '') || '';
      const readMallId = () => {
        try {
          const parsed = new URL(location.href);
          const fromUrl = parsed.searchParams.get('mall_id') || parsed.searchParams.get('mallId') || parsed.searchParams.get('mallid');
          if (fromUrl) return String(fromUrl);
        } catch (_) {}
        return String(readFirst(
          request.mallId,
          localStorage.getItem('agentseller-mall-info-id'),
          localStorage.getItem('seller-mall-info-id'),
          sessionStorage.getItem('agentseller-mall-info-id'),
          sessionStorage.getItem('seller-mall-info-id')
        ) || '');
      };
      const getAntiContent = () => {
        try {
          if (typeof window.secretKeyAnti === 'function') return window.secretKeyAnti() || '';
        } catch (_) {}
        return String(readFirst(
          localStorage.getItem('anti-content'),
          localStorage.getItem('Anti-Content'),
          sessionStorage.getItem('anti-content'),
          sessionStorage.getItem('Anti-Content')
        ) || '');
      };
      const parseJsonResponse = async (response) => {
        const rawText = await response.text();
        try {
          return rawText ? JSON.parse(rawText) : null;
        } catch (_) {
          return rawText;
        }
      };
      const getApiMessage = (data, fallback) => {
        if (!data || typeof data !== 'object') return fallback;
        return data.errorMsg || data.error_msg || data.message || data.msg || data.error || fallback;
      };
      const getMimeType = (dataUrl, name) => {
        const match = String(dataUrl || '').match(/^data:([^;,]+)[;,]/i);
        if (match?.[1]) return match[1];
        const lowerName = String(name || '').toLowerCase();
        if (lowerName.endsWith('.png')) return 'image/png';
        if (lowerName.endsWith('.webp')) return 'image/webp';
        if (lowerName.endsWith('.gif')) return 'image/gif';
        return 'image/jpeg';
      };
      const base64ToBlob = (value, mimeType) => {
        const base64 = String(value || '').split(',')[1] || String(value || '');
        const binary = atob(base64);
        const bytes = new Uint8Array(binary.length);
        for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
        return new Blob([bytes], { type: mimeType });
      };
      const requestWithXhrFallback = async (requestUrl, options = {}) => {
        try {
          return await fetch(requestUrl, options);
        } catch (fetchError) {
          if (typeof XMLHttpRequest !== 'function') throw fetchError;
          return await new Promise((resolve, reject) => {
            try {
              const xhr = new XMLHttpRequest();
              xhr.open(options.method || 'GET', requestUrl, true);
              xhr.withCredentials = options.credentials === 'include';
              Object.entries(options.headers || {}).forEach(([key, value]) => {
                if (value !== undefined && value !== null && value !== '') {
                  xhr.setRequestHeader(key, String(value));
                }
              });
              xhr.onload = () => resolve({
                ok: xhr.status >= 200 && xhr.status < 300,
                status: xhr.status,
                text: () => Promise.resolve(xhr.responseText || '')
              });
              xhr.onerror = () => reject(new Error('XMLHttpRequest 请求失败'));
              xhr.ontimeout = () => reject(new Error('XMLHttpRequest 请求超时'));
              xhr.timeout = Number(request.timeoutMs || 180000);
              xhr.send(options.body || null);
            } catch (xhrError) {
              reject(xhrError);
            }
          });
        }
      };

      const controller = new AbortController();
      const timer = setTimeout(() => controller.abort(new Error('timeout')), Number(request.timeoutMs || 180000));
      try {
        const tagName = String(request.tag || 'product-material-tag');
        const origin = /^https:\/\/agentseller(?:-[a-z]+)?\.temu\.com$/i.test(location.origin)
          ? location.origin
          : 'https://agentseller.temu.com';
        const mallId = readMallId();
        const antiContent = getAntiContent();
        const jsonHeaders = { 'Content-Type': 'application/json' };
        const uploadHeaders = {};
        if (mallId) {
          jsonHeaders.mallid = mallId;
          uploadHeaders.mallid = mallId;
        }
        if (antiContent) {
          jsonHeaders['anti-content'] = antiContent;
          uploadHeaders['anti-content'] = antiContent;
        }

        const signUrl = `${origin}/general_auth/get_signature?tag_name=${encodeURIComponent(tagName)}&scene_id=agent-seller`;
        const signResponse = await requestWithXhrFallback(signUrl, {
          method: 'POST',
          headers: jsonHeaders,
          body: JSON.stringify({ bucket_tag: tagName }),
          credentials: 'include',
          signal: controller.signal
        });
        const signData = await parseJsonResponse(signResponse);
        if (!signResponse.ok) {
          throw new Error(getApiMessage(signData, `TEMU 商品图片签名失败 HTTP ${signResponse.status}`));
        }
        const uploadSign = signData?.result?.signature || signData?.signature || signData?.result || signData?.data?.signature || '';
        if (!uploadSign || typeof uploadSign !== 'string') {
          throw new Error('TEMU 商品图片签名未返回 signature');
        }

        const mimeType = getMimeType(request.imageData, request.filename);
        const blob = base64ToBlob(request.imageData, mimeType);
        const formData = new FormData();
        formData.append('url_width_height', 'true');
        formData.append('image', blob, request.filename || 'image.jpg');
        formData.append('upload_sign', uploadSign);

        const uploadUrl = `${origin}/api/galerie/v3/store_image?tag_name=${encodeURIComponent(tagName)}`;
        const uploadResponse = await requestWithXhrFallback(uploadUrl, {
          method: 'POST',
          headers: uploadHeaders,
          body: formData,
          credentials: 'include',
          signal: controller.signal
        });
        const uploadData = await parseJsonResponse(uploadResponse);
        if (!uploadResponse.ok) {
          throw new Error(getApiMessage(uploadData, `TEMU 商品图片上传失败 HTTP ${uploadResponse.status}`));
        }
        const imageUrl = uploadData?.url
          || uploadData?.result?.url
          || uploadData?.result?.image_url
          || uploadData?.imageInfo?.url
          || uploadData?.processedUrls?.[0]?.url
          || (typeof uploadData?.result === 'string' ? uploadData.result : '');
        if (!imageUrl) {
          throw new Error('TEMU 商品图片上传成功但未返回 URL');
        }
        return { success: true, url: imageUrl, data: uploadData, origin, tag: tagName };
      } catch (error) {
        return { success: false, error: error?.message || String(error) };
      } finally {
        clearTimeout(timer);
      }
    }
  });

  const result = execResult?.result;
  if (!result?.success || !result.url) {
    throw new Error(result?.error || 'TEMU 商品图片上传失败');
  }
  console.log('[TEMU运营助手] 商品图片上传成功:', {
    url: result.url,
    tag: result.tag,
    origin: result.origin,
    mimeType: getTemuProductImageMimeType(imageData, filename)
  });
  return result.url;
}

async function uploadImageToTemuAndGetUrl(imageData, filename, auth) {
  try {
    console.log('[TEMU运营助手] 开始上传图片到 TEMU...');
    const imageUrl = await storeImageAndGetUrl(imageData, filename, auth);
    
    if (imageUrl) {
      console.log('[TEMU运营助手] 图片上传成功，URL:', imageUrl);
      return imageUrl;
    } else {
      console.error('[TEMU运营助手] 图片上传失败');
      return null;
    }
  } catch (error) {
    console.error('[TEMU运营助手] 图片上传失败:', error);
    return null;
  }
}

async function getPricingList(params = {}) {
  const auth = await getAuth();
  const pageNum = params.pageNum || 1;
  const pageSize = params.pageSize || 50;
  const priceReviewStatusList = params.priceReviewStatusList || [0, 1]; // 0=待卖家确认, 1=价格申报中
  const keyword = params.keyword || '';
  const skcIdList = params.skcIdList || [];

  const requestBody = {
    pageSize: pageSize,
    pageNum: pageNum,
    priceReviewStatusList: priceReviewStatusList,
    productNameKeyword: keyword,
    productSkcIdList: skcIdList,
    secondarySelectStatusList: [7],
    supplierTodoTypeList: []
  };

  console.log('[TEMU运营助手] 核价列表请求:', JSON.stringify(requestBody));

  const data = await temuSellerPost('https://agentseller.temu.com/api/kiana/mms/robin/searchForChainSupplier', requestBody, auth, 30000);
  console.log('[TEMU运营助手] 核价列表响应:', JSON.stringify(data).substring(0, 500));

  if (data.success || data.code === 0) {
    const result = data.result || data.data || {};
    let list = result.dataList || result.list || result.records || result.items || [];

    // 打印第一条数据的所有字段名，方便调试
    if (list.length > 0) {
      console.log('[TEMU运营助手] 核价列表第一条字段:', Object.keys(list[0]));
      const firstItem = list[0];
      // 尝试找到 SKC 列表
      const skcKey = Object.keys(firstItem).find(k =>
        Array.isArray(firstItem[k]) && firstItem[k].length > 0 &&
        firstItem[k][0] && typeof firstItem[k][0] === 'object' &&
        (firstItem[k][0].skuId || firstItem[k][0].goodsSkuId || firstItem[k][0].goodsSkcId)
      );
      if (skcKey) {
        console.log('[TEMU运营助手] SKC列表字段名:', skcKey);
        console.log('[TEMU运营助手] 第一个SKC字段:', Object.keys(firstItem[skcKey][0]));
      }
      // 尝试找到 selectId
      console.log('[TEMU运营助手] selectId:', firstItem.selectId, '| priceOrderId:', firstItem.priceOrderId, '| id:', firstItem.id);
    }

    // 确保每个 item 有正确的 selectId（兼容不同字段名）
    list = list.map(item => {
      item.selectId = item.selectId || item.priceOrderId || item.id || item.orderId || '';
      item.selectStatus = item.selectStatus || item.priceReviewStatus || item.status || 0;
      // 确保 skcList 存在
      if (!item.skcList) {
        // 尝试从其他字段找 SKC 列表
        const skcKey = Object.keys(item).find(k =>
          Array.isArray(item[k]) && item[k].length > 0 &&
          item[k][0] && typeof item[k][0] === 'object' &&
          (item[k][0].skuId || item[k][0].goodsSkuId || item[k][0].goodsSkcId)
        );
        if (skcKey) item.skcList = item[skcKey];
      }
      return item;
    });

    list = await mergeCapturedPricingReferencePrices(list);

    return {
      success: true,
      list,
      total: result.total || list.length || 0,
      pageNum: pageNum,
      pageSize: pageSize
    };
  } else {
    return {
      success: false,
      error: data.errorMsg || data.error_msg || '获取核价列表失败'
    };
  }
}

async function getMinPrice(skuIds) {
  const auth = await getAuth();

  const requestBody = {
    mallId: auth?.mallId || '',
    skuIds: skuIds
  };

  const data = await temuSellerPost('https://agentseller.temu.com/professional/goods/min/query/page/min/price', requestBody, auth, 25000);
  console.log('[TEMU运营助手] 最低价查询响应:', JSON.stringify(data).substring(0, 300));

  if (data.code === 0 && data.detail) {
    return {
      success: true,
      minList: data.detail.minList || []
    };
  } else {
    return {
      success: false,
      error: '查询最低价失败'
    };
  }
}

async function batchSaveMinPrice(items) {
  const auth = await getAuth();

  const requestBody = {
    mallId: auth?.mallId || '',
    updateGoodsMinPriceModels: items
  };

  const data = await temuSellerPost('https://agentseller.temu.com/professional/goods/min/batch/save/or/update/min/price', requestBody, auth, 30000);
  console.log('[TEMU运营助手] 批量保存阈值响应:', JSON.stringify(data).substring(0, 300));

  return {
    success: data.code === 0,
    error: data.msg || '保存阈值失败'
  };
}

const TEMU_PRICING_CAPTURE_CACHE_KEY = 'temuCapturedPricingReferencePrices';

function normalizePricingCaptureId(value) {
  const text = String(value ?? '').trim();
  if (!text) return '';
  const match = text.match(/\d{5,}/);
  return match ? match[0] : text;
}

function normalizePricingCaptureMoney(value) {
  if (value === undefined || value === null || value === '') return '';
  const text = String(value).replace(/[¥￥,\s]/g, '').trim();
  if (!text || /^[-—]+$/.test(text)) return '';
  const match = text.match(/\d+(?:\.\d+)?/);
  if (!match) return '';
  const num = Number(match[0]);
  return Number.isFinite(num) && num > 0 ? num.toFixed(2) : '';
}

function getPricingCaptureProductId(item = {}) {
  return normalizePricingCaptureId(item.productId || item.goodsId || item.spuId || item.productSpuId || item.id || '');
}

function getPricingCaptureSkuId(sku = {}) {
  return normalizePricingCaptureId(sku.productSkuId || sku.skuId || sku.goodsSkuId || sku.skuIdStr || '');
}

function getPricingCaptureSkcId(skc = {}) {
  return normalizePricingCaptureId(skc.skcId || skc.goodsSkcId || skc.productSkcId || skc.skcIdStr || skc.id || '');
}

function getPricingCaptureCandidateIds(...sources) {
  const ids = new Set();
  const visit = (value) => {
    if (value === undefined || value === null) return;
    if (Array.isArray(value)) {
      value.forEach(visit);
      return;
    }
    if (typeof value === 'object') {
      Object.values(value).forEach(visit);
      return;
    }
    const matches = String(value).match(/\b[0-9]{5,}\b/g) || [];
    matches.forEach(match => {
      const normalized = normalizePricingCaptureId(match);
      if (normalized) ids.add(normalized);
    });
  };
  sources.forEach(visit);
  return Array.from(ids);
}

async function readCapturedPricingReferenceRows() {
  try {
    const stored = await chrome.storage.local.get(TEMU_PRICING_CAPTURE_CACHE_KEY);
    const cache = stored?.[TEMU_PRICING_CAPTURE_CACHE_KEY];
    return Array.isArray(cache?.rows) ? cache.rows : [];
  } catch (error) {
    console.warn('[TEMU运营助手] 读取核价参考申报价缓存失败:', error?.message || error);
    return [];
  }
}

function isTemuSellerTabUrl(url = '') {
  return /^https:\/\/(agentseller|agentseller-us|agentseller-eu|seller|seller-eu)\.temu\.com\//i.test(String(url || ''))
    || /^https:\/\/seller\.kuajingmaihuo\.com\//i.test(String(url || ''));
}

function sendMessageToTab(tabId, message, timeoutMs = 5000) {
  return new Promise((resolve) => {
    let settled = false;
    const timer = setTimeout(() => {
      if (settled) return;
      settled = true;
      resolve({ success: false, error: 'content script 响应超时' });
    }, timeoutMs);
    try {
      chrome.tabs.sendMessage(tabId, message, (response) => {
        if (settled) return;
        settled = true;
        clearTimeout(timer);
        if (chrome.runtime.lastError) {
          resolve({ success: false, error: chrome.runtime.lastError.message });
          return;
        }
        resolve(response || { success: false, error: '未收到页面响应' });
      });
    } catch (error) {
      if (settled) return;
      settled = true;
      clearTimeout(timer);
      resolve({ success: false, error: error?.message || String(error) });
    }
  });
}

async function collectPricingDiagnostics() {
  const tabs = await chrome.tabs.query({});
  const sellerTabs = (tabs || []).filter(tab => isTemuSellerTabUrl(tab.url));
  const snapshots = [];
  for (const tab of sellerTabs.slice(0, 20)) {
    const result = await sendMessageToTab(tab.id, { action: 'collectPricingDomSnapshot' }, 6000);
    snapshots.push({
      tabId: tab.id,
      title: tab.title || '',
      url: tab.url || '',
      ...result
    });
  }
  const capturedRows = await readCapturedPricingReferenceRows();
  return {
    success: true,
    sellerTabCount: sellerTabs.length,
    snapshots,
    capturedCount: capturedRows.length,
    capturedRows: capturedRows.slice(0, 200)
  };
}

function findCapturedPricingReference(rows = [], { priceOrderId = '', skcId = '', skuId = '', skuCount = 0 } = {}) {
  const order = normalizePricingCaptureId(priceOrderId);
  const skc = normalizePricingCaptureId(skcId);
  const sku = normalizePricingCaptureId(skuId);
  const normalizedRows = rows
    .map(row => ({
      ...row,
      priceOrderId: normalizePricingCaptureId(row.priceOrderId),
      skcId: normalizePricingCaptureId(row.skcId),
      skuId: normalizePricingCaptureId(row.skuId),
      candidateIds: Array.isArray(row.candidateIds)
        ? row.candidateIds.map(normalizePricingCaptureId).filter(Boolean)
        : [],
      price: normalizePricingCaptureMoney(row.price),
      capturedAt: Number(row.capturedAt || 0)
    }))
    .filter(row => row.price)
    .sort((a, b) => Number(b.capturedAt || 0) - Number(a.capturedAt || 0));

  const isConflict = (row) => Boolean(
    (order && row.priceOrderId && row.priceOrderId !== order) ||
    (skc && row.skcId && row.skcId !== skc) ||
    (sku && row.skuId && row.skuId !== sku)
  );

  const matchers = [
    row => order && sku && row.priceOrderId === order && row.skuId === sku,
    row => sku && row.skuId === sku && !isConflict(row),
    row => skuCount === 1 && order && row.priceOrderId === order && !row.skuId && !isConflict(row),
    row => skuCount === 1 && skc && row.skcId === skc && !row.skuId && !isConflict(row),
    row => skuCount === 1 && sku && !row.skuId && row.candidateIds.includes(sku) && !isConflict(row),
    row => skuCount === 1 && skc && !row.skuId && row.candidateIds.includes(skc) && !isConflict(row),
    row => skuCount === 1 && order && !row.skuId && row.candidateIds.includes(order) && !isConflict(row)
  ];
  for (const matcher of matchers) {
    const found = normalizedRows.find(matcher);
    if (found) return found;
  }
  return null;
}

async function mergeCapturedPricingReferencePrices(list = []) {
  const capturedRows = await readCapturedPricingReferenceRows();
  if (!capturedRows.length) return list;
  let mergedCount = 0;
  const mergedList = (Array.isArray(list) ? list : []).map(item => {
    const skcList = Array.isArray(item.skcList) ? item.skcList : [];
    const productId = getPricingCaptureProductId(item);
    return {
      ...item,
      skcList: skcList.map(skc => {
        const skcId = getPricingCaptureSkcId(skc);
        const skcCandidateIds = getPricingCaptureCandidateIds(productId, skcId, skc);
        const reviewList = Array.isArray(skc.supplierPriceReviewInfoList) ? skc.supplierPriceReviewInfoList : [];
        return {
          ...skc,
          supplierPriceReviewInfoList: reviewList.map(reviewInfo => {
            const originalPriceOrderId = normalizePricingCaptureId(reviewInfo.priceOrderId || '');
            const productSkuList = Array.isArray(reviewInfo.productSkuList) ? reviewInfo.productSkuList : [];
            const skuCount = productSkuList.length;
            let mergedReviewPriceOrderId = originalPriceOrderId;
            const mergedProductSkuList = productSkuList.map(sku => {
                const skuId = getPricingCaptureSkuId(sku);
                const skuCandidateIds = getPricingCaptureCandidateIds(originalPriceOrderId, skcCandidateIds, skuId, sku);
                const scopedRows = capturedRows.filter(row => {
                  const rowOrderId = normalizePricingCaptureId(row.priceOrderId);
                  const rowSkcId = normalizePricingCaptureId(row.skcId);
                  const rowSkuId = normalizePricingCaptureId(row.skuId);
                  if (rowSkuId && skuId && rowSkuId === skuId) return true;
                  if (rowOrderId && originalPriceOrderId && rowOrderId === originalPriceOrderId) return true;
                  if (rowSkcId && skcId && rowSkcId === skcId) return true;
                  const rowCandidates = Array.isArray(row.candidateIds) ? row.candidateIds.map(normalizePricingCaptureId).filter(Boolean) : [];
                  if (!rowCandidates.length) return true;
                  return skuCandidateIds.some(id => rowCandidates.includes(id));
                });
                const captured = findCapturedPricingReference(scopedRows, { priceOrderId: originalPriceOrderId, skcId, skuId, skuCount });
                if (!captured?.price) return sku;
                if (!mergedReviewPriceOrderId && captured.priceOrderId) {
                  mergedReviewPriceOrderId = normalizePricingCaptureId(captured.priceOrderId);
                }
                mergedCount++;
                return {
                  ...sku,
                  xiaoqingwaCapturedReferencePrice: captured.price,
                  xiaoqingwaCapturedReferencePriceText: captured.price,
                  xiaoqingwaCapturedReferencePriceSource: captured.source || 'captured',
                  xiaoqingwaCapturedReferencePriceAt: captured.capturedAt || Date.now(),
                  xiaoqingwaCapturedReferencePriceOrderId: captured.priceOrderId || '',
                  xiaoqingwaCapturedReferencePriceSkcId: captured.skcId || '',
                  xiaoqingwaCapturedReferencePriceSkuId: captured.skuId || ''
                };
              });
            return {
              ...reviewInfo,
              priceOrderId: mergedReviewPriceOrderId || reviewInfo.priceOrderId,
              productSkuList: mergedProductSkuList
            };
          })
        };
      })
    };
  });
  if (mergedCount) {
    console.log(`[TEMU运营助手] 已合并核价参考申报价缓存 ${mergedCount} 个SKU`);
  }
  return mergedList;
}

async function approvePricing(priceOrderId, items, customPrices) {
  const auth = await getAuth();

  // 构建 items：自定义阈值价由前端显式传入；未传时只能使用前端从 TEMU 核价单读取到的系统参考申报价。
  // 半托管里该值必须来自“调整后申报价格(CNY)”，不能用原申报价或计算值兜底。
  const pickPriceFen = (item = {}, skuId = '') => {
    const customPrice = customPrices?.[skuId];
    if (customPrice !== undefined && customPrice !== null && customPrice !== '') {
      const yuan = Number(customPrice);
      return Number.isFinite(yuan) && yuan > 0 ? Math.round(yuan * 100) : 0;
    }
    const suggestedFen = Number(item.suggestSupplyPrice);
    return Number.isFinite(suggestedFen) && suggestedFen > 0 ? Math.round(suggestedFen) : 0;
  };

  const adjustedItems = (Array.isArray(items) ? items : []).map(item => {
    const skuId = String(item?.productSkuId || item?.skuId || item?.goodsSkuId || item?.skuIdStr || '').trim();
    const adjustedItem = { productSkuId: skuId };
    adjustedItem.price = pickPriceFen(item, skuId);
    console.log(`[TEMU运营助手] approvePricing: SKU ${skuId}, price=${adjustedItem.price}`);
    return adjustedItem;
  }).filter(item => item.productSkuId);

  // 安全检查：如果任何 item 缺少 price，直接返回错误
  const missingPrice = adjustedItems.find(item => !item.price);
  if (missingPrice) {
    return { success: false, error: '部分SKU缺少系统参考申报价；半托管必须读取“调整后申报价格(CNY)”，接口未返回时不能同意核价' };
  }

  const requestBody = {
    supplierResult: 1,
    priceOrderId: priceOrderId,
    items: adjustedItems,
    bargainReasonList: []
  };

  // 最多重试 3 次
  for (let i = 0; i < 3; i++) {
    try {
      console.log(`[TEMU运营助手] approvePricing attempt ${i+1}, body:`, JSON.stringify(requestBody));
      const data = await temuSellerPost('https://agentseller.temu.com/api/kiana/mms/magneto/price/bargain-no-bom', requestBody, auth, 30000);
      console.log('[TEMU运营助手] 重新调整报价响应:', JSON.stringify(data).substring(0, 300));
      if (data.success) return { success: true };
      return { success: false, error: data.errorMsg || '重新调整报价失败' };
    } catch (e) {
      if (i < 2) await new Promise(r => setTimeout(r, 1000));
    }
  }
  return { success: false, error: '重新调整报价失败（重试3次）' };
}

async function resubmitPricing(priceOrderId, items, customPrices) {
  const auth = await getAuth();

  const pickPriceFen = (item = {}, skuId = '') => {
    const customPrice = customPrices?.[skuId];
    if (customPrice !== undefined && customPrice !== null && customPrice !== '') {
      const yuan = Number(customPrice);
      return Number.isFinite(yuan) && yuan > 0 ? Math.round(yuan * 100) : 0;
    }
    return 0;
  };

  const adjustedItems = (Array.isArray(items) ? items : []).map(item => {
    const skuId = String(item?.productSkuId || item?.skuId || item?.goodsSkuId || item?.skuIdStr || '').trim();
    const price = pickPriceFen(item, skuId);
    return skuId ? { productSkuId: skuId, price } : null;
  }).filter(Boolean);

  if (!adjustedItems.length) {
    return { success: false, error: '缺少重新提报的SKU明细' };
  }
  const missingPrice = adjustedItems.find(item => !item.price);
  if (missingPrice) {
    return { success: false, error: '部分SKU缺少重新提报价格，请重新同步核价列表后再操作' };
  }

  const requestBody = {
    supplierResult: 2,
    priceOrderId: priceOrderId,
    items: adjustedItems,
    bargainReasonList: []
  };

  for (let i = 0; i < 3; i++) {
    try {
      console.log(`[TEMU运营助手] resubmitPricing attempt ${i + 1}, body:`, JSON.stringify(requestBody));
      const data = await temuSellerPost('https://agentseller.temu.com/api/kiana/mms/magneto/price/bargain-no-bom', requestBody, auth, 30000);
      console.log('[TEMU运营助手] 重新提报响应:', JSON.stringify(data).substring(0, 300));
      if (data.success) return { success: true };
      return { success: false, error: data.errorMsg || '重新提报失败' };
    } catch (e) {
      if (i < 2) await new Promise(r => setTimeout(r, 1000));
    }
  }
  return { success: false, error: '重新提报失败（重试3次）' };
}

async function rejectPricing(priceOrderId, items) {
  const auth = await getAuth();
  const adjustedItems = (Array.isArray(items) ? items : []).map(item => {
    const skuId = String(item?.productSkuId || item?.skuId || item?.goodsSkuId || item?.skuIdStr || '').trim();
    return skuId ? { productSkuId: skuId } : null;
  }).filter(Boolean);

  if (!adjustedItems.length) {
    return { success: false, error: '缺少要拒绝的SKU明细，请先勾选核价商品' };
  }

  const requestBody = {
    supplierResult: 2,
    priceOrderId: priceOrderId,
    items: adjustedItems,
    bargainReasonList: []
  };

  for (let i = 0; i < 3; i++) {
    try {
      const data = await temuSellerPost('https://agentseller.temu.com/api/kiana/mms/magneto/price/bargain-no-bom', requestBody, auth, 30000);
      console.log('[TEMU运营助手] 拒绝核价响应:', JSON.stringify(data).substring(0, 300));
      if (data.success) return { success: true };
      return { success: false, error: data.errorMsg || '拒绝失败' };
    } catch (e) {
      if (i < 2) await new Promise(r => setTimeout(r, 1000));
    }
  }
  return { success: false, error: '拒绝核价失败（重试3次）' };
}

async function voidPricing(priceOrderId) {
  const auth = await getAuth();

  const requestBody = { priceOrderId: priceOrderId };

  const data = await temuSellerPost('https://agentseller.temu.com/api/kiana/mms/magneto/api/price-review-order/no-bom/review', requestBody, auth, 30000);
  console.log('[TEMU运营助手] 放弃调整报价响应:', JSON.stringify(data).substring(0, 300));

  return {
    success: data.success === true,
    error: data.errorMsg || '放弃调整报价失败'
  };
}

function formatCustomizedTimestamp(value) {
  if (value === null || value === undefined || value === '') return '';
  const num = Number(value);
  const date = Number.isFinite(num)
    ? new Date(num > 1e12 ? num : num * 1000)
    : new Date(String(value).replace(/-/g, '/'));
  if (Number.isNaN(date.getTime())) return String(value);
  const pad = n => String(n).padStart(2, '0');
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
}

function parseSalesTimestamp(value) {
  if (value === null || value === undefined || value === '') return 0;
  if (typeof value === 'number' && Number.isFinite(value)) {
    return value > 1e12 ? value : value * 1000;
  }
  const text = String(value).trim();
  if (!text) return 0;
  const parsed = Date.parse(text.replace(/-/g, '/'));
  return Number.isNaN(parsed) ? 0 : parsed;
}

function extractSalesScore(item = {}) {
  const candidates = [
    item.score,
    item.productScore,
    item.avgScore,
    item.averageScore,
    item.reputationScore,
    item.sellerScore,
    item.shopScore,
    item.comprehensiveScore,
    item.productEvaluateScore
  ];
  for (const value of candidates) {
    if (value === null || value === undefined || value === '') continue;
    const num = Number(value);
    if (Number.isFinite(num)) return num;
  }
  return '';
}

function extractSalesDurationSeconds(item = {}) {
  const directCandidates = [
    item.onSalesDurationOffline,
    item.onSalesDuration,
    item.on_sales_duration,
    item.onlineDuration,
    item.inShopDuration,
    item.joinSiteDuration,
    item.siteDuration,
    item.duration,
    item.shelfDuration,
    item.shopDuration
  ];
  for (const value of directCandidates) {
    const num = Number(value);
    if (Number.isFinite(num) && num > 0) return num;
  }

  const ts = parseSalesTimestamp(
    item.createTime ||
    item.createDate ||
    item.publishTime ||
    item.joinTime ||
    item.addTime ||
    item.firstOnlineTime ||
    item.shelveTime
  );
  if (ts > 0) {
    return Math.max(0, Math.floor((Date.now() - ts) / 1000));
  }
  return 0;
}

function extractSalesInventoryFields(item = {}, detailList = []) {
  const firstDetail = Array.isArray(detailList) && detailList.length > 0 ? detailList[0] : {};
  const warehouseList = firstDetail.warehouseInfoList || item.warehouseInfoList || [];
  const firstWarehouse = Array.isArray(warehouseList) && warehouseList.length > 0 ? warehouseList[0] : {};
  return {
    availableInventoryNum: item.availableInventoryNum
      || item.inWarehouseAvailableInventoryNum
      || firstDetail.availableInventoryNum
      || firstDetail.inWarehouseAvailableInventoryNum
      || firstWarehouse.availableInventoryNum
      || firstWarehouse.inWarehouseAvailableInventoryNum
      || '',
    reservedInventoryNum: item.reservedInventoryNum
      || item.inWarehouseReservedInventoryNum
      || item.preOccupyInventoryNum
      || firstDetail.reservedInventoryNum
      || firstDetail.inWarehouseReservedInventoryNum
      || firstDetail.preOccupyInventoryNum
      || firstWarehouse.reservedInventoryNum
      || firstWarehouse.inWarehouseReservedInventoryNum
      || firstWarehouse.preOccupyInventoryNum
      || '',
    unavailableInventoryNum: item.unavailableInventoryNum
      || item.inWarehouseUnavailableInventoryNum
      || firstDetail.unavailableInventoryNum
      || firstDetail.inWarehouseUnavailableInventoryNum
      || firstWarehouse.unavailableInventoryNum
      || firstWarehouse.inWarehouseUnavailableInventoryNum
      || '',
    shippedInventoryNum: item.shippedInventoryNum
      || item.shippedNum
      || item.sentInventoryNum
      || item.deliveredInventoryNum
      || firstDetail.shippedInventoryNum
      || firstDetail.shippedNum
      || firstDetail.sentInventoryNum
      || firstDetail.deliveredInventoryNum
      || firstWarehouse.shippedInventoryNum
      || firstWarehouse.shippedNum
      || firstWarehouse.sentInventoryNum
      || firstWarehouse.deliveredInventoryNum
      || ''
  };
}

function extractSalesWarehouseList(item = {}, detailList = []) {
  const warehouseList = [];
  const pushList = list => {
    if (!Array.isArray(list)) return;
    list.forEach(w => {
      if (w && typeof w === 'object') warehouseList.push(w);
    });
  };

  if (Array.isArray(item.warehouseInfoList)) pushList(item.warehouseInfoList);
  if (Array.isArray(item.inventoryWarehouseList)) pushList(item.inventoryWarehouseList);
  (Array.isArray(detailList) ? detailList : []).forEach(detail => {
    if (Array.isArray(detail.warehouseInfoList)) pushList(detail.warehouseInfoList);
    if (Array.isArray(detail.warehouseList)) pushList(detail.warehouseList);
  });

  return warehouseList;
}

function extractSalesSkuSpecValues(source) {
  const values = [];
  const pushValue = (value) => {
    if (value === null || value === undefined || value === '') return;
    if (Array.isArray(value)) {
      value.forEach(pushValue);
      return;
    }
    if (typeof value === 'object') {
      const nested = value.attrValue
        ?? value.value
        ?? value.specValue
        ?? value.propertyValue
        ?? value.text;
      if (nested !== undefined) pushValue(nested);
      return;
    }
    values.push(String(value).trim());
  };

  if (Array.isArray(source)) {
    source.forEach(item => pushValue(item));
  } else if (source && typeof source === 'object') {
    ['attrValue', 'value', 'specValue', 'propertyValue', 'text', 'values', 'valueList', 'attrValues', 'specValues', 'items', 'list'].forEach(key => {
      if (source[key] !== undefined) pushValue(source[key]);
    });
  }

  return values.filter(Boolean);
}

function extractSalesSkuDisplayName(sku = {}) {
  const className = sku.className || sku.class_name || sku.skuClassName || sku.sku_class_name;
  if (className !== null && className !== undefined && className !== '') {
    return String(className);
  }

  const sources = [
    sku.spec,
    sku.skuAttrList,
    sku.specList,
    sku.skuAttributes,
    sku.attrList,
    sku.saleAttrList,
    sku.properties,
    sku.skuPropertyList
  ];

  for (const source of sources) {
    const values = extractSalesSkuSpecValues(source);
    if (values.length > 0) return values.join('/');
  }

  return '';
}

function extractSalesSkuClassName(sku = {}) {
  const className = sku.className || sku.class_name || sku.skuClassName || sku.sku_class_name;
  if (className !== null && className !== undefined && className !== '') {
    return String(className);
  }
  return extractSalesSkuDisplayName(sku);
}

function extractSalesSkuCodeText(sku = {}) {
  const candidates = [
    sku.extCode,
    sku.skuCode,
    sku.skuNo,
    sku.productSkuCode,
    sku.goodsSkuCode,
    sku.skuSn,
    sku.barcode,
    sku.skuPropertiesText
  ];
  for (const value of candidates) {
    if (value !== null && value !== undefined && String(value).trim() !== '') {
      return String(value).trim();
    }
  }
  return '';
}

function attachRawSkuFields(sku = {}) {
  return { ...sku };
}

function normalizeCustomizedImageUrlForExport(value = '') {
  const text = String(value || '').trim();
  if (!text) return '';
  if (/^data:image\//i.test(text)) return text;
  if (text.startsWith('//')) return `https:${text}`;
  if (text.startsWith('http://')) return `https://${text.slice(7)}`;
  return /^https?:\/\//i.test(text) ? text : '';
}

function collectCustomizedImageCandidates(source, output = [], depth = 0) {
  if (!source || depth > 3) return output;
  if (typeof source === 'string') {
    const url = normalizeCustomizedImageUrlForExport(source);
    if (url) output.push(url);
    return output;
  }
  if (Array.isArray(source)) {
    source.forEach(item => collectCustomizedImageCandidates(item, output, depth + 1));
    return output;
  }
  if (typeof source !== 'object') return output;

  [
    'url',
    'src',
    'image',
    'imageUrl',
    'imgUrl',
    'mainImage',
    'mainImageUrl',
    'goodsImg',
    'goodsImage',
    'productSkcPicture',
    'productSkcImage',
    'colorImageUrl',
    'materialImgUrl',
    'thumbUrl',
    'skuImage',
    'skuPreviewImage',
    'productSkuImage',
    'productImgUrl',
    'previewImgUrl',
    'previewImageUrl'
  ].forEach(key => collectCustomizedImageCandidates(source[key], output, depth + 1));

  [
    'imageList',
    'images',
    'goodsImages',
    'skcImages',
    'thumbUrlList',
    'previewImgUrlList',
    'previewImgUrls',
    'carouselImageUrls',
    'productSkcImageExtList',
    'productSkuThumbUrlI18nVOList'
  ].forEach(key => collectCustomizedImageCandidates(source[key], output, depth + 1));

  return output;
}

function scoreCustomizedImageUrl(url = '') {
  const text = String(url || '').toLowerCase();
  let score = /^data:image\//.test(text) ? 100 : 0;
  if (/main|skc|goods|product|color|preview/.test(text)) score += 8;
  if (/thumb|thumbnail|small|tiny/.test(text)) score -= 8;
  const dimensionMatches = Array.from(text.matchAll(/(?:^|[^\d])(\d{2,4})[x*_](\d{2,4})(?:[^\d]|$)/g));
  for (const match of dimensionMatches) {
    const w = Number(match[1]);
    const h = Number(match[2]);
    if (!Number.isFinite(w) || !Number.isFinite(h)) continue;
    const max = Math.max(w, h);
    const min = Math.min(w, h);
    if (max >= 800) score += 16;
    else if (max >= 400) score += 9;
    else if (max >= 240) score += 3;
    if (min > 0 && min <= 160) score -= 12;
  }
  return score;
}

function pickBestCustomizedImage(...sources) {
  const candidates = [];
  sources.forEach(source => collectCustomizedImageCandidates(source, candidates));
  const unique = Array.from(new Set(candidates.map(normalizeCustomizedImageUrlForExport).filter(Boolean)));
  unique.sort((a, b) => scoreCustomizedImageUrl(b) - scoreCustomizedImageUrl(a));
  return unique[0] || '';
}

function buildCustomizedStatusBadges(item = {}) {
  const badges = [];
  const isTruthyFlag = value => value === true || value === 1 || value === '1' || value === 'true';
  const isOnSale = Number(item.skcTopStatus) === 100;
  const orangeBadgeStyle = { color: '#ff6800', backgroundColor: '#fff4e6', borderColor: '#ff6800' };
  const blueBadgeStyle = { color: '#0071f3', backgroundColor: '#e6f6ff', borderColor: '#0071f3' };
  const redBadgeStyle = { color: '#dc2626', backgroundColor: '#fee2e2', borderColor: '#dc2626' };
  const skuSummaries = Array.isArray(item.productSkuSummaries) ? item.productSkuSummaries : [];
  const hasCustomizationTemplate = skuSummaries.some(sku => {
    const tmpl = sku?.productSkuSaleExtAttr?.productSkuCustomizationTmpl;
    return Boolean(tmpl && (!Array.isArray(tmpl.templateIds) || tmpl.templateIds.length > 0));
  });
  const personalization = item.productPersonalization || {};
  const hasPersonalizationEntry = Number(personalization.personalizationSwitch) === 1 || hasCustomizationTemplate;
  const autoDeleteDays = Number(item.autoDeleteRemainingDays);

  if (Number.isFinite(autoDeleteDays) && autoDeleteDays > 0) {
    badges.push({ text: `${autoDeleteDays}天后自动废弃`, ...orangeBadgeStyle });
  } else if (Number(item.productCertAuditStatus) === 1 || isTruthyFlag(item.offSaleByNoCert) || isTruthyFlag(item.noCertPunishRecord)) {
    badges.push({ text: '资质待上传', ...orangeBadgeStyle });
  }

  if (isOnSale) {
    badges.push({ text: '在售', ...blueBadgeStyle });
  }

  if (hasPersonalizationEntry) {
    badges.push({ text: '定制商品', ...(hasCustomizationTemplate ? blueBadgeStyle : orangeBadgeStyle) });
  }

  if (Number(item.skcTopStatus) === 200 && !(Number.isFinite(autoDeleteDays) && autoDeleteDays > 0)) {
    badges.push({ text: '已下架/已终止', ...redBadgeStyle });
  }

  if (Number(item.skcTopStatus) === 300) {
    badges.push({ text: '已删除', ...redBadgeStyle });
  }

  return badges;
}
function buildCustomizedProductItem(item = {}) {
  if (Array.isArray(item.productSkuSummaries) && item.productSkuSummaries.length > 0) {
    const skcImage = pickBestCustomizedImage(
      item.productSkcPicture,
      item.productSkcImage,
      item.colorImageUrl,
      item.mainImageUrl,
      item.mainImage,
      item.goodsImg,
      item.imageUrl,
      item.imageList,
      item.images,
      item.previewImgUrlList,
      item.previewImgUrls,
      item.productSkcImageExtList
    );
    const skuList = item.productSkuSummaries.map((sku, index) => {
      const skuSpec = Array.isArray(sku.productSkuSpecList)
        ? sku.productSkuSpecList.map(spec => spec?.specName || spec?.value || '').filter(Boolean).join(' / ')
        : '';
      const priceSource = sku.supplierPrice ?? sku.price ?? '';
      const price = priceSource === '' || priceSource === null || priceSource === undefined
        ? ''
        : (Number(priceSource) / 100).toFixed(2);
      const stockCandidates = [
        sku.realStock,
        sku.stock,
        sku.stockNum,
        sku.inventoryNum,
        sku.availableStock,
        sku.virtualStock,
        sku.productSkuSemiManagedStock
      ];
      const stockValue = stockCandidates.find(value => value !== null && value !== undefined && value !== '' && Number.isFinite(Number(value)));
      const stockText = stockValue === undefined ? '' : Number(stockValue).toLocaleString();
      const createTime = sku.createdAt || sku.createTime || sku.createDate || item.productCreateTime || item.createdAt || item.createTime || '';
      const skuImage = pickBestCustomizedImage(
        sku.skuImage,
        sku.imageUrl,
        sku.thumbUrl,
        sku.productSkuImage,
        sku.skuPreviewImage,
        sku.productSkuThumbUrlI18nVOList,
        skcImage
      );
      return {
        skuId: sku.productSkuId || sku.skuId || sku.skuIdStr || '',
        skuSpec,
        skuImage,
        imageUrl: sku.imageUrl || skuImage,
        thumbUrl: sku.thumbUrl || skuImage,
        productSkuImage: sku.productSkuImage || skuImage,
        stockText,
        showStockText: stockText,
        price,
        createTime: formatCustomizedTimestamp(createTime),
        productSkuCustomizationTmpl: sku.productSkuSaleExtAttr?.productSkuCustomizationTmpl || null,
        stockBadgeText: '',
        saleTypeText: '',
        rawText: '',
        orderIndex: index
      };
    }).filter(sku => sku.skuId || sku.skuSpec || sku.price || sku.stockText);

    const productCreateTime = item.productCreateTime || item.createdAt || item.createTime || item.createDate || item.publishTime || item.joinTime || item.addTime || item.firstOnlineTime || item.shelveTime || '';
    const topStatusNameMap = {
      0: '未发布到站点',
      100: '在售中',
      200: '已下架/已终止',
      300: '已删除'
    };
    const lifecycleStageName = topStatusNameMap[Number(item.skcTopStatus)] || '';

      return {
      goodsId: item.productId || item.goodsId || item.goodId || item.id || '',
      productId: item.productSkcId || item.skcId || item.productSkuId || '',
      productName: item.productName || item.goodsName || item.productCNName || item.name || '-',
      productStatus: item.productStatus ?? item.status ?? '',
      skcStatus: item.skcStatus ?? '',
      skcSiteStatus: item.skcSiteStatus ?? '',
      removeStatus: item.removeStatus ?? '',
      skcTopStatus: item.skcTopStatus ?? '',
      productCertAuditStatus: item.productCertAuditStatus ?? '',
      offSaleByNoCert: item.offSaleByNoCert ?? '',
      noCertPunishRecord: item.noCertPunishRecord ?? '',
      productPersonalization: item.productPersonalization || {},
      autoDeleteRemainingDays: item.autoDeleteRemainingDays ?? null,
      lifecycleStage: Number(item.skcStatus || item.productStatus || item.status || 0),
      lifecycleStageName,
      productStatusName: lifecycleStageName,
      price: item.supplierPrice ? (Number(item.supplierPrice) / 100).toFixed(2) : item.price ? (Number(item.price) / 100).toFixed(2) : '',
      mainImage: skcImage,
      imageList: Array.from(new Set(collectCustomizedImageCandidates([
        skcImage,
        item.imageList,
        item.images,
        item.previewImgUrlList,
        item.previewImgUrls,
        item.productSkcImageExtList
      ], []))).slice(0, 12),
      productSkcImageExtList: Array.isArray(item.productSkcImageExtList) ? item.productSkcImageExtList : [],
      skcId: item.productSkcId || item.skcId || '',
      skcExtCode: item.extCode || item.skcExtCode || item.skcCode || item.productSkcCode || '',
      skuCount: skuList.length,
      categoryId: item.classId || item.categoryId || '',
      categoryName: item.leafCat?.catName || item.categoryName || item.catName || item.category || '',
      createTime: formatCustomizedTimestamp(productCreateTime),
      updateTime: formatCustomizedTimestamp(item.updateTime || item.modifyTime || item.modifiedTime || ''),
      onlineTime: formatCustomizedTimestamp(item.onlineTime || item.shelveTime || ''),
      score: extractSalesScore(item),
      skuDisplayName: '',
      skuCode: item.extCode || item.skcExtCode || item.skcCode || item.productSkcCode || '',
      productPropertyList: Array.isArray(item.productProperties) ? item.productProperties : (Array.isArray(item.productPropertyList) ? item.productPropertyList : []),
      skuName: item.productName || '-',
      skuSpecText: '',
      saleStatusText: Number(item.skcSiteStatus) === 1 ? '在售' : '',
      onSalesDuration: extractSalesDurationSeconds({ createTime: productCreateTime }),
      skuList,
      skuQuantityDetailList: skuList.map(attachRawSkuFields),
      warehouseInfoList: [],
      statusBadges: buildCustomizedStatusBadges(item)
    };
  }

  const productStatus = item.productStatus || item.status || 0;
  let lifecycleStageName = '未知';
  switch (productStatus) {
    case 1: lifecycleStageName = '价格申报中'; break;
    case 2: lifecycleStageName = '待创建首单'; break;
    case 3: lifecycleStageName = '已创建首单'; break;
    case 4: lifecycleStageName = '已发布到站点'; break;
    case 5: lifecycleStageName = '已下架/终止'; break;
  }

  const skuList = item.skuList || item.skuListInfo || [];
  const skuDisplayName = extractSalesSkuDisplayName(item);
  const skuCode = extractSalesSkuCodeText(item);
  const createTime = item.createTime || item.createDate || item.publishTime || item.joinTime || item.addTime || item.firstOnlineTime || item.shelveTime || '';
  const skcImage = pickBestCustomizedImage(
    item.productSkcPicture,
    item.productSkcImage,
    item.colorImageUrl,
    item.goodsImg,
    item.mainImageUrl,
    item.mainImage,
    item.imageUrl,
    item.imageList,
    item.images,
    item.previewImgUrlList,
    item.previewImgUrls,
    item.productSkcImageExtList
  );

  return {
    goodsId: item.goodsId || item.goodId || item.id || '',
    productId: item.goodspu || item.productSpuId || item.productId || '',
    productName: item.goodsName || item.productCNName || item.productName || '-',
    productStatus: item.productStatus ?? item.status ?? '',
    skcStatus: item.skcStatus ?? '',
    skcSiteStatus: item.skcSiteStatus ?? '',
    removeStatus: item.removeStatus ?? '',
    skcTopStatus: item.skcTopStatus ?? '',
    lifecycleStage: productStatus,
    lifecycleStageName,
    productStatusName: lifecycleStageName,
    price: item.price ? (item.price / 100).toFixed(2) : item.supplierPrice ? (item.supplierPrice / 100).toFixed(2) : '',
    mainImage: skcImage,
    imageList: Array.from(new Set(collectCustomizedImageCandidates([
      skcImage,
      item.imageList,
      item.images,
      item.previewImgUrlList,
      item.previewImgUrls,
      item.productSkcImageExtList
    ], []))).slice(0, 12),
    productSkcImageExtList: Array.isArray(item.productSkcImageExtList) ? item.productSkcImageExtList : [],
    skcId: item.productSkcId || item.skcId || '',
    skcExtCode: item.skcExtCode || item.skcCode || item.productSkcCode || '',
    skuCount: skuList.length,
    categoryId: item.categoryId || '',
    categoryName: item.categoryName || item.catName || item.category || '',
    createTime,
    updateTime: item.updateTime || item.modifyTime || item.modifiedTime || '',
    onlineTime: item.onlineTime || item.shelveTime || '',
    score: extractSalesScore(item),
    skuDisplayName,
    skuCode,
    productPropertyList: item.productPropertyList || [],
    skuName: skuDisplayName || `SKU ${item.productSkuId || item.skuId || ''}`.trim(),
    skuSpecText: skuDisplayName,
    saleStatusText: item.saleStatusText || item.saleStatusName || item.statusName || '',
    onSalesDuration: extractSalesDurationSeconds(item),
    skuList: skuList.map(sku => {
      const skuImage = pickBestCustomizedImage(
        sku.skuImage,
        sku.imageUrl,
        sku.thumbUrl,
        sku.productSkuImage,
        sku.skuPreviewImage,
        sku.productSkuThumbUrlI18nVOList,
        skcImage
      );
      return attachRawSkuFields({
        ...sku,
        skuImage,
        imageUrl: sku.imageUrl || skuImage,
        thumbUrl: sku.thumbUrl || skuImage,
        productSkuImage: sku.productSkuImage || skuImage
      });
    }),
    skuQuantityDetailList: (item.skuQuantityDetailList || []).map(attachRawSkuFields),
    warehouseInfoList: extractSalesWarehouseList(item, item.skuQuantityDetailList || []),
    ...extractSalesInventoryFields(item, item.skuQuantityDetailList || [])
  };
}

function buildSalesProductFromApi(item = {}) {
  const product = buildCustomizedProductItem(item);
  const skuRows = [
    ...(Array.isArray(product.skuQuantityDetailList) ? product.skuQuantityDetailList : []),
    ...(Array.isArray(product.skuList) ? product.skuList : [])
  ];
  const readNumber = (...values) => {
    for (const value of values) {
      const num = normalizeDashboardMetricNumber(value);
      if (num) return num;
    }
    return 0;
  };
  const sumSku = keys => skuRows.reduce((sum, sku) => {
    const value = keys.map(key => sku?.[key]).find(v => v !== undefined && v !== null && v !== '');
    return sum + normalizeDashboardMetricNumber(value);
  }, 0);

  product.todaySaleVolume = Math.max(sumSku([
    'todaySaleVolume',
    'todaySalesVolume',
    'todaySale',
    'todayPlatformPurchaseNum',
    'todayPlatformSalesNum'
  ]), readNumber(
    item.todaySaleVolume,
    item.todaySalesVolume,
    item.todaySale,
    item.todayPlatformPurchaseNum,
    item.todayPlatformSalesNum
  ));
  product.sevenDaysSaleVolume = Math.max(sumSku([
    'lastSevenDaysSaleVolume',
    'sevenDaysSaleVolume',
    'sevenDaySaleVolume',
    'last7DaysSaleVolume'
  ]), readNumber(
    item.lastSevenDaysSaleVolume,
    item.sevenDaysSaleVolume,
    item.sevenDaySaleVolume,
    item.last7DaysSaleVolume,
    item.weekSaleVolume,
    item.recent7DaysSaleVolume
  ));
  product.thirtyDaysSaleVolume = Math.max(sumSku([
    'lastThirtyDaysSaleVolume',
    'thirtyDaysSaleVolume',
    'thirtyDaySaleVolume',
    'last30DaysSaleVolume'
  ]), readNumber(
    item.lastThirtyDaysSaleVolume,
    item.thirtyDaysSaleVolume,
    item.thirtyDaySaleVolume,
    item.last30DaysSaleVolume,
    item.monthSaleVolume,
    item.recent30DaysSaleVolume
  ));
  return product;
}

async function fetchSalesData(params = {}) {
  const auth = await getAuth();
  const pageNo = Math.max(1, Number(params.pageNo || params.pageNum || 1) || 1);
  const pageSize = Math.min(Math.max(Number(params.pageSize || 100) || 100, 20), 200);
  const body = {
    pageNo,
    pageSize,
    priceAdjustRecentDays: Number(params.priceAdjustRecentDays || 7)
  };
  const requestAuth = {
    mallId: params.mallId || auth?.mallId || '',
    antiContent: params.antiContent || auth?.antiContent || ''
  };
  const url = 'https://agentseller.temu.com/mms/venom/api/supplier/sales/management/listWarehouse';
  let data = null;
  try {
    data = await temuSellerPagePost(url, body, requestAuth, 25000);
  } catch (pageError) {
    console.warn('[TEMU运营助手] 销量查询页面请求失败，尝试后台请求兜底:', pageError);
    try {
      data = await temuSellerBackgroundPost(url, body, requestAuth, 25000);
    } catch (backgroundError) {
      const pageMessage = pageError?.message || String(pageError);
      const backgroundMessage = backgroundError?.message || String(backgroundError);
      return {
        success: false,
        error: `销量查询接口请求失败：${backgroundMessage || pageMessage}`,
        pageError: pageMessage,
        backgroundError: backgroundMessage
      };
    }
  }
  if (!isTemuApiSuccess(data) || !data?.result) {
    return { success: false, error: getTemuApiMessage(data, '获取销售数据失败') };
  }
  const result = data.result || {};
  const list = result.subOrderList || result.productList || result.list || result.items || result.records || [];
  const products = Array.isArray(list) ? list.map(buildSalesProductFromApi) : [];
  const total = Number(result.total || result.totalCount || products.length || 0) || products.length;
  return {
    success: true,
    products,
    total,
    totalPages: Math.max(1, Math.ceil(total / pageSize)),
    pageNum: pageNo,
    pageSize
  };
}

async function fetchSalesDataAll(params = {}) {
  const pageSize = Math.min(Math.max(Number(params.pageSize || 100) || 100, 20), 200);
  const maxPages = Math.min(Math.max(Number(params.maxPages || 30) || 30, 1), 80);
  const products = [];
  let total = 0;
  let totalPages = 1;

  for (let pageNo = 1; pageNo <= totalPages && pageNo <= maxPages; pageNo += 1) {
    const pageResult = await fetchSalesData({ ...params, pageNo, pageSize });
    if (!pageResult.success) return pageResult;
    products.push(...(Array.isArray(pageResult.products) ? pageResult.products : []));
    total = pageResult.total || total || products.length;
    totalPages = Math.max(1, pageResult.totalPages || Math.ceil(total / pageSize));
    if (!pageResult.products?.length || pageResult.products.length < pageSize) break;
    await new Promise(resolve => setTimeout(resolve, 80));
  }

  return {
    success: true,
    products,
    total: total || products.length,
    totalPages: Math.max(1, totalPages)
  };
}

async function fetchCustomizedProductListPreferred(auth, params = {}, currentPage = 1, pageSize = 20) {
  try {
    const data = await temuSellerPost('https://agentseller.temu.com/visage-agent-seller/product/skc/pageQuery', {
        page: currentPage,
        pageSize,
        ...(params.lifecycleStage !== undefined && params.lifecycleStage !== null && params.lifecycleStage !== ''
          ? { skcTopStatus: Number(params.lifecycleStage) }
          : {}),
        productName: params.productName || undefined,
        productId: params.productId || params.productSkcId || undefined
      }, auth, 25000);
    const detail = data.detail || data.result || data.data || {};
    const items = detail.pageItems || detail.items || detail.list || detail.dataList || detail.records || [];
    const total = detail.total || detail.totalCount || detail.totalNum || items.length || 0;
    if (items.length === 0) return null;
    return {
      success: true,
      products: items.map(buildCustomizedProductItem),
      total,
      pageNo: currentPage,
      pageSize,
      totalPages: Math.ceil(total / pageSize)
    };
  } catch (error) {
    console.log('[TEMU运营助手] 定制品备用商品管理页失败:', error.message);
    return null;
  }
}

async function fetchCustomizedProductList(params = {}) {
  const auth = await getAuth();
  try {
    const currentPage = params.pageNo || 1;
    const pageSize = params.pageSize || 20;

    const data = await temuSellerPost('https://agentseller.temu.com/visage-agent-seller/product/skc/pageQuery', {
        page: currentPage,
        pageSize,
        ...(params.lifecycleStage !== undefined && params.lifecycleStage !== null && params.lifecycleStage !== ''
          ? { skcTopStatus: Number(params.lifecycleStage) }
          : {}),
        ...(params.productName ? { productName: params.productName } : {}),
        ...(params.productId || params.productSkcId ? { productId: params.productId || params.productSkcId } : {})
      }, auth, 25000);
    const detail = data.detail || data.result || data.data || {};
    const items = detail.pageItems || detail.items || detail.list || detail.dataList || detail.records || [];
    const total = detail.total || detail.totalCount || detail.totalNum || items.length || 0;

    if (!items.length) {
      return { success: false, error: '商品列表为空' };
    }

    return {
      success: true,
      products: items.map(buildCustomizedProductItem),
      total,
      pageNo: currentPage,
      pageSize,
      totalPages: Math.ceil(total / pageSize)
    };
  } catch (error) {
    console.error('[TEMU运营助手] fetchCustomizedProductList 出错:', error);
    return { success: false, error: error.message };
  }
}

const CUSTOMIZED_SKC_PAGE_QUERY_URL = 'https://agentseller.temu.com/visage-agent-seller/product/skc/pageQuery';
const CUSTOMIZED_TEMPLATE_EDIT_URL = 'https://agentseller.temu.com/visage-agent-seller/product/customization/template/edit';
const CUSTOMIZED_STOCK_QUERY_URL = 'https://agentseller.temu.com/darwin-mms/api/kiana/ghost/btg/sales/stock/queryBtgProductStockInfo';
const CUSTOMIZED_STOCK_UPDATE_SEMI_URL = 'https://agentseller.temu.com/darwin-mms/api/kiana/ghost/btg/sales/stock/updateMmsBtgProductSalesStock';
const CUSTOMIZED_STOCK_UPDATE_FULL_URL = 'https://agentseller.temu.com/darwin-mms/api/kiana/foredawn/sales/stock/updateMmsProductSalesStock';
const TEMU_SELLER_USER_INFO_URL = 'https://agentseller.temu.com/api/seller/auth/userInfo';
const TEMU_PRODUCT_DRAFT_QUERY_URL = 'https://agentseller.temu.com/visage-agent-seller/product/draft/query';
const TEMU_PRODUCT_ADD_URL = 'https://agentseller.temu.com/visage-agent-seller/product/add';

function normalizeTemuRequestId(value) {
  const text = String(value ?? '').trim();
  if (!text) return '';
  if (/^\d+$/.test(text)) {
    const num = Number(text);
    return Number.isSafeInteger(num) ? num : text;
  }
  return text;
}

function getTemuApiMessage(data = {}, fallback = '请求失败') {
  return data?.errorMsg
    || data?.error_msg
    || data?.message
    || data?.msg
    || data?.error
    || data?.result?.errorMsg
    || data?.detail?.errorMsg
    || fallback;
}

function getTemuActivityApiMessage(data = {}, fallback = 'TEMU 活动报名失败') {
  const root = data?.result || data?.data || data?.detail || {};
  return getTemuApiMessage(data,
    root?.errorMsg ||
    root?.error_msg ||
    root?.message ||
    root?.msg ||
    root?.failReason ||
    root?.reason ||
    fallback
  );
}

function isTemuApiSuccess(data) {
  if (!data || typeof data !== 'object') return false;
  if (data.success === true) return true;
  if (data.code !== undefined) return Number(data.code) === 0;
  if (data.errorCode !== undefined) return Number(data.errorCode) === 0 || Number(data.errorCode) === 1000000;
  return Boolean(data.result || data.detail || data.data);
}

function extractCustomizedPageResult(data = {}) {
  const detail = data.result || data.detail || data.data || {};
  const items = detail.pageItems || detail.items || detail.list || detail.dataList || detail.records || [];
  const total = detail.total || detail.totalCount || detail.totalNum || items.length || 0;
  return { items: Array.isArray(items) ? items : [], total };
}

async function postCustomizedSkcPageQuery(auth, body, timeoutMs = 20000) {
  let pageFetchError = '';
  try {
    return await temuSellerPagePost(CUSTOMIZED_SKC_PAGE_QUERY_URL, body, auth, timeoutMs);
  } catch (error) {
    pageFetchError = error?.message || String(error);
  }

  const response = await fetch(CUSTOMIZED_SKC_PAGE_QUERY_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'mallid': auth?.mallId || '',
      'anti-content': auth?.antiContent || ''
    },
    credentials: 'include',
    body: JSON.stringify(body)
  });
  const data = await response.json().catch(() => null);
  if (!response.ok && !isTemuApiSuccess(data)) {
    throw new Error(getTemuApiMessage(data, pageFetchError || `HTTP ${response.status}`));
  }
  return data;
}

async function queryCustomizedSkcPageFresh(auth, body, timeoutMs = 20000) {
  const payload = {
    page: Number(body.page || 1),
    pageSize: Number(body.pageSize || 10),
    ...body
  };
  if (Array.isArray(payload.productIds)) {
    payload.productIds = payload.productIds.map(normalizeTemuRequestId).filter(Boolean);
  }
  if (Array.isArray(payload.productSkuIds)) {
    payload.productSkuIds = payload.productSkuIds.map(normalizeTemuRequestId).filter(Boolean);
  }

  const data = await postCustomizedSkcPageQuery(auth, payload, timeoutMs);
  if (!isTemuApiSuccess(data)) {
    return { success: false, error: getTemuApiMessage(data, '定制品商品数据查询失败'), raw: data };
  }

  const { items, total } = extractCustomizedPageResult(data);
  if (!items.length) {
    return { success: false, error: 'TEMU 未返回目标商品，请确认 SPU/SKU 是否正确或商品是否仍可编辑', raw: data };
  }

  return { success: true, items, total, raw: data };
}

function getCustomizedPageSkuList(product = {}) {
  const candidates = [
    product.productSkuSummaries,
    product.skuList,
    product.skuListInfo,
    product.productSkuList,
    product.skus
  ];
  return candidates.find(Array.isArray) || [];
}

function getCustomizedPageProductId(product = {}) {
  return product.productId || product.goodsId || product.goodspu || product.productSpuId || product.id || '';
}

function getCustomizedPageSkuId(sku = {}) {
  return String(sku.productSkuId || sku.skuId || sku.skuIdStr || '').trim();
}

function readTemuNumber(value, fallback = 0) {
  if (value === null || value === undefined || value === '') return fallback;
  const num = Number(value);
  return Number.isFinite(num) ? num : fallback;
}

function getCustomizedProductSkcId(product = {}) {
  return String(product.productSkcId || product.skcId || product.skc || product.productSkcIdStr || '').trim();
}

function getCustomizedSkuShippingMode(sku = {}) {
  const value = sku.productSkuShippingMode
    ?? sku.shippingMode
    ?? sku.productSkuSaleExtAttr?.productSkuShippingMode
    ?? sku.summary?.productSkuShippingMode;
  const num = Number(value);
  return Number.isFinite(num) ? num : null;
}

function getCustomizedSkuVirtualStock(sku = {}) {
  return readTemuNumber(
    sku.virtualStock
      ?? sku.summary?.virtualStock
      ?? sku.realStock
      ?? sku.stock
      ?? sku.stockNum
      ?? sku.inventoryNum
      ?? sku.availableStock
      ?? sku.productSkuSemiManagedStock,
    0
  );
}

async function getTemuMallManagedType(auth) {
  try {
    const data = await temuSellerPagePost(TEMU_SELLER_USER_INFO_URL, {}, auth, 12000);
    const mallList = data?.result?.mallList
      || data?.data?.mallList
      || data?.detail?.mallList
      || data?.mallList
      || [];
    if (!Array.isArray(mallList)) return null;
    const mallId = String(auth?.mallId || '').trim();
    const matched = mallList.find(mall => String(mall?.mallId || mall?.mall_id || mall?.id || '').trim() === mallId);
    const managedType = Number(matched?.managedType ?? matched?.manageType ?? matched?.mallManagedType);
    return Number.isFinite(managedType) ? managedType : null;
  } catch (error) {
    console.warn('[TEMU运营助手] 查询店铺托管类型失败，改用库存接口自动判断:', error?.message || error);
    return null;
  }
}

async function buildCustomizedSemiManagedStockPayload(auth, product = {}, productId = '', stockQuantity = 0) {
  const skuList = getCustomizedPageSkuList(product);
  const skuIds = [...new Set(skuList.map(getCustomizedPageSkuId).filter(Boolean))];
  if (!skuIds.length) return { canApply: false, error: 'TEMU 未返回可修改库存的 SKU' };

  const productSkuIdList = skuIds.map(normalizeTemuRequestId).filter(Boolean);
  let data = null;
  try {
    data = await temuSellerPagePost(CUSTOMIZED_STOCK_QUERY_URL, {
      productId: normalizeTemuRequestId(productId),
      productSkuIdList
    }, auth, 20000);
  } catch (error) {
    return { canApply: false, error: error?.message || '半托管库存查询失败' };
  }
  if (!isTemuApiSuccess(data)) {
    return { canApply: false, error: getTemuApiMessage(data, '半托管库存查询失败'), raw: data };
  }

  const result = data?.result || data?.detail || data?.data || {};
  const productStockList = result.productStockList || result.skuStockList || result.list || [];
  if (!Array.isArray(productStockList) || !productStockList.length) {
    return { canApply: false, error: 'TEMU 未返回半托管仓库库存' };
  }

  const shippingModeMap = new Map();
  skuList.forEach(sku => {
    const skuId = getCustomizedPageSkuId(sku);
    const mode = getCustomizedSkuShippingMode(sku);
    if (skuId && mode !== null) shippingModeMap.set(String(skuId), mode);
  });

  const skuStockChangeList = [];
  let warehouseCount = 0;
  for (const item of productStockList) {
    const productSkuId = String(item?.productSkuId || item?.skuId || '').trim();
    if (!productSkuId) continue;
    const warehouseStockList = item?.warehouseStockList || item?.warehouseStockQuantityList || item?.stockList || [];
    if (!Array.isArray(warehouseStockList)) continue;
    for (const warehouse of warehouseStockList) {
      if (warehouse?.warehouseDisable) continue;
      const warehouseId = warehouse?.warehouseInfo?.warehouseId ?? warehouse?.warehouseId;
      if (warehouseId === null || warehouseId === undefined || warehouseId === '') continue;
      warehouseCount++;
      const currentStockAvailable = readTemuNumber(
        warehouse.stockAvailable
          ?? warehouse.currentStockAvailable
          ?? warehouse.availableStock
          ?? warehouse.stock
          ?? warehouse.inventoryNum,
        0
      );
      const stockDiff = stockQuantity - currentStockAvailable;
      if (stockDiff === 0) continue;
      const change = {
        productSkuId: normalizeTemuRequestId(productSkuId),
        stockDiff,
        currentStockAvailable,
        warehouseId: normalizeTemuRequestId(warehouseId)
      };
      const mode = shippingModeMap.get(productSkuId);
      if (mode !== undefined) change.currentShippingMode = mode;
      skuStockChangeList.push(change);
    }
  }

  if (!warehouseCount) return { canApply: false, error: 'TEMU 未返回可用仓库，无法修改半托管库存' };
  return {
    canApply: true,
    noChanges: skuStockChangeList.length === 0,
    mode: 'semiManaged',
    payload: {
      productId: normalizeTemuRequestId(productId),
      skuStockChangeList,
      skuTypeChangeList: [],
      isCheckVersion: true,
      source: 0
    },
    skuCount: skuIds.length,
    warehouseCount
  };
}

function buildCustomizedFullManagedStockPayload(product = {}, productId = '', stockQuantity = 0) {
  const skuList = getCustomizedPageSkuList(product);
  const productSkcId = getCustomizedProductSkcId(product);
  if (!productSkcId) return { canApply: false, error: 'TEMU 未返回 SKC ID，无法修改全托管库存' };
  if (!skuList.length) return { canApply: false, error: 'TEMU 未返回可修改库存的 SKU' };

  const skuVirtualStockChangeList = [];
  for (const sku of skuList) {
    const productSkuId = getCustomizedPageSkuId(sku);
    if (!productSkuId) continue;
    const currentStockAvailable = getCustomizedSkuVirtualStock(sku);
    const virtualStockDiff = stockQuantity - currentStockAvailable;
    if (virtualStockDiff === 0) continue;
    skuVirtualStockChangeList.push({
      productSkuId: normalizeTemuRequestId(productSkuId),
      currentStockAvailable,
      virtualStockDiff
    });
  }

  return {
    canApply: true,
    noChanges: skuVirtualStockChangeList.length === 0,
    mode: 'fullManaged',
    payload: {
      productId: normalizeTemuRequestId(productId),
      skcVirtualStockChangeDTOList: [{
        productSkcId: normalizeTemuRequestId(productSkcId),
        stockUpdateSource: 1,
        skuVirtualStockChangeList
      }]
    },
    skuCount: skuList.length,
    skcCount: 1
  };
}

async function submitCustomizedStockPayload(auth, builtPayload) {
  if (!builtPayload?.canApply) {
    return { success: false, error: builtPayload?.error || '库存接口不可用' };
  }
  if (builtPayload.noChanges) {
    return {
      success: true,
      stockApplied: true,
      stockNoChange: true,
      stockMode: builtPayload.mode,
      stockUpdatedSkuCount: 0,
      stockWarehouseCount: builtPayload.warehouseCount || 0
    };
  }

  const url = builtPayload.mode === 'semiManaged'
    ? CUSTOMIZED_STOCK_UPDATE_SEMI_URL
    : CUSTOMIZED_STOCK_UPDATE_FULL_URL;
  const data = await temuSellerPagePost(url, builtPayload.payload, auth, 30000);
  if (!isTemuApiSuccess(data)) {
    return { success: false, error: getTemuApiMessage(data, '库存更新失败'), raw: data };
  }
  return {
    success: true,
    stockApplied: true,
    stockMode: builtPayload.mode,
    stockUpdatedSkuCount: builtPayload.skuCount || 0,
    stockWarehouseCount: builtPayload.warehouseCount || 0,
    raw: data
  };
}

async function applyCustomizedProductStock(auth, product = {}, productId = '', stockQuantity = null) {
  const targetStock = Number(stockQuantity);
  if (!Number.isInteger(targetStock) || targetStock < 0) {
    return { success: false, error: '商品库存必须是大于等于 0 的整数' };
  }

  const managedType = await getTemuMallManagedType(auth);
  const attempts = managedType === 1
    ? ['semiManaged', 'fullManaged']
    : managedType === null
      ? ['semiManaged', 'fullManaged']
      : ['fullManaged', 'semiManaged'];
  let lastUnavailable = '';

  for (const mode of attempts) {
    const builtPayload = mode === 'semiManaged'
      ? await buildCustomizedSemiManagedStockPayload(auth, product, productId, targetStock)
      : buildCustomizedFullManagedStockPayload(product, productId, targetStock);

    if (!builtPayload.canApply) {
      lastUnavailable = builtPayload.error || lastUnavailable;
      continue;
    }

    const submitResult = await submitCustomizedStockPayload(auth, builtPayload);
    if (submitResult.success) {
      return {
        ...submitResult,
        stockAttempted: true,
        stockQuantity: targetStock
      };
    }
    return {
      success: false,
      stockAttempted: true,
      error: submitResult.error || '库存更新失败',
      raw: submitResult.raw
    };
  }

  return {
    success: false,
    stockAttempted: true,
    error: lastUnavailable || '未找到可用的 TEMU 库存更新接口'
  };
}

async function resolveFreshCustomizedTemplateIds(auth, params = {}) {
  const templateSkuId = String(params.templateSkuId || params.sourceTemplateSkuId || params.skuId || '').trim();
  const fallbackTemplateIds = [...new Set(
    [params.templateId, ...(Array.isArray(params.templateIds) ? params.templateIds : [])]
      .map(id => String(id || '').trim())
      .filter(Boolean)
  )];

  if (!templateSkuId) {
    if (fallbackTemplateIds.length) {
      return { success: true, templateIds: fallbackTemplateIds, source: 'saved-template' };
    }
    return { success: false, error: '模板缺少来源 SKU，请重新保存定制品模板' };
  }

  const queryResult = await queryCustomizedSkcPageFresh(auth, {
    page: 1,
    pageSize: 1,
    productSkuIds: [templateSkuId]
  }, 20000);

  if (!queryResult.success) {
    return { success: false, error: `模板 SKU ${templateSkuId} 实时查询失败：${queryResult.error || '未知错误'}` };
  }

  let matchedSku = null;
  for (const product of queryResult.items) {
    matchedSku = getCustomizedPageSkuList(product).find(sku => getCustomizedPageSkuId(sku) === templateSkuId);
    if (matchedSku) break;
  }

  if (!matchedSku) {
    return { success: false, error: `模板 SKU ${templateSkuId} 已不在 TEMU 当前商品数据中，请重新保存模板` };
  }

  const templateIds = getCustomizedSkuTemplateCandidates(matchedSku);
  if (!templateIds.length) {
    return { success: false, error: `模板 SKU ${templateSkuId} 当前未配置定制品信息，请重新设置后再保存模板` };
  }

  return { success: true, templateIds, source: 'temu-live-sku', templateSkuId };
}

function buildFreshCustomizedEditList(product = {}, templateIds = [], params = {}) {
  const skuList = getCustomizedPageSkuList(product);
  if (!skuList.length) {
    return { success: false, error: 'TEMU 当前商品没有返回 SKU 数据' };
  }

  const selectedSkuIds = new Set(
    [
      ...(Array.isArray(params.targetSkuIds) ? params.targetSkuIds : []),
      ...(Array.isArray(params.skuIds) ? params.skuIds : []),
      ...(Array.isArray(params.edits) ? params.edits.map(item => item?.productSkuId || item?.skuId) : [])
    ]
      .map(id => String(id || '').trim())
      .filter(Boolean)
  );
  const isPartial = params.applyMode === 'partial' || params.partial === true;
  let applyCount = 0;

  const editSkuCustomizationTmplList = [];
  skuList.forEach(sku => {
    const productSkuId = getCustomizedPageSkuId(sku);
    if (!productSkuId) return;

    if (!isPartial || selectedSkuIds.has(productSkuId)) {
      editSkuCustomizationTmplList.push({ productSkuId, templateIds });
      applyCount++;
      return;
    }

    const preservedTemplateIds = getCustomizedSkuTemplateCandidates(sku);
    if (preservedTemplateIds.length > 0) {
      editSkuCustomizationTmplList.push({ productSkuId, templateIds: preservedTemplateIds });
    }
  });

  if (isPartial && applyCount === 0) {
    return { success: false, error: '目标 SKU 已发生变化，未匹配到要修改的 SKU，请重新同步商品后再试' };
  }
  if (!editSkuCustomizationTmplList.length) {
    return { success: false, error: '没有可提交的 SKU 定制模板数据' };
  }

  return {
    success: true,
    productId: String(getCustomizedPageProductId(product) || '').trim(),
    editSkuCustomizationTmplList,
    applyCount
  };
}

function readDashboardMetric(node, keys = [], depth = 0) {
  if (!node || typeof node !== 'object' || depth > 5) return null;
  for (const key of keys) {
    if (node[key] !== undefined && node[key] !== null && node[key] !== '') return node[key];
  }
  for (const value of Object.values(node)) {
    if (value && typeof value === 'object') {
      const found = readDashboardMetric(value, keys, depth + 1);
      if (found !== null && found !== undefined && found !== '') return found;
    }
  }
  return null;
}

function normalizeDashboardMetricNumber(value) {
  if (value === null || value === undefined || value === '') return 0;
  if (typeof value === 'number') return Number.isFinite(value) ? value : 0;
  if (typeof value === 'object') {
    return normalizeDashboardMetricNumber(value.value ?? value.amount ?? value.num ?? value.count ?? value.number);
  }
  const parsed = Number(String(value).replace(/[,\s¥￥]/g, ''));
  return Number.isFinite(parsed) ? parsed : 0;
}

function extractDashboardHomeSalesPayload(data = {}) {
  const root = data?.result || data?.data || data?.detail || data;
  const todayTotal = normalizeDashboardMetricNumber(readDashboardMetric(root, [
    'todaySaleVolume',
    'todaySalesVolume',
    'todaySaleNum',
    'todaySalesNum',
    'todayOrderNum',
    'todayPayOrderNum',
    'todayCount'
  ]));
  const sevenDayTotal = normalizeDashboardMetricNumber(readDashboardMetric(root, [
    'sevenDaysSaleVolume',
    'lastSevenDaysSaleVolume',
    'sevenDaySaleVolume',
    'last7DaysSaleVolume',
    'sevenDaysSaleNum',
    'sevenDaySalesNum',
    'weekSaleVolume',
    'recent7DaysSaleVolume'
  ]));
  const todayAmount = normalizeDashboardMetricNumber(readDashboardMetric(root, [
    'todaySaleAmount',
    'todaySalesAmount',
    'todayPayAmount',
    'todayGmv',
    'todayGMV'
  ]));
  const sevenDayAmount = normalizeDashboardMetricNumber(readDashboardMetric(root, [
    'sevenDaysSaleAmount',
    'lastSevenDaysSaleAmount',
    'sevenDaySaleAmount',
    'last7DaysSaleAmount',
    'weekSaleAmount',
    'sevenDaysGmv',
    'sevenDayGMV'
  ]));
  if (todayTotal || sevenDayTotal || todayAmount || sevenDayAmount) {
    return { success: true, todayTotal, sevenDayTotal, todayAmount, sevenDayAmount, raw: root };
  }
  return null;
}

function extractDashboardSalesFromSupplierList(data = {}) {
  const root = data?.result || data?.data || data?.detail || data || {};
  const items = root.pageItems || root.items || root.list || root.dataList || root.records || [];
  if (!Array.isArray(items) || items.length === 0) return null;

  let todayTotal = 0;
  let sevenDayTotal = 0;
  let todayAmount = 0;
  let sevenDayAmount = 0;
  for (const item of items) {
    const skuTotal = item?.skuQuantityTotalInfo || item?.skuQuantityInfo || item?.quantityTotalInfo || {};
    todayTotal += normalizeDashboardMetricNumber(item.todaySaleVolume ?? item.todaySalesVolume ?? item.todaySale ?? skuTotal.todaySaleVolume ?? skuTotal.todaySalesVolume);
    sevenDayTotal += normalizeDashboardMetricNumber(item.sevenDaysSaleVolume ?? item.lastSevenDaysSaleVolume ?? item.sevenDaySaleVolume ?? item.saleNum7 ?? skuTotal.lastSevenDaysSaleVolume ?? skuTotal.sevenDaysSaleVolume);
    todayAmount += normalizeDashboardMetricNumber(item.todaySaleAmount ?? item.todaySalesAmount ?? item.todayGmv ?? item.profit1);
    sevenDayAmount += normalizeDashboardMetricNumber(item.sevenDaysSaleAmount ?? item.lastSevenDaysSaleAmount ?? item.sevenDaysGmv ?? item.profit7);
  }
  if (todayTotal || sevenDayTotal || todayAmount || sevenDayAmount) {
    return { success: true, todayTotal, sevenDayTotal, todayAmount, sevenDayAmount, raw: root };
  }
  return null;
}

function extractDashboardTrafficSales(data = {}) {
  const root = data?.result || data?.data || data?.detail || data || {};
  const aggregateTotal = normalizeDashboardMetricNumber(
    root.totalPayGoodsNum
    ?? root.payGoodsNumTotal
    ?? root.payGoodsTotalNum
    ?? root.totalSalesNum
    ?? root.totalSaleNum
    ?? root.totalSalesVolume
    ?? root.salesVolumeTotal
  );
  const aggregateAmount = normalizeDashboardMetricNumber(
    root.totalPayAmount
    ?? root.payAmountTotal
    ?? root.gmvTotal
    ?? root.totalGmv
    ?? root.totalGMV
    ?? root.totalSalesAmount
    ?? root.salesAmountTotal
  );
  if (aggregateTotal || aggregateAmount) {
    return {
      total: aggregateTotal,
      amount: aggregateAmount,
      raw: root,
      itemsCount: 0,
      aggregate: true
    };
  }

  const items = root.list || root.pageItems || root.items || root.dataList || root.records || [];
  if (!Array.isArray(items)) return null;

  let total = 0;
  let amount = 0;
  for (const item of items) {
    total += normalizeDashboardMetricNumber(item?.payGoodsNum ?? item?.payOrderNum ?? item?.buyerNum ?? item?.salesNum);
    amount += normalizeDashboardMetricNumber(
      item?.payAmount
      ?? item?.payAmt
      ?? item?.gmv
      ?? item?.saleAmount
      ?? item?.salesAmount
      ?? item?.transactionAmount
    );
  }

  if (Array.isArray(items)) {
    const totalPages = Number(root.totalPages ?? root.totalPage ?? root.pages ?? root.pageCount ?? 0) || 0;
    const pageNum = Number(root.pageNum ?? root.pageNo ?? root.currentPage ?? root.page ?? 1) || 1;
    const pageSize = Number(root.pageSize ?? root.size ?? items.length) || items.length;
    const totalRecords = Number(root.total ?? root.totalCount ?? root.recordCount ?? 0) || 0;
    return { total, amount, raw: root, itemsCount: items.length, pageNum, pageSize, totalPages, totalRecords };
  }
  return null;
}

async function fetchDashboardTrafficSalesByDimension(timeDimension, auth = {}) {
  const url = 'https://agentseller.temu.com/api/seller/full/flow/analysis/goods/list';
  const pageSize = 100;
  const headers = {
    'Content-Type': 'application/json',
    'mallid': auth?.mallId || state.mallId || '',
    'anti-content': auth?.antiContent || state.antiContent || ''
  };
  let total = 0;
  let amount = 0;
  let pageNum = 1;
  let partial = false;
  let lastPayload = null;
  let lastError = '';

  while (pageNum <= 20) {
    const result = await executeTemuPageRequestVariants([{
      url,
      headers,
      body: {
        pageNum,
        pageSize,
        productIdList: [],
        timeDimension
      },
      extract: extractDashboardTrafficSales
    }], 10000);

    if (!result.success) {
      lastError = result.error || '实时读取销量失败';
      partial = pageNum > 1;
      break;
    }

    const payload = result.payload || {};
    lastPayload = payload;
    if (payload.aggregate) {
      return { success: true, total: Number(payload.total || 0), amount: Number(payload.amount || 0), sourceUrl: url, partial: false };
    }

    total += Number(payload.total || 0);
    amount += Number(payload.amount || 0);

    const totalPages = Number(payload.totalPages || 0);
    const itemsCount = Number(payload.itemsCount || 0);
    const totalRecords = Number(payload.totalRecords || 0);
    const payloadPageSize = Number(payload.pageSize || pageSize) || pageSize;
    const reachedKnownLastPage = totalPages > 0 && pageNum >= totalPages;
    const reachedRecordTotal = totalRecords > 0 && pageNum * payloadPageSize >= totalRecords;
    const noPaginationHint = totalPages <= 0 && totalRecords <= 0;
    if (reachedKnownLastPage || reachedRecordTotal || itemsCount === 0 || (noPaginationHint && itemsCount < payloadPageSize)) break;
    pageNum += 1;
  }

  if (lastPayload) return { success: true, total, amount, sourceUrl: url, partial };
  return { success: false, error: lastError || '实时读取 TEMU 后台首页销量失败' };
}

async function getDashboardHomeSales(auth = {}) {
  const mallId = auth?.mallId || state.mallId || '';
  if (!mallId) return { success: false, error: '请先连接店铺' };

  const [todayResult, sevenDayResult] = await Promise.all([
    fetchDashboardTrafficSalesByDimension(2, auth),
    fetchDashboardTrafficSalesByDimension(3, auth)
  ]);

  if (!todayResult.success && !sevenDayResult.success) {
    return { success: false, error: todayResult.error || sevenDayResult.error || '实时读取 TEMU 后台首页销量失败' };
  }

  const today = todayResult.success ? (todayResult.payload || todayResult) : {};
  const sevenDay = sevenDayResult.success ? (sevenDayResult.payload || sevenDayResult) : {};
  return {
    success: true,
    todayTotal: Number(today.total || 0),
    sevenDayTotal: Number(sevenDay.total || 0),
    todayAmount: Number(today.amount || 0),
    sevenDayAmount: Number(sevenDay.amount || 0),
    sourceUrl: today.sourceUrl || sevenDay.sourceUrl || '',
    source: 'temu-live-traffic',
    partial: !todayResult.success || !sevenDayResult.success,
    error: !todayResult.success ? todayResult.error : (!sevenDayResult.success ? sevenDayResult.error : '')
  };
}
async function fetchCustomizedProductStatusCount(params = {}) {
  const auth = await getAuth();
  try {
    return await temuSellerPost('https://agentseller.temu.com/visage-agent-seller/product/skc/countStatus', {
        mallId: auth?.mallId || '',
        page: params.page || 1,
        pageSize: params.pageSize || 20
      }, auth, 20000);
  } catch (error) {
    console.error('[TEMU运营助手] fetchCustomizedProductStatusCount 出错:', error);
    return { success: false, error: error.message };
  }
}

// ========== 优惠活动报名 API ==========

// 查询可报名的活动列表
async function fetchActivityList(params = {}) {
  const auth = await getAuth();
  try {
    const pickFirst = (...values) => {
      for (const value of values) {
        if (value !== undefined && value !== null && value !== '') return value;
      }
      return '';
    };

    // 尝试多个可能的API端点
    const apiEndpoints = [
      {
        url: 'https://agentseller.temu.com/api/kiana/gamblers/marketing/enroll/activity/list',
        body: { needCanEnrollCnt: true, ...params },
        checkSuccess: (d) => d.success
      },
      {
        url: 'https://agentseller.temu.com/api/kiana/gamblers/marketing/activity/list',
        body: { pageNo: 1, pageSize: 50 },
        checkSuccess: (d) => d.success || d.code === 0
      },
      {
        url: 'https://agentseller.temu.com/api/kiana/gamblers/marketing/enroll/query/activity/list',
        body: { needCanEnrollCnt: true },
        checkSuccess: (d) => d.success
      }
    ];

    let lastError = '';
    for (const endpoint of apiEndpoints) {
      try {
        const data = await temuSellerPost(endpoint.url, endpoint.body, auth, 25000);
        console.log(`[TEMU运营助手] 活动列表(${endpoint.url.substring(endpoint.url.lastIndexOf('/') + 1)})响应:`, JSON.stringify(data).substring(0, 500));

        const result = data.result || data.data || data.detail;
        const activityList = result?.list || result?.activityList || result?.items || (Array.isArray(result) ? result : []);

        if (activityList.length > 0 || endpoint.checkSuccess(data)) {
          // 展开专题活动的 thematicList，过滤 activityType 51/52/53
          let allActivities = [];
          for (const act of activityList) {
            const actType = act.activityType || act.type || act.activity_type || '';
            // 过滤掉不需要的活动类型
            if (['51', '52', '53'].includes(String(actType))) continue;
            // 有 thematicList 的专题活动，展开子活动
            const thematic = act.thematicList || act.thematic_list || [];
            if (thematic.length > 0) {
              for (const sub of thematic) {
                allActivities.push({
                  activityId: sub.activityId || sub.id || sub.activity_id,
                  activityThematicId: sub.activityThematicId || sub.activityThematic || sub.thematicId || act.activityThematicId || act.activityThematic || act.thematicId || '',
                  activityName: pickFirst(sub.activityThematicName, sub.activityName, sub.activityThemeName, sub.name, sub.activity_name, sub.title, act.activityThematicName, act.activityName, act.name, act.title, '未命名活动'),
                  activityContent: pickFirst(sub.activityThematicContent, sub.activityContent, sub.content, sub.desc, sub.description, act.activityThematicContent, act.activityContent, act.content, ''),
                  startTime: pickFirst(sub.sessionStartTime, sub.startTime, sub.start_time, sub.enrollStartAt, sub.enrollStartTime, sub.enroll_start_time, act.sessionStartTime, act.startTime, act.start_time, ''),
                  endTime: pickFirst(sub.sessionEndTime, sub.endTime, sub.end_time, sub.enrollDeadLine, sub.enrollEndTime, sub.enroll_end_time, act.sessionEndTime, act.endTime, act.end_time, ''),
                  enrollStartTime: pickFirst(sub.enrollStartAt, sub.enrollStartTime, sub.enroll_start_time, '', act.enrollStartAt, act.enrollStartTime, act.enroll_start_time),
                  enrollEndTime: pickFirst(sub.enrollDeadLine, sub.enrollEndTime, sub.enroll_end_time, '', act.enrollDeadLine, act.enrollEndTime, act.enroll_end_time),
                  status: sub.status || sub.activityStatus || 0,
                  canEnrollCnt: sub.canEnrollCnt ?? sub.canEnrollCount ?? sub.canEnrollTotal ?? act.canEnrollCnt ?? act.canEnrollCount ?? act.canEnrollTotal ?? 0,
                  enrolledCount: sub.enrolledCount ?? sub.enrolled_cnt ?? sub.enrollCnt ?? sub.enrollCount ?? sub.participantCount ?? sub.registeredCount ?? null,
                  enrollStatus: sub.enrollStatus || sub.enroll_status || 0,
                  discountRate: pickFirst(sub.discountRate, sub.discount, sub.discountRateStr, sub.discountThreshold, sub.discountRatio, sub.ratio, act.discountRate, act.discount, act.discountRateStr, act.discountThreshold, ''),
                  activityType: sub.activityType || sub.type || sub.activity_type || actType,
                  desc: sub.desc || sub.description || sub.remark || '',
                  enrollUrl: sub.enrollUrl || sub.enroll_url || act.enrollUrl || ''
                });
              }
            } else {
              allActivities.push({
                activityId: act.activityId || act.id || act.activity_id,
                activityThematicId: act.activityThematicId || act.activityThematic || act.thematicId || '',
                activityName: pickFirst(act.activityName, act.activityThematicName, act.activityThemeName, act.name, act.activity_name, act.title, '未命名活动'),
                activityContent: pickFirst(act.activityContent, act.activityThematicContent, act.content, act.desc, act.description, ''),
                startTime: pickFirst(act.sessionStartTime, act.startTime, act.start_time, act.enrollStartAt, act.enrollStartTime, act.enroll_start_time, ''),
                endTime: pickFirst(act.sessionEndTime, act.endTime, act.end_time, act.enrollDeadLine, act.enrollEndTime, act.enroll_end_time, ''),
                enrollStartTime: pickFirst(act.enrollStartAt, act.enrollStartTime, act.enroll_start_time, ''),
                enrollEndTime: pickFirst(act.enrollDeadLine, act.enrollEndTime, act.enroll_end_time, ''),
                status: act.status || act.activityStatus || 0,
                canEnrollCnt: act.canEnrollCnt ?? act.canEnrollCount ?? act.canEnrollTotal ?? 0,
                enrolledCount: act.enrolledCount ?? act.enrolled_cnt ?? act.enrollCnt ?? act.enrollCount ?? act.participantCount ?? act.registeredCount ?? null,
                enrollStatus: act.enrollStatus || act.enroll_status || 0,
                discountRate: pickFirst(act.discountRate, act.discount, act.discountRateStr, act.discountThreshold, act.discountRatio, act.ratio, ''),
                activityType: actType,
                desc: act.desc || act.description || act.remark || '',
                enrollUrl: act.enrollUrl || act.enroll_url || ''
              });
            }
          }
          return {
            success: true,
            activities: allActivities
          };
        }
        lastError = data.error_msg || data.message || '返回数据为空';
      } catch (e) {
        console.warn(`[TEMU运营助手] API ${endpoint.url} 失败:`, e.message);
        lastError = e.message;
      }
    }

    return { success: false, error: '所有活动API均失败: ' + lastError };
  } catch (error) {
    console.error('[TEMU运营助手] fetchActivityList 出错:', error);
    return { success: false, error: error.message };
  }
}

// 滚动匹配活动商品（查看哪些商品可参加活动）
async function scrollMatchActivity(params = {}) {
  const auth = await getAuth();
  try {
    const data = await temuSellerPost('https://agentseller.temu.com/api/kiana/gamblers/marketing/enroll/scroll/match', params, auth, 25000);
    console.log('[TEMU运营助手] 活动匹配响应:', JSON.stringify(data).substring(0, 500));

    const result = data?.result ?? data?.data ?? data?.detail ?? data;
    const success = data?.success === true || data?.code === 0 || data?.code === '0';
    const matchList = result?.matchList || result?.products || result?.list || result?.items || result?.productList || [];

    return {
      ...data,
      success: success || (Array.isArray(matchList) && matchList.length > 0),
      result,
      matchList,
      error_msg: data?.error_msg || data?.message || data?.msg || ''
    };
  } catch (error) {
    console.error('[TEMU运营助手] scrollMatchActivity 出错:', error);
    return { success: false, error: error.message };
  }
}

// 提交活动报名
async function enrollActivity(params = {}) {
  const auth = await getAuth();
  try {
    const payload = Array.isArray(params.productList) && params.productList.length > 0
      ? {
          activityType: params.activityType,
          activityThematicId: params.activityThematicId,
          productList: params.productList
        }
      : {
          activityType: params.activityType,
          activityThematicId: params.activityThematicId,
          productList: Array.isArray(params.productIdList)
            ? params.productIdList.map((productId) => ({
                productId,
                activityStock: 0,
                skcList: [],
                sessionIds: [],
                activityEnrollPrivilegeType: 0
              }))
            : []
        };

    const data = await temuSellerPost('https://agentseller.temu.com/api/kiana/gamblers/marketing/enroll/submit', payload, auth, 60000);
    console.log('[TEMU运营助手] 活动报名响应:', JSON.stringify(data).substring(0, 500));

    return {
      ...data,
      success: data?.success === true || data?.code === 0 || data?.code === '0',
      result: data?.result ?? data?.data ?? data?.detail ?? data,
      error_msg: getTemuActivityApiMessage(data, ''),
      requestSummary: {
        activityType: payload.activityType || '',
        activityThematicId: payload.activityThematicId || '',
        productCount: payload.productList.length,
        firstProductId: payload.productList[0]?.productId || '',
        firstSkcCount: Array.isArray(payload.productList[0]?.skcList) ? payload.productList[0].skcList.length : 0
      }
    };
  } catch (error) {
    console.error('[TEMU运营助手] enrollActivity 出错:', error);
    return { success: false, error: error.message };
  }
}

// ========== 资质批量上传 API ==========

function isQualificationSuccess(payload) {
  return !!(payload?.success || payload?.code === 0 || payload?.result?.success || payload?.detail?.success);
}

function getQualificationApiMessage(data = {}, fallback = 'TEMU 资质接口请求失败') {
  const message = getTemuApiMessage(data, fallback);
  const code = data?.errorCode
    ?? data?.error_code
    ?? data?.code
    ?? data?.result?.errorCode
    ?? data?.result?.error_code
    ?? data?.result?.code
    ?? data?.detail?.errorCode
    ?? data?.detail?.error_code
    ?? data?.detail?.code;
  if (code !== undefined && code !== null && String(code) !== '' && Number(code) !== 0) {
    return `${message}（code: ${code}）`;
  }
  return message;
}

function getQualificationApiCode(data = {}) {
  return data?.errorCode
    ?? data?.error_code
    ?? data?.code
    ?? data?.result?.errorCode
    ?? data?.result?.error_code
    ?? data?.result?.code
    ?? data?.detail?.errorCode
    ?? data?.detail?.error_code
    ?? data?.detail?.code
    ?? data?.raw?.errorCode
    ?? data?.raw?.error_code
    ?? data?.raw?.code
    ?? data?.raw?.result?.errorCode
    ?? data?.raw?.result?.error_code
    ?? data?.raw?.result?.code
    ?? data?.raw?.detail?.errorCode
    ?? data?.raw?.detail?.error_code
    ?? data?.raw?.detail?.code;
}

function isQualificationTransientServerError(data = {}) {
  const code = String(getQualificationApiCode(data) ?? '').trim();
  const message = [
    data?.error,
    data?.message,
    data?.msg,
    data?.errorMessage,
    data?.raw?.error,
    data?.raw?.message,
    data?.raw?.msg,
    data?.raw?.errorMessage,
    getQualificationMessageDeep(data, ''),
    getQualificationApiMessage(data, '')
  ].map(value => String(value || '')).join(' ');
  return code === '1000002' || /1000002|服务器开小差|server.*busy|temporar|稍后|重试/i.test(message);
}

async function uploadQualificationBatchOneByOne(params = {}, productIds = [], reason = '') {
  const requestedProductIds = Array.from(new Set((productIds || []).map(id => String(id || '').trim()).filter(Boolean)));
  const successProductIds = [];
  const failedProductIds = [];
  const skippedProductIds = [];
  const perProductResults = [];
  const maxAttempts = Number(params.__singleSpuMaxAttempts || 4);
  const retryDelays = [0, 3000, 6500, 11000];

  for (let index = 0; index < requestedProductIds.length; index += 1) {
    const productId = requestedProductIds[index];
    if (index > 0) await sleep(1800);
    let result = null;
    const attempts = [];
    for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
      const delay = retryDelays[Math.min(attempt, retryDelays.length - 1)] || 0;
      if (delay > 0) await sleep(delay);
      result = await uploadQualificationBatch({
        ...params,
        productId,
        productIds: [productId],
        __singleSpuRetry: true
      });
      attempts.push({
        attempt: attempt + 1,
        success: !!result?.success,
        error: result?.error || result?.message || '',
        code: getQualificationApiCode(result)
      });
      if (result?.success || !isQualificationTransientServerError(result)) break;
    }
    perProductResults.push({ productId, attempts, result });
    if (result?.success) {
      const ids = Array.isArray(result.verifiedProductIds) && result.verifiedProductIds.length
        ? result.verifiedProductIds
        : (Array.isArray(result.productIds) && result.productIds.length ? result.productIds : [productId]);
      ids.map(id => String(id || '').trim()).filter(Boolean).forEach(id => {
        if (!successProductIds.includes(id)) successProductIds.push(id);
      });
      (result.skippedProductIds || []).map(id => String(id || '').trim()).filter(Boolean).forEach(id => {
        if (!skippedProductIds.includes(id)) skippedProductIds.push(id);
      });
    } else {
      failedProductIds.push(productId);
    }
  }

  return {
    success: successProductIds.length > 0,
    warning: reason ? `官方批量接口临时失败，已自动拆分为单 SPU 重试：${reason}` : '官方批量接口临时失败，已自动拆分为单 SPU 重试',
    error: successProductIds.length
      ? ''
      : `官方批量接口临时失败，单 SPU 重试仍失败：${perProductResults.map(item => `${item.productId} ${item.result?.error || '失败'}`).join('；')}`,
    productIds: successProductIds,
    verifiedProductIds: successProductIds,
    pendingProductIds: failedProductIds,
    requestedProductIds,
    skippedProductIds: Array.from(new Set([...skippedProductIds, ...failedProductIds])),
    perProductResults
  };
}

function normalizeQualificationFileList(list, type) {
  return (Array.isArray(list) ? list : []).map((item, index) => {
    const fileName = item?.file_name || item?.fileName || item?.name || item?.title || `文件${index + 1}`;
    const originalFileUrl = item?.original_file_url || item?.originalFileUrl || item?.originFileUrl || item?.origin_file_url || '';
    const signedFileUrl = item?.file_url || item?.fileUrl || item?.url || '';
    const fileUrl = originalFileUrl || signedFileUrl;
    return {
      fileName,
      fileUrl,
      originalFileUrl,
      signedFileUrl,
      type: String(item?.type || type || ''),
      raw: item
    };
  }).filter(file => file.fileName || file.fileUrl);
}

function getQualificationRoot(payload = {}) {
  return payload?.result || payload?.data || payload?.detail || payload || {};
}

function getQualificationMessageDeep(data = {}, fallback = 'TEMU 资质接口请求失败') {
  const candidates = [
    data?.error_msg,
    data?.errorMsg,
    data?.message,
    data?.msg,
    data?.errorMessage,
    data?.result?.error_msg,
    data?.result?.errorMsg,
    data?.result?.message,
    data?.result?.msg,
    data?.detail?.error_msg,
    data?.detail?.errorMsg,
    data?.detail?.message,
    data?.detail?.msg
  ];
  for (const value of candidates) {
    const text = String(value || '').trim();
    if (text) return text;
  }
  return fallback;
}

function normalizeQualificationSubmissionFile(item = {}, fallbackType = '') {
  const raw = item?.raw && typeof item.raw === 'object' ? item.raw : item;
  const fileName = item?.fileName || item?.file_name || item?.name || raw?.file_name || raw?.fileName || raw?.name || '';
  const originalFileUrl = item?.originalFileUrl
    || item?.original_file_url
    || raw?.original_file_url
    || raw?.originalFileUrl
    || raw?.originFileUrl
    || raw?.origin_file_url
    || '';
  const fileUrl = originalFileUrl
    || item?.fileUrl
    || item?.file_url
    || item?.url
    || raw?.file_url
    || raw?.fileUrl
    || raw?.url
    || '';
  if (!fileName && !fileUrl) return null;
  return {
    fileName: String(fileName || '文件'),
    fileUrl: String(fileUrl || ''),
    type: String(item?.type || raw?.type || fallbackType || '')
  };
}

function normalizeQualificationSubmissionFiles(list = [], fallbackType = '') {
  return (Array.isArray(list) ? list : [])
    .map(item => normalizeQualificationSubmissionFile(item, fallbackType))
    .filter(item => item && item.fileUrl);
}

function normalizeQualificationMultiLangFileMap(value = null) {
  if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
  const result = {};
  for (const [lang, files] of Object.entries(value)) {
    const normalizedFiles = normalizeQualificationSubmissionFiles(files, '');
    if (normalizedFiles.length) result[lang] = normalizedFiles.map(file => ({
      fileName: file.fileName,
      fileUrl: file.fileUrl
    }));
  }
  return Object.keys(result).length ? result : null;
}

function normalizeQualificationDocPdfContentReq(value = null, selectedCheckItems = null) {
  if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
  const rawItems = value.contentItemList || value.content_item_list || [];
  const contentItemList = (Array.isArray(rawItems) ? rawItems : []).map(item => {
    const vid = item?.vid;
    const contentList = item?.contentList || item?.content_list || null;
    if (Array.isArray(contentList) && contentList.length) {
      return { vid, contentList };
    }
    const rawFileReqs = item?.fileContentReqs || item?.file_content_reqs || item?.file_content_req_list || [];
    const fileContentReqs = (Array.isArray(rawFileReqs) ? rawFileReqs : [])
      .map(file => {
        const fileUrl = file?.originalFileUrl
          || file?.original_file_url
          || file?.fileUrl
          || file?.file_url
          || file?.url
          || '';
        return fileUrl ? { fileUrl } : null;
      })
      .filter(Boolean);
    return fileContentReqs.length ? { vid, fileContentReqs } : null;
  }).filter(Boolean);
  if (!contentItemList.length) return null;
  const doc = {
    contentItemList,
    uniqueKey: value.uniqueKey || value.unique_key,
    needSimple: value.needSimple ?? value.need_simple
  };
  const selectVids = value.selectVids || value.select_vids || selectedCheckItems?.[1000100015];
  if (selectVids) doc.selectVids = selectVids;
  const simpleCertIds = value.simpleCertIds || value.simple_cert_ids;
  if (Array.isArray(simpleCertIds) && simpleCertIds.length) doc.simpleCertIds = simpleCertIds;
  const signatureItem = contentItemList.find(item => Number(item.vid) === 1000139783);
  const signatureUrl = value.signatureUrl || value.signature_url || signatureItem?.originalFileUrl;
  if (signatureUrl) doc.signatureUrl = signatureUrl;
  return doc;
}

function buildQualificationExtendedInfo(certInfoResp = {}, detail = {}) {
  const root = getQualificationRoot(certInfoResp);
  const source = root?.extendedInfo || root?.extended_info || detail?.extendedInfo || detail?.extended_info || {};
  const pick = (camelKey, snakeKey) => {
    if (Object.prototype.hasOwnProperty.call(source, snakeKey)) return source[snakeKey];
    if (Object.prototype.hasOwnProperty.call(source, camelKey)) return source[camelKey];
    if (Object.prototype.hasOwnProperty.call(root, snakeKey)) return root[snakeKey];
    if (Object.prototype.hasOwnProperty.call(root, camelKey)) return root[camelKey];
    return undefined;
  };
  const extendedInfo = {
    hitUploadGray: pick('hitUploadGray', 'hit_upload_gray'),
    hitNewDocGray: pick('hitNewDocGray', 'hit_new_doc_gray'),
    hitFrDocGray: pick('hitFrDocGray', 'hit_fr_doc_gray'),
    hitUploadMultiAuthCodesGray: pick('hitUploadMultiAuthCodesGray', 'hit_upload_multi_auth_codes_gray'),
    hitUploadMultiLanguageGary: pick('hitUploadMultiLanguageGary', 'hit_upload_multi_language_gary'),
    hitCertFileRecognizeGray: pick('hitCertFileRecognizeGray', 'hit_cert_file_recognize_gray'),
    hitGenerateDocPdfGary: pick('hitGenerateDocPdfGary', 'hit_generate_doc_pdf_gary')
  };
  const cleaned = Object.fromEntries(Object.entries(extendedInfo).filter(([, value]) => value !== undefined && value !== null));
  return Object.keys(cleaned).length ? cleaned : null;
}

function buildQualificationSubmitFiles(detail = {}, params = {}) {
  const certInfo = detail?.raw?.product_cert_info || detail?.raw || {};
  const inspectReportFiles = normalizeQualificationSubmissionFiles(
    detail.inspectReportFiles || certInfo.inspect_report_files || [],
    '1'
  );
  const productCertFiles = normalizeQualificationSubmissionFiles(
    detail.productCertFiles || certInfo.product_cert_files || [],
    '2'
  );
  if (!inspectReportFiles.length && !productCertFiles.length) {
    const files = normalizeQualificationSubmissionFiles(params.files || [], '');
    return {
      inspectReportFiles: files.filter(file => file.type !== '2'),
      productCertFiles: files.filter(file => file.type === '2')
    };
  }
  return { inspectReportFiles, productCertFiles };
}

function buildQualificationPoolKey(item = {}) {
  const baseId = String(item?.spuId || item?.goodsId || item?.catId || item?.spuName || '');
  const certList = Array.isArray(item?.waitTaskList) ? item.waitTaskList : [];
  const certKey = certList.map(cert => [
    cert?.task_id || cert?.taskId || '',
    cert?.certType || cert?.task_type || '',
    cert?.certName || cert?.showName || cert?.task_name || '',
    cert?.status ?? cert?.uploadStatus ?? cert?.upload_status ?? cert?.task_status ?? ''
  ].join(':')).join('|');
  return `${baseId}::${certKey}`;
}

function extractQualificationCategory(base = {}, item = {}) {
  return String(
    base?.leaf_category_name ||
    base?.leafCategoryName ||
    base?.category_name ||
    base?.categoryName ||
    base?.cat_name ||
    base?.catName ||
    base?.category ||
    item?.leaf_category_name ||
    item?.leafCategoryName ||
    item?.category_name ||
    item?.categoryName ||
    item?.cat_name ||
    item?.catName ||
    item?.category ||
    ''
  ).trim();
}

function pickFirstQualificationValue(...values) {
  for (const value of values) {
    if (value === undefined || value === null) continue;
    if (typeof value === 'string') {
      const text = value.trim();
      if (text) return text;
      continue;
    }
    if (typeof value === 'number' && Number.isFinite(value)) return value;
    if (typeof value === 'boolean') return value;
  }
  return undefined;
}

function getQualificationTaskCertType(task = {}) {
  if (!task || typeof task !== 'object') return '';
  return String(pickFirstQualificationValue(
    task?.certType,
    task?.cert_type,
    task?.task_type,
    task?.taskType,
    task?.taskTypeCode,
    task?.cert_type_code,
    task?.certTypeCode,
    task?.type,
    task?.product_cert_type,
    task?.productCertType,
    task?.raw?.cert_type,
    task?.raw?.certType,
    task?.raw?.task_type,
    task?.raw?.taskType,
    task?.raw?.taskTypeCode,
    task?.raw?.cert_type_code,
    task?.raw?.certTypeCode,
    task?.raw?.type,
    task?.raw?.product_cert_type,
    task?.raw?.productCertType
  ) || '').trim();
}

function getQualificationFailureText(task = {}) {
  if (!task || typeof task !== 'object') return '';
  return String(
    pickFirstQualificationValue(
      task.raw?.failure_reason,
      task.raw?.error_message,
      task.raw?.error_msg,
      task.raw?.reject_reason,
      task.raw?.rejectReason,
      task.failure_reason,
      task.error_message,
      task.errorMsg,
      task.reject_reason,
      task.rejectReason
    ) ?? ''
  ).trim();
}

function getQualificationExplicitStatusText(task = {}) {
  if (!task || typeof task !== 'object') return '';
  const rawText = pickFirstQualificationValue(
    task.statusText,
    task.statusLabel,
    task.status_name,
    task.statusName,
    task.statusDesc,
    task.status_desc,
    task.uploadStatusText,
    task.upload_status_text,
    task.uploadStatusLabel,
    task.upload_status_label,
    task.uploadStatusDesc,
    task.upload_status_desc,
    task.auditStatusText,
    task.audit_status_text,
    task.auditStatusDesc,
    task.audit_status_desc,
    task.raw?.status_text,
    task.raw?.statusText,
    task.raw?.status_name,
    task.raw?.statusName,
    task.raw?.status_desc,
    task.raw?.statusDesc,
    task.raw?.upload_status_text,
    task.raw?.uploadStatusText,
    task.raw?.upload_status_name,
    task.raw?.uploadStatusName,
    task.raw?.upload_status_desc,
    task.raw?.uploadStatusDesc,
    task.raw?.audit_status_text,
    task.raw?.auditStatusText,
    task.raw?.audit_status_name,
    task.raw?.auditStatusName,
    task.raw?.audit_status_desc,
    task.raw?.auditStatusDesc,
    task.raw?.display_status,
    task.raw?.displayStatus,
    task.raw?.process_status,
    task.raw?.processStatus
  );
  if (typeof rawText !== 'string') return '';
  const text = rawText.trim();
  if (!text || /^\d+$/.test(text) || /^状态(?:码)?\s*\d+$/i.test(text)) return '';
  return text;
}

function getQualificationRawStatusCode(task = {}) {
  if (!task || typeof task !== 'object') return undefined;
  return pickFirstQualificationValue(
    task.statusCode,
    task.uploadStatus,
    task.status,
    task.upload_status,
    task.task_status,
    task.raw?.status_code,
    task.raw?.statusCode,
    task.raw?.upload_status_code,
    task.raw?.uploadStatusCode,
    task.raw?.task_status_code,
    task.raw?.taskStatusCode,
    task.raw?.upload_status,
    task.raw?.uploadStatus,
    task.raw?.status,
    task.raw?.task_status
  );
}

function hasQualificationReturnedFiles(task = {}) {
  if (!task || typeof task !== 'object') return false;
  const raw = task.raw || {};
  const listFields = [
    task.cert_file_list,
    task.certFileList,
    task.product_cert_files,
    task.productCertFiles,
    task.inspect_report_files,
    task.inspectReportFiles,
    raw.cert_file_list,
    raw.certFileList,
    raw.product_cert_files,
    raw.productCertFiles,
    raw.inspect_report_files,
    raw.inspectReportFiles
  ];
  if (listFields.some(list => Array.isArray(list) && list.length > 0)) return true;
  const mapFields = [
    task.multi_lang_product_cert_file_map,
    task.multiLangProductCertFileMap,
    task.doc_pdf_content_req,
    task.docPdfContentReq,
    raw.multi_lang_product_cert_file_map,
    raw.multiLangProductCertFileMap,
    raw.doc_pdf_content_req,
    raw.docPdfContentReq
  ];
  return mapFields.some(value => value && typeof value === 'object' && Object.keys(value).length > 0);
}

function resolveQualificationStateFromText(text = '') {
  const normalized = String(text || '').trim().toLowerCase();
  if (!normalized) return 'unknown';
  if (/失败|驳回|拒绝|不通过|failed|rejected|refused|error|not\s*pass|declined/.test(text) || /failed|rejected|refused|error|not\s*pass|declined/.test(normalized)) return 'failed';
  if (/上传完成|已上传|已完成|完成|通过|审核通过|成功|uploaded|passed|success|done|approved|complete/.test(text) || /uploaded|passed|success|done|approved|complete/.test(normalized)) return 'completed';
  if (/审核中|待审|待审核|审核|review|processing|in\s*review|reviewing|pending\s*review/.test(text) || /review|processing|in\s*review|reviewing|pending\s*review/.test(normalized)) return 'reviewing';
  if (/待上传|未上传|待处理|待补充|未开始|缺失|缺少|not\s*started|to\s*be\s*uploaded|waiting|to\s*upload|missing|required/.test(text) || /not\s*started|to\s*be\s*uploaded|waiting|to\s*upload|missing|required/.test(normalized)) return 'pending';
  if (/废弃|失效|作废|expired|abandoned/.test(text) || /expired|abandoned/.test(normalized)) return 'closed';
  return 'unknown';
}

function getQualificationStatusMetaFromCode(code) {
  const statusNum = Number(code);
  if (!Number.isFinite(statusNum)) return null;
  const detail = `TEMU 状态码 ${statusNum}`;
  if (statusNum === 1) return { state: 'pending', label: '待上传', detail };
  if (statusNum === 6) return { state: 'completed', label: '上传成功', detail };
  return null;
}

function getQualificationTaskState(task = {}) {
  const failureText = getQualificationFailureText(task);
  if (failureText) return { state: 'failed', label: '失败/驳回', detail: failureText };

  const statusText = getQualificationExplicitStatusText(task);
  if (statusText) {
    const state = resolveQualificationStateFromText(statusText);
    if (state === 'unknown') {
      const codedMeta = getQualificationStatusMetaFromCode(getQualificationRawStatusCode(task));
      if (codedMeta) return codedMeta;
    }
    return {
      state,
      label: statusText,
      detail: ''
    };
  }

  const rawStatus = getQualificationRawStatusCode(task);
  const statusNum = Number(rawStatus);
  const statusLabel = Number.isFinite(statusNum) ? `状态码 ${statusNum}` : '';

  if (hasQualificationReturnedFiles(task)) {
    return {
      state: 'completed',
      label: '有资质文件',
      detail: statusLabel
    };
  }

  const codedMeta = getQualificationStatusMetaFromCode(rawStatus);
  if (codedMeta) return codedMeta;

  if (statusLabel) {
    return { state: 'unknown', label: '状态待确认', detail: `TEMU ${statusLabel}` };
  }
  return { state: 'unknown', label: '状态待确认', detail: '' };
}

function isQualificationTaskCompleted(task = {}) {
  return getQualificationTaskState(task).state === 'completed';
}

function isQualificationTaskUploadRequired(task = {}) {
  const state = getQualificationTaskState(task).state;
  return state === 'pending' || state === 'failed';
}

function normalizeQualificationCertEntry(cert = {}, index = 0, base = {}) {
  const certType = String(pickFirstQualificationValue(
    cert?.cert_type,
    cert?.certType,
    cert?.task_type,
    cert?.taskType,
    cert?.taskTypeCode,
    cert?.cert_type_code,
    cert?.certTypeCode,
    cert?.type,
    cert?.product_cert_type,
    cert?.productCertType
  ) || '').trim();
  const certName = String(pickFirstQualificationValue(
    cert?.cert_name,
    cert?.certName,
    cert?.show_name,
    cert?.showName,
    cert?.task_name,
    cert?.taskName,
    cert?.name,
    cert?.display_name,
    cert?.displayName
  ) || '').trim();
  const rawNumericStatus = pickFirstQualificationValue(
    cert?.upload_status,
    cert?.uploadStatus,
    cert?.status,
    cert?.task_status,
    cert?.audit_status,
    cert?.auditStatus,
    cert?.status_code,
    cert?.statusCode,
    cert?.upload_status_code,
    cert?.uploadStatusCode,
    cert?.task_status_code,
    cert?.taskStatusCode
  );
  const rawTextStatus = pickFirstQualificationValue(
    cert?.status_text,
    cert?.statusText,
    cert?.status_name,
    cert?.statusName,
    cert?.status_desc,
    cert?.statusDesc,
    cert?.upload_status_text,
    cert?.uploadStatusText,
    cert?.upload_status_name,
    cert?.uploadStatusName,
    cert?.upload_status_desc,
    cert?.uploadStatusDesc,
    cert?.audit_status_text,
    cert?.auditStatusText,
    cert?.audit_status_name,
    cert?.auditStatusName,
    cert?.audit_status_desc,
    cert?.auditStatusDesc,
    cert?.display_status,
    cert?.displayStatus,
    cert?.process_status,
    cert?.processStatus
  );
  const statusRaw = rawTextStatus ?? rawNumericStatus;
  const statusCode = Number.isFinite(Number(statusRaw)) ? Number(statusRaw) : null;
  const statusText = pickFirstQualificationValue(
    cert?.reject_reason,
    cert?.rejectReason,
    cert?.failure_reason,
    cert?.failureReason,
    cert?.error_message,
    cert?.errorMessage,
    cert?.error_msg,
    cert?.errorMsg,
    cert?.status_text,
    cert?.statusText,
    cert?.status_name,
    cert?.statusName,
    cert?.status_desc,
    cert?.statusDesc,
    cert?.upload_status_text,
    cert?.uploadStatusText,
    cert?.upload_status_name,
    cert?.uploadStatusName,
    cert?.upload_status_desc,
    cert?.uploadStatusDesc,
    cert?.audit_status_text,
    cert?.auditStatusText,
    cert?.audit_status_name,
    cert?.auditStatusName,
    cert?.audit_status_desc,
    cert?.auditStatusDesc,
    cert?.display_status,
    cert?.displayStatus,
    cert?.process_status,
    cert?.processStatus
  ) || '';
  return {
    task_id: cert?.task_id || cert?.taskId || cert?.id || `${base?.product_id || base?.spu_id || 'cert'}-${index}`,
    task_type: certType,
    task_name: certName || certType || `资质${index + 1}`,
    certType,
    certName: certName || certType || `资质${index + 1}`,
    showName: cert?.show_name || cert?.showName || certName || certType || `资质${index + 1}`,
    productId: String(cert?.product_id || cert?.productId || base?.product_id || base?.productId || base?.spu_id || base?.spuId || '').trim(),
    goodsId: String(cert?.goods_id || cert?.goodsId || base?.goods_id || base?.goodsId || '').trim(),
    fileUploadType: cert?.file_upload_type || cert?.fileUploadType || null,
    selectedCheckItems: cert?.selected_check_items || cert?.selectedCheckItems || null,
    status: statusText,
    statusText,
    statusCode,
    statusRaw,
    uploadStatus: statusCode,
    upload_status: statusRaw,
    is_not_required: !!cert?.is_not_required || !!cert?.optional,
    raw: {
      ...cert,
      cert_file_list: cert?.cert_file_list,
      certFileList: cert?.certFileList,
      product_cert_files: cert?.product_cert_files,
      productCertFiles: cert?.productCertFiles,
      inspect_report_files: cert?.inspect_report_files,
      inspectReportFiles: cert?.inspectReportFiles,
      multi_lang_product_cert_file_map: cert?.multi_lang_product_cert_file_map,
      multiLangProductCertFileMap: cert?.multiLangProductCertFileMap,
      doc_pdf_content_req: cert?.doc_pdf_content_req,
      docPdfContentReq: cert?.docPdfContentReq,
      failure_reason: cert?.failure_reason,
      error_message: cert?.error_message,
      error_msg: cert?.error_msg,
      reject_reason: cert?.reject_reason,
      rejectReason: cert?.rejectReason,
      cert_type: cert?.cert_type,
      certType: cert?.certType,
      task_type: cert?.task_type,
      taskType: cert?.taskType,
      taskTypeCode: cert?.taskTypeCode,
      audit_status: cert?.audit_status,
      auditStatus: cert?.auditStatus,
      upload_status: cert?.upload_status,
      uploadStatus: cert?.uploadStatus,
      status: cert?.status
    }
  };
}

function extractQualificationCertEntries(source, base = {}) {
  const result = [];
  const visited = new Set();
  const pushCert = (cert) => {
    if (!cert || typeof cert !== 'object') return;
    const normalized = normalizeQualificationCertEntry(cert, result.length, base);
    const key = [
      normalized.task_id || '',
      normalized.certType || '',
      normalized.certName || '',
      normalized.statusCode ?? normalized.statusRaw ?? normalized.status ?? ''
    ].join('::');
    if (visited.has(key)) return;
    visited.add(key);
    result.push(normalized);
  };
  const walk = (node) => {
    if (!node) return;
    if (Array.isArray(node)) {
      node.forEach(walk);
      return;
    }
    if (typeof node !== 'object') return;

    const hasCertShape = !!(
      node.cert_name || node.show_name || node.task_name || node.name ||
      node.cert_type || node.task_type || node.type ||
      node.task_id || node.certType || node.taskType || node.upload_status !== undefined ||
      node.uploadStatus !== undefined || node.status !== undefined || node.task_status !== undefined
    );
    if (hasCertShape) {
      pushCert(node);
    }

    const nestedKeys = [
      'product_cert_info_list',
      'productCertInfoList',
      'product_cert_list',
      'productCertList',
      'wait_task_dtolist',
      'waitTaskList',
      'cert_list',
      'certList',
      'items',
      'list',
      'data',
      'result'
    ];
    for (const key of nestedKeys) {
      if (node[key] && node[key] !== node) walk(node[key]);
    }
  };
  walk(source);
  return result;
}

function normalizeQualificationPoolItem(item = {}) {
  const base = item.product_base_info || item.productBaseInfo || item.base_info || item.baseInfo || item;
  const certList = item.product_cert_info_list || item.productCertInfoList || item.product_cert_list || item.productCertList || item.wait_task_dtolist || item.waitTaskList || [];
  const waitTaskList = extractQualificationCertEntries(certList, base);

  const pendingTasks = waitTaskList.filter(isQualificationTaskUploadRequired);
  const reviewingTasks = waitTaskList.filter(t => getQualificationTaskState(t).state === 'reviewing');
  const unresolvedTasks = waitTaskList.filter(t => getQualificationTaskState(t).state === 'unknown');
  const productId = base?.product_id || base?.productId || base?.spu_id || base?.spuId || item.product_id || item.productId || item.spu_id || item.spuId || '';
  const goodsId = base?.goods_id || base?.goodsId || item.goods_id || item.goodsId || '';
  const categoryName = extractQualificationCategory(base, item);
  const status = !waitTaskList.length
    ? 'unknown'
    : (pendingTasks.length > 0
      ? 'pending'
      : (reviewingTasks.length > 0 ? 'reviewing' : (unresolvedTasks.length > 0 ? 'unknown' : 'completed')));
  const statusDetail = !waitTaskList.length
    ? '未返回资质任务'
    : (pendingTasks.length > 0
      ? `需处理 ${pendingTasks.length} 项`
      : (reviewingTasks.length > 0 ? `审核中 ${reviewingTasks.length} 项` : (unresolvedTasks.length > 0 ? `待确认 ${unresolvedTasks.length} 项` : '已返回完成状态')));

  return {
    spuId: productId ? String(productId) : '',
    goodsId: goodsId ? String(goodsId) : '',
    catId: String(base?.cat_id || base?.catId || item.cat_id || item.catId || ''),
    categoryName,
    spuName: base?.product_name || base?.productName || base?.spu_name || base?.spuName || item.product_name || item.productName || item.spu_name || item.spuName || '',
    mainImage: base?.main_image_url || base?.mainImage || item.main_image_url || item.main_image || item.image_url || item.goods_img || '',
    status,
    statusDetail,
    waitTaskList,
    pendingCertTypes: pendingTasks.map(getQualificationTaskCertType).filter(Boolean),
    pendingCertNames: pendingTasks.map(t => t.certName || t.showName || t.task_name).filter(Boolean)
  };
}

function normalizeQualificationDetailResponse(data) {
  const root = data?.result || data?.data || data?.detail || data || {};
  const certInfo = root.product_cert_info || root.productCertInfo || root;
  const inspectReportFiles = normalizeQualificationFileList(certInfo.inspect_report_files || root.inspect_report_files || [], '1');
  const productCertFiles = normalizeQualificationFileList(certInfo.product_cert_files || root.product_cert_files || [], '2');
  return {
    success: isQualificationSuccess(data),
    certType: root.cert_type || certInfo.cert_type || '',
    certName: root.cert_name || certInfo.cert_name || '',
    showName: root.show_name || certInfo.show_name || '',
    fileUploadType: certInfo.file_upload_type || root.file_upload_type || null,
    selectedCheckItems: certInfo.selected_check_items || root.selected_check_items || [],
    multiLangProductCertFileMap: certInfo.multi_lang_product_cert_file_map || root.multi_lang_product_cert_file_map || null,
    docPdfContentReq: certInfo.doc_pdf_content_req || root.doc_pdf_content_req || null,
    inspectReportFiles,
    productCertFiles,
    hasSubmittedFiles: inspectReportFiles.length > 0
      || productCertFiles.length > 0
      || hasNonEmptyQualificationValue(certInfo.multi_lang_product_cert_file_map || root.multi_lang_product_cert_file_map)
      || hasNonEmptyQualificationValue(certInfo.doc_pdf_content_req || root.doc_pdf_content_req),
    raw: root
  };
}

function getQualificationPoolProductId(item = {}) {
  const direct = String(
    item?.product_id
    || item?.productId
    || item?.spu_id
    || item?.spuId
    || item?.product_base_info?.product_id
    || item?.productBaseInfo?.productId
    || item?.product_base_info?.spu_id
    || item?.productBaseInfo?.spuId
    || item?.base_info?.product_id
    || item?.baseInfo?.productId
    || item?.base_info?.spu_id
    || item?.baseInfo?.spuId
    || item?.product_info?.product_id
    || item?.productInfo?.productId
    || item?.product_info?.spu_id
    || item?.productInfo?.spuId
    || ''
  ).trim();
  return direct || readFirstTemuValueByKeys(item, ['product_id', 'productId', 'spu_id', 'spuId']);
}

function getQualificationPoolGoodsId(item = {}) {
  const direct = String(
    item?.goods_id
    || item?.goodsId
    || item?.product_base_info?.goods_id
    || item?.productBaseInfo?.goodsId
    || item?.base_info?.goods_id
    || item?.baseInfo?.goodsId
    || item?.product_info?.goods_id
    || item?.productInfo?.goodsId
    || ''
  ).trim();
  return direct || readFirstTemuValueByKeys(item, ['goods_id', 'goodsId', 'good_id', 'goodId']);
}

function isQualificationPoolRealPictureMissing(item = {}) {
  const value = pickFirstQualificationValue(
    item.real_picture_uploaded,
    item.realPictureUploaded,
    item.has_real_picture,
    item.hasRealPicture,
    item.product_base_info?.real_picture_uploaded,
    item.productBaseInfo?.realPictureUploaded,
    item.product_base_info?.has_real_picture,
    item.productBaseInfo?.hasRealPicture,
    item.base_info?.real_picture_uploaded,
    item.baseInfo?.realPictureUploaded,
    item.base_info?.has_real_picture,
    item.baseInfo?.hasRealPicture,
    item.product_info?.real_picture_uploaded,
    item.productInfo?.realPictureUploaded,
    item.product_info?.has_real_picture,
    item.productInfo?.hasRealPicture
  );
  if (value === undefined || value === null || value === '') return false;
  if (typeof value === 'boolean') return value === false;
  const text = String(value).trim().toLowerCase();
  return text === 'false' || text === '0' || text === 'no';
}

function findQualificationPoolItemForProduct(poolList = [], productId = '') {
  const ids = normalizeQualificationIdSet(productId);
  return (Array.isArray(poolList) ? poolList : []).find(item => {
    const itemIds = normalizeQualificationIdSet(
      getQualificationPoolProductId(item),
      getQualificationPoolGoodsId(item),
      item?.product_id,
      item?.productId,
      item?.spu_id,
      item?.spuId,
      item?.goods_id,
      item?.goodsId
    );
    for (const id of ids) {
      if (itemIds.has(id)) return true;
    }
    return false;
  }) || null;
}

function buildQualificationPoolLivePhotoHint(poolItem = {}, fallbackProductId = '') {
  if (!poolItem || typeof poolItem !== 'object') return null;
  return {
    ...poolItem,
    product_id: getQualificationPoolProductId(poolItem) || fallbackProductId,
    spu_id: getQualificationPoolProductId(poolItem) || fallbackProductId,
    goods_id: getQualificationPoolGoodsId(poolItem),
    __livePhotoLookupSource: 'qualification_batch_product_pool'
  };
}

function pickQualificationImageUrl(item = {}) {
  return item?.image_url
    || item?.imageUrl
    || item?.url
    || item?.img_url
    || item?.imgUrl
    || item?.photo_url
    || item?.photoUrl
    || item?.picture_url
    || item?.pictureUrl
    || item?.real_picture_url
    || item?.realPictureUrl
    || item?.material_img_url
    || item?.materialImgUrl
    || item?.file_url
    || item?.fileUrl
    || item?.original_file_url
    || item?.originalFileUrl
    || '';
}

function isNonEmptyObject(value) {
  return !!value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0;
}

function hasNonEmptyQualificationValue(value) {
  if (Array.isArray(value)) return value.length > 0;
  return isNonEmptyObject(value);
}

function extractTemuListFromPayload(payload = {}) {
  const root = payload?.result || payload?.data || payload?.detail || payload || {};
  const directCandidates = [
    root.items,
    root.list,
    root.data,
    root.records,
    root.pageItems,
    root.page_items,
    root.real_picture_list,
    root.realPictureList,
    root.real_picture_info_list,
    root.realPictureInfoList,
    root.product_list,
    root.productList
  ];
  for (const candidate of directCandidates) {
    if (Array.isArray(candidate)) return candidate;
  }
  if (Array.isArray(root)) return root;
  return [];
}

function extractTemuTotalFromPayload(payload = {}, fallback = 0) {
  const root = payload?.result || payload?.data || payload?.detail || payload || {};
  const value = root.total ?? root.totalCount ?? root.total_count ?? root.count ?? root.total_num ?? root.totalNum;
  const numeric = Number(value);
  return Number.isFinite(numeric) ? numeric : fallback;
}

function normalizeQualificationIdSet(...values) {
  return new Set(values.map(value => String(value || '').trim()).filter(Boolean));
}

function getLivePhotoItemIds(item = {}) {
  const values = [];
  const add = (value) => {
    const text = String(value || '').trim();
    if (text) values.push(text);
  };
  const walk = (node, depth = 0) => {
    if (!node || depth > 4) return;
    if (Array.isArray(node)) {
      node.forEach(child => walk(child, depth + 1));
      return;
    }
    if (typeof node !== 'object') return;
    [
      'spu_id',
      'spuId',
      'product_id',
      'productId',
      'goods_id',
      'goodsId',
      'good_id',
      'goodId'
    ].forEach(key => add(node[key]));
    [
      'product_base_info',
      'productBaseInfo',
      'base_info',
      'baseInfo',
      'real_picture_info_list',
      'realPictureInfoList',
      'sku_photo_info_list',
      'skuPhotoInfoList',
      'items',
      'list',
      'data'
    ].forEach(key => {
      if (node[key] && node[key] !== node) walk(node[key], depth + 1);
    });
  };
  walk(item);
  return new Set(values);
}

function livePhotoItemMatchesIds(item = {}, ids = new Set()) {
  if (!ids || ids.size === 0) return false;
  const itemIds = getLivePhotoItemIds(item);
  for (const id of ids) {
    if (itemIds.has(id)) return true;
  }
  return false;
}

function extractLivePhotoUrlsFromItem(item = {}) {
  const urls = [];
  const seen = new Set();
  const pushUrl = (value) => {
    const text = String(value || '').trim();
    if (!text || seen.has(text)) return;
    if (!/^https?:\/\//i.test(text)) return;
    if (!/\.(png|jpe?g|webp|gif)(\?|#|$)/i.test(text) && !/(image|img|photo|picture|galerie|media)/i.test(text)) return;
    seen.add(text);
    urls.push(text);
  };
  const walk = (node) => {
    if (!node) return;
    if (Array.isArray(node)) {
      node.forEach(walk);
      return;
    }
    if (typeof node !== 'object') {
      if (typeof node === 'string' && /^https?:\/\//i.test(node)) pushUrl(node);
      return;
    }
    pushUrl(pickQualificationImageUrl(node));
    [
      'image_list',
      'imageList',
      'image_url_list',
      'imageUrlList',
      'img_list',
      'imgList',
      'photo_list',
      'photoList',
      'picture_list',
      'pictureList',
      'url_list',
      'urlList',
      'urls',
      'images',
      'photos',
      'pictures',
      'upload_content',
      'uploadContent',
      'upload_file_list',
      'uploadFileList',
      'real_picture_info_list',
      'realPictureInfoList',
      'sku_photo_info_list',
      'skuPhotoInfoList',
      'product_real_picture_info_list',
      'productRealPictureInfoList',
      'items',
      'list',
      'data',
      'result'
    ].forEach(key => {
      if (node[key] && node[key] !== node) walk(node[key]);
    });
  };
  walk(item);
  return urls.slice(0, 5).map((url, index) => ({
    name: `实拍图${index + 1}`,
    url,
    imageUrl: url,
    type: 'image/url',
    source: 'temu_real_picture'
  }));
}

function extractQualificationDetailLivePhotoFiles(detail = {}) {
  const root = detail?.raw || detail || {};
  const containers = [];
  const visited = new Set();
  const shouldCollectKey = (key = '') => /real[_-]?picture|live[_-]?photo|actual[_-]?photo|real[_-]?pic|product[_-]?real|商品实拍图/i.test(key);
  const shouldWalkKey = (key = '') => [
    'product_cert_info',
    'productCertInfo',
    'result',
    'data',
    'detail',
    'items',
    'list',
    'product_info',
    'productInfo',
    'product_base_info',
    'productBaseInfo'
  ].includes(key) || /picture|photo|image|img|pic|upload/i.test(key);
  const walk = (node, keyPath = '') => {
    if (!node || typeof node !== 'object') return;
    if (visited.has(node)) return;
    visited.add(node);
    if (keyPath && shouldCollectKey(keyPath)) {
      containers.push(node);
      return;
    }
    if (Array.isArray(node)) {
      node.forEach(item => walk(item, keyPath));
      return;
    }
    for (const [key, value] of Object.entries(node)) {
      if (!value || typeof value !== 'object') continue;
      const nextPath = keyPath ? `${keyPath}.${key}` : key;
      if (shouldCollectKey(key)) {
        containers.push(value);
      } else if (shouldWalkKey(key)) {
        walk(value, nextPath);
      }
    }
  };
  walk(root);

  const files = [];
  const seenUrls = new Set();
  for (const container of containers) {
    for (const file of extractLivePhotoUrlsFromItem(container)) {
      const url = String(file?.url || file?.imageUrl || '').trim();
      if (!url || seenUrls.has(url)) continue;
      seenUrls.add(url);
      files.push({ ...file, source: 'qualification_detail_real_picture' });
      if (files.length >= 5) return files;
    }
  }
  return files;
}

async function getCapturedLivePhotoItems() {
  try {
    const stored = await chrome.storage.local.get(['temuCapturedLivePhotoList']);
    const captured = stored?.temuCapturedLivePhotoList || {};
    return Array.isArray(captured.items) ? captured.items : [];
  } catch (error) {
    console.warn('[TEMU运营助手] 读取已捕获实拍图缓存失败:', error);
    return [];
  }
}

async function resolveQualificationProductForTemplate(productId, poolItem = null) {
  const auth = await getAuth();
  const normalized = normalizeComplianceProductForUpload({
    spuId: productId,
    goodsId: poolItem?.goodsId || '',
    _raw: poolItem?.raw || null,
    waitTaskList: poolItem?.waitTaskList || []
  });
  if (normalized.goodsId) return normalized;
  try {
    return await resolveComplianceProductForUpload(normalized, auth);
  } catch (error) {
    console.warn('[TEMU运营助手] 查询模板商品 goods_id 失败:', error);
    return normalized;
  }
}

async function fetchQualificationLivePhotoFiles(params = {}) {
  const productId = String(params.productId || params.spuId || '').trim();
  const goodsId = String(params.goodsId || '').trim();
  const ids = normalizeQualificationIdSet(productId, goodsId);
  if (!ids.size) return { files: [], lookup: { checked: 0, matched: 0, ids: [] } };

  const allItems = [];
  const lookup = {
    checked: 0,
    matched: 0,
    ids: Array.from(ids),
    requests: [],
    firstKeys: []
  };
  const appendItems = (items, source = '') => {
    if (!Array.isArray(items) || !items.length) return;
    lookup.checked += items.length;
    allItems.push(...items.map(item => ({ item, source })));
    if (!lookup.firstKeys.length && items[0] && typeof items[0] === 'object') {
      lookup.firstKeys = Object.keys(items[0]).slice(0, 30);
    }
  };

  appendItems(await getCapturedLivePhotoItems(), 'captured_real_picture_list');

  const requests = [
    { pageNum: 1, pageSize: 100, spuId: productId, idField: 'spu_id_list' },
    { pageNum: 1, pageSize: 100, spuId: productId },
    { pageNum: 1, pageSize: 100, productId, idField: 'product_id' },
    goodsId ? { pageNum: 1, pageSize: 100, spuId: productId, goodsId, idField: 'goods_id' } : null,
    { pageNum: 1, pageSize: 100 }
  ].filter(Boolean);

  for (const requestParams of requests) {
    const resp = await getLivePhotoList(requestParams);
    lookup.requests.push({
      requestBody: resp?.requestBody || requestParams,
      success: !!resp?.success,
      total: resp?.total || 0,
      count: Array.isArray(resp?.list) ? resp.list.length : 0,
      error: resp?.error || ''
    });
    if (resp?.success) appendItems(resp.list, 'real_picture_list_api');
  }

  const matchedFiles = [];
  const seenUrls = new Set();
  for (const entry of allItems) {
    if (!livePhotoItemMatchesIds(entry.item, ids)) continue;
    lookup.matched += 1;
    for (const file of extractLivePhotoUrlsFromItem(entry.item)) {
      const url = String(file?.url || file?.imageUrl || '').trim();
      if (!url || seenUrls.has(url)) continue;
      seenUrls.add(url);
      matchedFiles.push({ ...file, source: entry.source || file.source });
      if (matchedFiles.length >= 5) break;
    }
    if (matchedFiles.length >= 5) break;
  }

  return { files: matchedFiles, lookup };
}

function hasQualificationTemplateCertData(template = {}) {
  const detail = template.detail || template.certDetail || {};
  return hasQualificationDetailSubmitData(detail);
}

function hasQualificationDetailSubmitData(detail = {}) {
  return !!(
    hasNonEmptyQualificationValue(detail?.multiLangProductCertFileMap)
    || hasNonEmptyQualificationValue(detail?.docPdfContentReq)
    || (Array.isArray(detail?.inspectReportFiles) && detail.inspectReportFiles.length)
    || (Array.isArray(detail?.productCertFiles) && detail.productCertFiles.length)
  );
}

async function buildQualificationTemplateFromSpu(params = {}) {
  const productId = String(params.productId || params.spuId || '').trim();
  const requestedCertValue = String(params.certType || params.qualType || '').trim();
  if (!productId) return { success: false, error: '请填写已完成资质的模板 SPU' };

  const poolResp = await fetchQualificationPool({
    pageNum: 1,
    pageSize: 50,
    productIds: [productId],
    uploadStatusList: [0, 1, 2, 3, 4, 5, 6]
  });
  const poolItem = poolResp?.products?.find(item => String(item.spuId) === productId);
  const templateProduct = await resolveQualificationProductForTemplate(productId, poolItem || null);
  const templateGoodsId = String(templateProduct?.goodsId || poolItem?.goodsId || '').trim();
  const taskList = Array.isArray(poolItem?.waitTaskList) ? poolItem.waitTaskList : [];
  const matchesRequestedCert = (task = {}) => {
    if (!requestedCertValue) return false;
    return [
      task.certType,
      task.task_type,
      task.certName,
      task.showName,
      task.taskName,
      task.task_name,
      task.task_id,
      task.raw?.cert_type,
      task.raw?.certType,
      task.raw?.task_type,
      task.raw?.taskType,
      task.raw?.cert_name,
      task.raw?.certName,
      task.raw?.show_name,
      task.raw?.showName,
      task.raw?.task_name,
      task.raw?.taskName
    ].some(value => String(value || '').trim() === requestedCertValue);
  };
  const targetTask = requestedCertValue
    ? taskList.find(matchesRequestedCert)
    : taskList.find(task => isQualificationTaskCompleted(task)) || taskList[0] || null;
  const finalCertType = targetTask?.certType
    || targetTask?.task_type
    || targetTask?.raw?.cert_type
    || targetTask?.raw?.certType
    || requestedCertValue
    || poolItem?.pendingCertTypes?.[0]
    || '';
  if (!finalCertType) return { success: false, error: '未能从模板 SPU 识别资质类型' };

  const detailResp = await fetchQualificationDetail({
    productId,
    certType: finalCertType,
    taskId: targetTask?.task_id || '',
    task: targetTask || null
  });
  if (!detailResp?.success) return detailResp;
  if (!detailResp.hasSubmittedFiles) {
    return { success: false, error: '该模板 SPU 没有已上传的资质文件，无法保存为资质模板' };
  }

  const detailLivePhotoFiles = extractQualificationDetailLivePhotoFiles(detailResp);
  const livePhotoResp = detailLivePhotoFiles.length
    ? { files: detailLivePhotoFiles, lookup: { source: 'qualification_detail', matched: detailLivePhotoFiles.length } }
    : await fetchQualificationLivePhotoFiles({ productId, goodsId: templateGoodsId });
  const livePhotoFiles = livePhotoResp.files || [];
  if (!livePhotoFiles.length) {
    console.warn('[TEMU运营助手] 模板 SPU 实拍图未命中:', JSON.stringify(livePhotoResp.lookup || {}).substring(0, 1000));
    return {
      success: false,
      error: `该模板 SPU 没有读取到可复用的实拍图（SPU: ${productId}${templateGoodsId ? `，goods_id: ${templateGoodsId}` : ''}）。请打开 TEMU 商品实拍图页面刷新一次后重试；如果后台详情中已有实拍图，请把控制台里的“模板 SPU 实拍图未命中”日志发给我继续对齐字段。`,
      livePhotoLookup: livePhotoResp.lookup || null
    };
  }
  return {
    success: true,
    template: {
      sourceSpuId: productId,
      sourceGoodsId: templateGoodsId,
      certType: finalCertType,
      certName: detailResp.certName || detailResp.showName || finalCertType,
      files: [
        ...detailResp.inspectReportFiles.map(file => ({ ...file, kind: 'inspect_report' })),
        ...detailResp.productCertFiles.map(file => ({ ...file, kind: 'product_cert' }))
      ],
      livePhotoFiles,
      detail: {
        certType: finalCertType,
        certName: detailResp.certName || '',
        showName: detailResp.showName || '',
        fileUploadType: detailResp.fileUploadType || null,
        selectedCheckItems: detailResp.selectedCheckItems || [],
        multiLangProductCertFileMap: detailResp.multiLangProductCertFileMap || null,
        docPdfContentReq: detailResp.docPdfContentReq || null,
        inspectReportFiles: detailResp.inspectReportFiles || [],
        productCertFiles: detailResp.productCertFiles || []
      }
    }
  };
}

function buildQualificationAuditCandidates(params = {}, detail = {}) {
  const taskId = params.taskId || params.task_id || '';
  const certType = params.certType || params.cert_type || '';
  const certInfo = detail?.raw?.product_cert_info || detail?.raw || {};
  const selectedCheckItems = detail.selectedCheckItems || certInfo.selected_check_items || [];
  const multiLangProductCertFileMap = normalizeQualificationMultiLangFileMap(detail.multiLangProductCertFileMap || certInfo.multi_lang_product_cert_file_map || null);
  const docPdfContentReq = normalizeQualificationDocPdfContentReq(detail.docPdfContentReq || certInfo.doc_pdf_content_req || null, selectedCheckItems);
  const { inspectReportFiles, productCertFiles } = buildQualificationSubmitFiles(detail, params);
  const extendedInfo = buildQualificationExtendedInfo(params.certInfo || params.certInfoResp || {}, detail);

  const variants = [];
  const baseMeta = {
    taskId,
    task_id: taskId
  };
  if (extendedInfo) baseMeta.extendedInfo = extendedInfo;
  const exactBaseMeta = {
    taskId
  };
  if (extendedInfo) exactBaseMeta.extendedInfo = extendedInfo;

  if (multiLangProductCertFileMap || String(certType).toUpperCase().includes('EU DOC') || Number(detail.fileUploadType) === 1) {
    variants.push({
      ...exactBaseMeta,
      productCatCertReqList: [{
        fileUploadType: detail.fileUploadType || certInfo.file_upload_type || 1,
        docPdfContentReq: null,
        multiLangProductCertFileMap: multiLangProductCertFileMap || {},
        selectedCheckItems
      }]
    });
    variants.push({
      ...baseMeta,
      productCatCertReqList: [{
        certType,
        fileUploadType: detail.fileUploadType || certInfo.file_upload_type || 1,
        docPdfContentReq: null,
        multiLangProductCertFileMap: multiLangProductCertFileMap || {},
        selectedCheckItems
      }]
    });
  }

  if (docPdfContentReq) {
    variants.push({
      ...exactBaseMeta,
      productCatCertReqList: [{
        fileUploadType: detail.fileUploadType || certInfo.file_upload_type || 2,
        docPdfContentReq,
        multiLangProductCertFileMap: null,
        selectedCheckItems
      }]
    });
    variants.push({
      ...baseMeta,
      productCatCertReqList: [{
        certType,
        fileUploadType: detail.fileUploadType || certInfo.file_upload_type || 2,
        docPdfContentReq,
        multiLangProductCertFileMap: null,
        selectedCheckItems,
        needSignatureUrl: ['1']
      }]
    });
  }

  if (inspectReportFiles.length || productCertFiles.length) {
    variants.push({
      ...exactBaseMeta,
      productCatCertReqList: [{
        docPdfContentReq: null,
        inspectReportFiles: [...inspectReportFiles, ...productCertFiles]
      }]
    });
    variants.push({
      ...exactBaseMeta,
      productCatCertReqList: [{
        docPdfContentReq: null,
        productCertFiles: [...inspectReportFiles, ...productCertFiles]
      }]
    });
    variants.push({
      ...exactBaseMeta,
      productCatCertReqList: [{
        docPdfContentReq: null,
        inspectReportFiles: inspectReportFiles.length ? inspectReportFiles : null,
        productCertFiles: productCertFiles.length ? productCertFiles : null
      }]
    });
    variants.push({
      ...baseMeta,
      productCatCertReqList: [{
        certType,
        docPdfContentReq: null,
        inspectReportFiles: inspectReportFiles.length ? inspectReportFiles : null,
        productCertFiles: productCertFiles.length ? productCertFiles : null
      }]
    });
    variants.push({
      ...baseMeta,
      productCatCertReqList: [{
        certType,
        docPdfContentReq: null,
        productCertFiles: [...inspectReportFiles, ...productCertFiles]
      }]
    });
  }

  if (!variants.length) {
    variants.push({
      ...baseMeta,
      productCatCertReqList: [{
        certType,
        docPdfContentReq: null,
        inspectReportFiles: null,
        productCertFiles: null,
        selectedCheckItems
      }]
    });
  }

  return variants;
}

function resolveQualificationSubmitDetail(params = {}, detailResp = {}) {
  const templateDetail = params.template?.detail || params.certTemplate?.detail || params.templateDetail || null;
  if (templateDetail && hasQualificationDetailSubmitData(templateDetail)) {
    return {
      ...detailResp,
      ...templateDetail,
      raw: {
        ...(detailResp.raw || {}),
        ...(templateDetail.raw || {})
      }
    };
  }
  return detailResp;
}

// 查询资质商品池
async function fetchQualificationPool(params = {}) {
  const auth = await getAuth();
  try {
    const pageNum = params.pageNum || params.page || 1;
    const pageSize = params.pageSize || params.page_size || 50;
    const fetchAll = !!params.fetchAll;
    const includeAllStatus = !!params.includeAllStatus || !!params.allStatuses;
    const explicitUploadStatusList = Array.isArray(params.uploadStatusList) ? params.uploadStatusList : null;
    const collectPage = async (currentPage, options = {}) => {
      const uploadStatusList = Array.isArray(options.uploadStatusList)
        ? options.uploadStatusList
        : (explicitUploadStatusList && explicitUploadStatusList.length ? explicitUploadStatusList : [0, 1, 2, 3, 4, 5, 6]);
      const requestBody = {
        page: currentPage,
        page_size: pageSize,
      };
      if (!includeAllStatus && !options.includeAllStatus && uploadStatusList.length) {
        requestBody.upload_status_list = uploadStatusList;
      }
      if (params.certType) requestBody.cert_type = params.certType;
      if (Array.isArray(params.productIds) && params.productIds.length) requestBody.product_ids = params.productIds;

      const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/query/list', requestBody, auth, 25000);
      const root = data?.result || data?.data || data?.detail || {};
      const listCandidates = [
        root.product_with_cert_list,
        root.productWithCertList,
        root.product_cert_list,
        root.productCertList,
        root.list,
        root.items,
        root.pageItems,
        root.dataList,
        root.product_list,
        root.productList
      ];
      let rawList = [];
      for (const candidate of listCandidates) {
        if (Array.isArray(candidate)) {
          rawList = candidate;
          break;
        }
        if (candidate && typeof candidate === 'object') {
          const values = Object.values(candidate).flat?.() || Object.values(candidate);
          if (values.some(v => v && typeof v === 'object')) {
            rawList = values.filter(v => v && typeof v === 'object');
            break;
          }
        }
      }
      const products = rawList.map(normalizeQualificationPoolItem);
      const totalRaw = root.total ?? root.total_count ?? root.totalCount ?? data?.total ?? data?.totalCount ?? data?.total_count ?? null;
      const total = Number.isFinite(Number(totalRaw)) ? Number(totalRaw) : null;
      const totalPages = total && total > 0 ? Math.ceil(total / pageSize) : 0;
      return { data, products, total, totalPages };
    };

    if (fetchAll) {
      const collectAllPages = async (options = {}) => {
        const merged = [];
        const seen = new Set();
        let total = 0;
        let totalPages = 0;
        let currentPage = pageNum;
        for (let guard = 0; guard < 50; guard++) {
          const pageResp = await collectPage(currentPage, options);
        const before = merged.length;
        for (const item of pageResp.products) {
          const key = buildQualificationPoolKey(item);
          if (!key || seen.has(key)) continue;
          seen.add(key);
          merged.push(item);
        }
          total = Math.max(total, pageResp.total);
          totalPages = Math.max(totalPages, pageResp.totalPages);
          const added = merged.length - before;
          if (!pageResp.products.length) break;
          if (pageResp.total != null && merged.length >= pageResp.total) break;
          if (pageResp.totalPages && currentPage >= pageResp.totalPages) break;
          if (!added) break;
          currentPage += 1;
        }
        return { merged, total, totalPages };
      };

      let { merged, total, totalPages } = await collectAllPages();
      if (merged.length <= 1 && !explicitUploadStatusList && !includeAllStatus) {
        const broad = await collectAllPages({ includeAllStatus: true });
        if (broad.merged.length > merged.length) {
          merged = broad.merged;
          total = broad.total;
          totalPages = broad.totalPages;
        }
      }

      console.log('[TEMU运营助手] 资质商品池响应(全量):', merged.length);
      return {
        success: merged.length > 0,
        products: merged,
        total: total || merged.length,
        totalPages: totalPages || Math.ceil((total || merged.length) / pageSize)
      };
    }

    const pageResp = await collectPage(pageNum);
    console.log('[TEMU运营助手] 资质商品池响应:', JSON.stringify(pageResp.data).substring(0, 500));
    return {
      success: isQualificationSuccess(pageResp.data) || pageResp.products.length > 0,
      products: pageResp.products,
      total: pageResp.total,
      totalPages: pageResp.totalPages
    };
  } catch (error) {
    console.error('[TEMU运营助手] fetchQualificationPool 出错:', error);
    return { success: false, error: error.message };
  }
}

async function fetchQualificationDetail(params = {}) {
  const auth = await getAuth();
  try {
    const productId = params.productId || params.spuId || params.goodsId;
    const certType = params.certType || params.cert_type || params.taskType || params.task_type;
    if (!productId || !certType) {
      return { success: false, error: '请提供 SPU ID 和资质类型' };
    }

    const requestBody = { product_id: productId, cert_type: certType };
    const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/query/detail', requestBody, auth, 25000);
    const normalized = normalizeQualificationDetailResponse(data);
    console.log('[TEMU运营助手] 资质证书详情响应:', JSON.stringify(data).substring(0, 500));
    const hasDetailData = !!(normalized.certType || normalized.certName || normalized.showName || normalized.inspectReportFiles.length || normalized.productCertFiles.length || normalized.docPdfContentReq);
    return (normalized.success || hasDetailData)
      ? normalized
      : {
          success: false,
          error: `${getQualificationApiMessage(data, '查询资质详情失败')}（product_id: ${productId}, cert_type: ${certType}）`,
          raw: data,
          requestBody
        };
  } catch (error) {
    console.error('[TEMU运营助手] fetchQualificationDetail 出错:', error);
    return { success: false, error: error.message };
  }
}

async function createQualificationBatchTask(params = {}) {
  const auth = await getAuth();
  try {
    const productIds = (params.productIds || [params.productId || params.spuId]).filter(Boolean).map(String);
    const certType = params.certType || params.cert_type;
    if (!productIds.length || !certType) {
      return { success: false, error: '请提供 SPU ID 和资质类型' };
    }

    const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/batch_upload/upload', {
        batch_upload_task_type: 1,
        cert_type: certType,
        product_ids: productIds
      }, auth, 30000);
    console.log('[TEMU运营助手] 资质批量任务响应:', JSON.stringify(data).substring(0, 500));
    return isQualificationSuccess(data)
      ? {
          success: true,
          taskId: data?.result?.taskId || data?.result?.task_id || data?.taskId || data?.task_id || null,
          raw: data
        }
      : { success: false, error: data?.msg || data?.message || '创建资质批量任务失败', raw: data };
  } catch (error) {
    console.error('[TEMU运营助手] createQualificationBatchTask 出错:', error);
    return { success: false, error: error.message };
  }
}

async function fetchQualificationBatchEligibleProductIds(params = {}) {
  const auth = await getAuth();
  try {
    const productIds = Array.from(new Set((params.productIds || []).map(value => String(value || '').trim()).filter(Boolean)));
    const certType = params.certType || params.cert_type;
    if (!productIds.length || !certType) {
      return { success: false, error: '请提供 SPU ID 和资质类型' };
    }
    const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/batch_upload/product_list', {
      page: 1,
      page_size: Math.max(50, productIds.length),
      cert_type: certType,
      product_ids: productIds
    }, auth, 25000);
    const root = getQualificationRoot(data);
    const list = root.productWithCertList || root.product_with_cert_list || root.product_list || root.productList || root.items || root.list || [];
    const eligibleIds = Array.from(new Set(
      (Array.isArray(list) ? list : [])
        .map(item => String(item?.product_id || item?.productId || item?.spu_id || item?.spuId || '').trim())
        .filter(Boolean)
    ));
    return {
      success: isQualificationSuccess(data) || eligibleIds.length > 0,
      productIds: eligibleIds,
      raw: data
    };
  } catch (error) {
    console.error('[TEMU运营助手] fetchQualificationBatchEligibleProductIds 出错:', error);
    return { success: false, error: error.message };
  }
}

function qualificationTaskMatchesCertType(task = {}, certType = '') {
  const expected = String(certType || '').trim().toLowerCase();
  if (!expected) return true;
  const candidates = [
    getQualificationTaskCertType(task),
    task?.certName,
    task?.showName,
    task?.task_name,
    task?.taskName,
    task?.raw?.cert_name,
    task?.raw?.certName,
    task?.raw?.show_name,
    task?.raw?.showName,
    task?.raw?.task_name,
    task?.raw?.taskName
  ].map(value => String(value || '').trim().toLowerCase()).filter(Boolean);
  return candidates.some(value => value === expected || value.includes(expected) || expected.includes(value));
}

function isQualificationTaskSubmittedOrActive(task = {}) {
  const state = getQualificationTaskState(task).state;
  return state === 'completed' || state === 'reviewing' || hasQualificationReturnedFiles(task);
}

async function verifyQualificationProductsAfterSubmit(params = {}) {
  const productIds = Array.from(new Set((params.productIds || []).map(value => String(value || '').trim()).filter(Boolean)));
  const certType = String(params.certType || params.cert_type || '').trim();
  if (!productIds.length) {
    return { success: false, verifiedProductIds: [], pendingProductIds: [], error: '没有需要回读确认的 SPU' };
  }

  const verifiedProductIds = [];
  const pendingProductIds = [];
  const productStates = [];

  for (const productId of productIds) {
    let matchedTask = null;
    let lastResp = null;
    for (let attempt = 0; attempt < 3; attempt++) {
      lastResp = await fetchQualificationPool({
        pageNum: 1,
        pageSize: 50,
        productIds: [productId],
        certType,
        includeAllStatus: true
      });
      const product = Array.isArray(lastResp?.products)
        ? lastResp.products.find(item => String(item.spuId) === productId) || lastResp.products[0]
        : null;
      const tasks = (Array.isArray(product?.waitTaskList) ? product.waitTaskList : [])
        .filter(task => task && typeof task === 'object');
      matchedTask = tasks.find(task => qualificationTaskMatchesCertType(task, certType)) || tasks[0] || null;
      if (matchedTask && isQualificationTaskSubmittedOrActive(matchedTask)) break;
      await sleep(2000);
    }

    const meta = matchedTask ? getQualificationTaskState(matchedTask) : { state: 'unknown', label: '未返回资质任务', detail: '' };
    productStates.push({
      productId,
      certType,
      state: meta.state,
      label: meta.label,
      detail: meta.detail || '',
      matched: !!matchedTask
    });
    if (matchedTask && isQualificationTaskSubmittedOrActive(matchedTask)) {
      verifiedProductIds.push(productId);
    } else {
      pendingProductIds.push(productId);
    }
  }

  return {
    success: verifiedProductIds.length > 0,
    verifiedProductIds,
    pendingProductIds,
    productStates
  };
}

// 查询资质证书信息
async function fetchQualificationCertInfo(params = {}) {
  const auth = await getAuth();
  try {
    const taskId = params.taskId || params.task_id;
    if (!taskId) {
      return { success: false, error: '请提供 taskId' };
    }

    const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/batch_upload/query_cert_info', { task_id: taskId }, auth, 25000);
    console.log('[TEMU运营助手] 资质证书信息响应:', JSON.stringify(data).substring(0, 500));
    return data;
  } catch (error) {
    console.error('[TEMU运营助手] fetchQualificationCertInfo 出错:', error);
    return { success: false, error: error.message };
  }
}

async function fetchQualificationBatchProductPool(params = {}) {
  const auth = await getAuth();
  try {
    const taskId = params.taskId || params.task_id;
    if (!taskId) {
      return { success: false, error: '请提供 taskId' };
    }
    const pageSize = Number(params.pageSize || params.page_size || 50) || 50;
    const requestBody = {
      page: Number(params.page || 1) || 1,
      task_id: taskId,
      page_size: pageSize
    };
    const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/batch_upload/product_pool_list', requestBody, auth, 25000);
    const root = getQualificationRoot(data);
    const list = root.productWithCertList || root.product_with_cert_list || root.list || root.items || [];
    console.log('[TEMU运营助手] 资质批量商品池响应:', JSON.stringify(data).substring(0, 500));
    return {
      success: isQualificationSuccess(data) || Array.isArray(list),
      list: Array.isArray(list) ? list : [],
      raw: data
    };
  } catch (error) {
    console.error('[TEMU运营助手] fetchQualificationBatchProductPool 出错:', error);
    return { success: false, error: error.message };
  }
}

async function queryQualificationSubmitStatus(params = {}) {
  const auth = await getAuth();
  try {
    const taskId = params.taskId || params.task_id;
    if (!taskId) {
      return { success: false, error: '请提供 taskId' };
    }

    const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/batch_upload/submit_query', { task_id: taskId, need_detail: true }, auth, 25000);
    console.log('[TEMU运营助手] 资质提交状态响应:', JSON.stringify(data).substring(0, 500));
    const root = getQualificationRoot(data);
    const batchUploadResult = root.batchUploadResult || root.batch_upload_result || {};
    const failList = batchUploadResult.fail_send_audit_product_list
      || batchUploadResult.failSendAuditProductList
      || root.fail_send_audit_product_list
      || root.failSendAuditProductList
      || [];
    return {
      success: isQualificationSuccess(data),
      raw: data,
      status: batchUploadResult.status ?? root.status,
      failList: Array.isArray(failList) ? failList : [],
      batchUploadResult
    };
  } catch (error) {
    console.error('[TEMU运营助手] queryQualificationSubmitStatus 出错:', error);
    return { success: false, error: error.message };
  }
}

// 提交资质审核
async function submitQualificationAudit(params = {}) {
  const auth = await getAuth();
  try {
    const taskId = params.taskId || params.task_id;
    const detail = params.detail || params.certDetail || {};
    const candidates = buildQualificationAuditCandidates({ ...params, taskId }, detail);
    let lastData = null;
    let lastBody = null;

    for (const body of candidates) {
      lastBody = body;
      const data = await temuSellerPost('https://agentseller.temu.com/mms/arbok/product_cert/batch_upload/send_audit', body, auth, 30000);
      lastData = data;
      console.log('[TEMU运营助手] 资质审核提交请求:', JSON.stringify(body).substring(0, 700));
      console.log('[TEMU运营助手] 资质审核提交响应:', JSON.stringify(data).substring(0, 700));
      if (isQualificationSuccess(data)) {
        return {
          success: true,
          raw: data,
          taskId,
          requestBody: body
        };
      }
      const message = getQualificationMessageDeep(data, '');
      if (message && /无效|不存在|过期|权限|参数|parameter|invalid|expired|not found/i.test(message)) {
        console.warn('[TEMU运营助手] 资质审核提交失败:', message);
      }
    }

    return {
      success: false,
      error: getQualificationApiMessage(lastData, getQualificationMessageDeep(lastData, '提交资质审核失败')),
      raw: lastData,
      requestBody: lastBody
    };
  } catch (error) {
    console.error('[TEMU运营助手] submitQualificationAudit 出错:', error);
    return { success: false, error: error.message };
  }
}

async function uploadQualification(params = {}) {
  const productId = params.productId || params.spuId;
  const certType = params.certType || params.cert_type || params.qualType;
  if (!productId) {
    return { success: false, error: '请提供 SPU ID' };
  }

  const poolResp = await fetchQualificationPool({
    pageNum: 1,
    pageSize: 50,
    productIds: [productId]
  });
  const poolItem = poolResp?.products?.find(item => String(item.spuId) === String(productId));
  const uploadRequiredTask = poolItem?.waitTaskList?.find(isQualificationTaskUploadRequired);
  const inferredCertType = certType || poolItem?.pendingCertTypes?.[0] || getQualificationTaskCertType(uploadRequiredTask) || '';

  const detailResp = await fetchQualificationDetail({ productId, certType: inferredCertType || '' });
  if (!detailResp.success) {
    return detailResp;
  }

  const finalCertType = inferredCertType || detailResp.certType || detailResp.showName || detailResp.certName;
  const taskResp = await createQualificationBatchTask({
    productId,
    certType: finalCertType
  });
  if (!taskResp.success) {
    return taskResp;
  }

  const taskId = taskResp.taskId;
  const certInfoResp = taskId ? await fetchQualificationCertInfo({ taskId }) : null;
  const submitDetail = resolveQualificationSubmitDetail(params, detailResp);
  if (!hasQualificationDetailSubmitData(submitDetail)) {
    return { success: false, error: '未找到可提交的资质文件，请先用已填写好的 SPU 保存资质模板' };
  }
  const auditResp = await submitQualificationAudit({
    taskId,
    productId,
    certType: finalCertType,
    detail: submitDetail,
    certInfo: certInfoResp,
    files: params.files || []
  });

  if (!auditResp.success) {
    return auditResp;
  }

  const statusResp = taskId ? await queryQualificationSubmitStatus({ taskId }) : null;
  return {
    success: true,
    productId: String(productId),
    certType: finalCertType,
    taskId,
    detail: detailResp,
    certInfo: certInfoResp,
    audit: auditResp,
    submitStatus: statusResp
  };
}

async function uploadQualificationBatch(params = {}) {
  const productIds = Array.from(new Set(
    (params.productIds || [params.productId || params.spuId])
      .flat()
      .map(v => String(v).trim())
      .filter(Boolean)
  ));
  const certType = params.certType || params.cert_type || params.qualType;

  if (!productIds.length) {
    return { success: false, error: '请提供 SPU ID 列表' };
  }

  const poolResp = await fetchQualificationPool({
    pageNum: 1,
    pageSize: 50,
    productIds
  });
  const firstPoolItem = poolResp?.products?.find(item => productIds.includes(String(item.spuId)));
  const uploadRequiredTask = firstPoolItem?.waitTaskList?.find(isQualificationTaskUploadRequired);
  const inferredCertType = certType
    || firstPoolItem?.pendingCertTypes?.[0]
    || getQualificationTaskCertType(uploadRequiredTask)
    || '';

  const detailResp = await fetchQualificationDetail({
    productId: productIds[0],
    certType: inferredCertType || ''
  });

  const finalCertType = inferredCertType || detailResp.certType || detailResp.showName || detailResp.certName;
  const submitDetail = resolveQualificationSubmitDetail(params, detailResp);
  if (!detailResp.success && !hasQualificationDetailSubmitData(submitDetail)) {
    return detailResp;
  }
  if (!hasQualificationDetailSubmitData(submitDetail)) {
    return { success: false, error: '未找到可提交的资质文件，请先用已填写好的 SPU 保存资质模板' };
  }
  const livePhotoFiles = params.livePhotoFiles || params.template?.livePhotoFiles || [];
  const livePhotoResults = [];

  const eligibleResp = await fetchQualificationBatchEligibleProductIds({
    productIds,
    certType: finalCertType
  });
  const eligibleProductIds = eligibleResp?.success && Array.isArray(eligibleResp.productIds) && eligibleResp.productIds.length
    ? eligibleResp.productIds
    : productIds;
  const skippedProductIds = eligibleResp?.success && Array.isArray(eligibleResp.productIds) && eligibleResp.productIds.length
    ? productIds.filter(id => !eligibleProductIds.includes(String(id)))
    : [];
  if (!eligibleResp?.success) {
    console.warn('[TEMU运营助手] 资质可上传商品预查询失败，继续按所选 SPU 创建官方批量任务:', eligibleResp?.error || '');
  } else if (!Array.isArray(eligibleResp.productIds) || !eligibleResp.productIds.length) {
    console.warn('[TEMU运营助手] 资质可上传商品预查询未返回 SPU，继续按所选 SPU 创建官方批量任务');
  }

  const taskResp = await createQualificationBatchTask({
    productIds: eligibleProductIds,
    certType: finalCertType
  });
  if (!taskResp.success) {
    if (!params.__singleSpuRetry && eligibleProductIds.length > 1 && isQualificationTransientServerError(taskResp)) {
      return await uploadQualificationBatchOneByOne(params, eligibleProductIds, taskResp.error || getQualificationApiMessage(taskResp.raw || taskResp, 'TEMU 批量任务创建临时失败'));
    }
    return taskResp;
  }

  const taskId = taskResp.taskId;
  const certInfoResp = taskId ? await fetchQualificationCertInfo({ taskId }) : null;
  const poolBeforeSubmit = taskId ? await fetchQualificationBatchProductPool({ taskId, pageSize: Math.max(50, eligibleProductIds.length) }) : null;
  if (poolBeforeSubmit?.success && Array.isArray(poolBeforeSubmit.list) && poolBeforeSubmit.list.length) {
    const missingRealPictureIds = poolBeforeSubmit.list
      .filter(isQualificationPoolRealPictureMissing)
      .map(getQualificationPoolProductId)
      .filter(Boolean);
    if (missingRealPictureIds.length) {
      if (!Array.isArray(livePhotoFiles) || !livePhotoFiles.length) {
        return {
          success: false,
          error: `TEMU 批量任务中 ${missingRealPictureIds.length} 个 SPU 缺少实拍图，请先用带实拍图的 SPU 重新保存资质模板`,
          productIds: eligibleProductIds,
          requestedProductIds: productIds,
          skippedProductIds,
          taskId,
          poolBeforeSubmit
        };
      }
      for (const productId of missingRealPictureIds) {
        const poolItem = findQualificationPoolItemForProduct(poolBeforeSubmit.list, productId);
        const productHint = buildQualificationPoolLivePhotoHint(poolItem, productId);
        const livePhotoResp = await applyLivePhotoUrlsToProduct(productId, livePhotoFiles, productHint);
        livePhotoResults.push({ ...livePhotoResp, phase: 'task_pool_recheck' });
        if (!livePhotoResp?.success) {
          return {
            success: false,
            error: `SPU ${productId} 实拍图上传失败：${livePhotoResp?.error || '未知错误'}`,
            productIds: eligibleProductIds,
            requestedProductIds: productIds,
            skippedProductIds,
            taskId,
            livePhotoResults,
            poolBeforeSubmit
          };
        }
      }
    }
  }
  const auditResp = await submitQualificationAudit({
    taskId,
    productId: eligibleProductIds[0],
    productIds: eligibleProductIds,
    certType: finalCertType,
    detail: submitDetail,
    certInfo: certInfoResp,
    files: params.files || []
  });

  if (!auditResp.success) {
    if (!params.__singleSpuRetry && eligibleProductIds.length > 1 && isQualificationTransientServerError(auditResp)) {
      return await uploadQualificationBatchOneByOne(params, eligibleProductIds, auditResp.error || getQualificationApiMessage(auditResp.raw || auditResp, 'TEMU 批量提交临时失败'));
    }
    const verifyResp = await verifyQualificationProductsAfterSubmit({
      productIds: eligibleProductIds,
      certType: finalCertType
    });
    if (verifyResp.success) {
      return {
        success: true,
        warning: auditResp.error || 'TEMU 提交接口返回失败，但官方回读已确认资质状态已更新',
        productIds: verifyResp.verifiedProductIds,
        verifiedProductIds: verifyResp.verifiedProductIds,
        pendingProductIds: verifyResp.pendingProductIds,
        requestedProductIds: productIds,
        skippedProductIds,
        certType: finalCertType,
        taskId,
        detail: detailResp,
        certInfo: certInfoResp,
        audit: auditResp,
        verify: verifyResp,
        poolBeforeSubmit,
        livePhotoResults
      };
    }
    return {
      ...auditResp,
      productIds: eligibleProductIds,
      requestedProductIds: productIds,
      taskId,
      certInfo: certInfoResp,
      poolBeforeSubmit,
      verify: verifyResp
    };
  }

  let statusResp = null;
  if (taskId) {
    for (let attempt = 0; attempt < 6; attempt++) {
      statusResp = await queryQualificationSubmitStatus({ taskId });
      const statusCode = Number(statusResp?.status);
      if (statusCode === 50 || (Array.isArray(statusResp?.failList) && statusResp.failList.length)) break;
      await sleep(2500);
    }
  }
  const failList = Array.isArray(statusResp?.failList) ? statusResp.failList : [];
  if (failList.length) {
    const firstError = failList
      .map(item => `${item.product_id || item.productId || ''}${item.error_message || item.errorMessage ? `：${item.error_message || item.errorMessage}` : ''}`)
      .filter(Boolean)
      .slice(0, 3)
      .join('；');
    const verifyResp = await verifyQualificationProductsAfterSubmit({
      productIds: eligibleProductIds,
      certType: finalCertType
    });
    if (verifyResp.success) {
      const stillFailed = eligibleProductIds.filter(id => !verifyResp.verifiedProductIds.includes(String(id)));
      return {
        success: true,
        warning: firstError || 'TEMU 返回失败列表，但官方回读已确认部分或全部 SPU 状态已更新',
        productIds: verifyResp.verifiedProductIds,
        verifiedProductIds: verifyResp.verifiedProductIds,
        pendingProductIds: stillFailed,
        requestedProductIds: productIds,
        skippedProductIds: [...new Set([...skippedProductIds, ...stillFailed])],
        certType: finalCertType,
        taskId,
        detail: detailResp,
        certInfo: certInfoResp,
        audit: auditResp,
        submitStatus: statusResp,
        poolBeforeSubmit,
        livePhotoResults,
        verify: verifyResp
      };
    }
    return {
      success: false,
      error: firstError || 'TEMU 返回部分商品提交资质审核失败',
      productIds: eligibleProductIds,
      requestedProductIds: productIds,
      certType: finalCertType,
      taskId,
      detail: detailResp,
      certInfo: certInfoResp,
      audit: auditResp,
      submitStatus: statusResp,
      poolBeforeSubmit,
      livePhotoResults,
      verify: verifyResp
    };
  }
  const verifyResp = await verifyQualificationProductsAfterSubmit({
    productIds: eligibleProductIds,
    certType: finalCertType
  });
  return {
    success: true,
    productIds: verifyResp.success ? verifyResp.verifiedProductIds : eligibleProductIds,
    productId: (verifyResp.success ? verifyResp.verifiedProductIds : eligibleProductIds)[0],
    verifiedProductIds: verifyResp.verifiedProductIds || [],
    pendingProductIds: verifyResp.pendingProductIds || [],
    requestedProductIds: productIds,
    skippedProductIds,
    certType: finalCertType,
    taskId,
    detail: detailResp,
    certInfo: certInfoResp,
    audit: auditResp,
    submitStatus: statusResp,
    poolBeforeSubmit,
    livePhotoResults,
    verify: verifyResp
  };
}

// ========== 定制品模板查询 ==========

function getCustomizedSkuTemplateCandidates(sku = {}) {
  const candidates = [
    sku.templateId,
    sku.template_id,
    sku.templateIds,
    sku.template_ids,
    sku.productSkuCustomizationTmpl,
    sku.productSkuSaleExtAttr?.productSkuCustomizationTmpl,
    sku.productSkuSaleExtAttr?.productSkuCustomizationTemplate,
    sku.productSkuSaleExtAttr?.customizationTmpl,
    sku.productSkuSaleExtAttr?.customizationTemplate,
    sku.customizationTmpl,
    sku.customizationTemplate
  ];
  const ids = [];
  for (const candidate of candidates) {
    if (!candidate) continue;
    if (Array.isArray(candidate)) {
      candidate.flat?.().forEach(item => {
        if (item === undefined || item === null || item === '') return;
        ids.push(String(item));
      });
      continue;
    }
    if (typeof candidate === 'object') {
      const nestedIds = candidate.templateIds || candidate.template_ids || candidate.templateId || candidate.template_id;
      if (Array.isArray(nestedIds)) {
        nestedIds.flat?.().forEach(item => {
          if (item === undefined || item === null || item === '') return;
          ids.push(String(item));
        });
      } else if (nestedIds !== undefined && nestedIds !== null && nestedIds !== '') {
        ids.push(String(nestedIds));
      }
      const ownId = candidate.id || candidate.templateId || candidate.template_id;
      if (ownId !== undefined && ownId !== null && ownId !== '') {
        ids.push(String(ownId));
      }
      continue;
    }
    ids.push(String(candidate));
  }
  return [...new Set(ids.filter(Boolean))];
}

function cloneStructuredData(value) {
  if (value === undefined || value === null) return value;
  try {
    return JSON.parse(JSON.stringify(value));
  } catch (error) {
    console.warn('[TEMU运营助手] cloneStructuredData 失败，返回原始值:', error);
    return value;
  }
}

function getCustomizedSkuSurfaces(sku = {}) {
  const candidates = [
    sku.surfaces,
    sku.surface,
    sku.productSkuCustomizationTmpl?.surfaces,
    sku.productSkuCustomizationTmpl?.surface,
    sku.productSkuSaleExtAttr?.productSkuCustomizationTmpl?.surfaces,
    sku.productSkuSaleExtAttr?.productSkuCustomizationTmpl?.surface,
    sku.productSkuSaleExtAttr?.productSkuCustomizationTemplate?.surfaces,
    sku.productSkuSaleExtAttr?.productSkuCustomizationTemplate?.surface,
    sku.customizationTmpl?.surfaces,
    sku.customizationTmpl?.surface,
    sku.customizationTemplate?.surfaces,
    sku.customizationTemplate?.surface
  ];

  for (const candidate of candidates) {
    if (!candidate) continue;
    if (Array.isArray(candidate)) {
      const normalized = candidate.filter(item => item && typeof item === 'object').map(cloneStructuredData);
      if (normalized.length > 0) return normalized;
      continue;
    }
    if (typeof candidate === 'object') {
      return [cloneStructuredData(candidate)];
    }
  }

  return [];
}

function getCustomizedSkuSpecInfo(sku = {}) {
  const sources = [
    sku.skuAttrList,
    sku.sku_attr_list,
    sku.specInfoList,
    sku.spec_info_list,
    sku.specList,
    sku.spec_list,
    sku.specifications,
    sku.specificationList,
    sku.productSkuSaleExtAttr?.skuAttrList,
    sku.productSkuSaleExtAttr?.sku_attr_list
  ];
  for (const source of sources) {
    if (!source) continue;
    if (Array.isArray(source)) {
      const text = source
        .map(attr => attr?.attrValue || attr?.attr_value || attr?.value || attr?.specValue || attr?.spec_value || attr?.name || attr?.attrName || attr?.attr_name || '')
        .filter(Boolean)
        .join(' / ');
      if (text) return text;
    } else if (typeof source === 'object') {
      const values = Object.values(source)
        .flat?.()
        .map?.(v => (typeof v === 'object' ? (v?.attrValue || v?.value || v?.name || '') : v))
        .filter(Boolean);
      const text = values.join(' / ');
      if (text) return text;
    } else if (typeof source === 'string' && source.trim()) {
      return source.trim();
    }
  }
  return '';
}

function hasCustomizedSkuTemplate(sku = {}) {
  return getCustomizedSkuTemplateCandidates(sku).length > 0;
}

function buildCustomizedTemplateDataFromProduct(product = {}, fallbackId = '') {
  const productId = product.productId || product.skcId || product.productSkcId || product.goodspu || product.productSpuId || product.goodsId || fallbackId || '';
  const goodsId = product.goodsId || product.spuId || product.goodspu || fallbackId || '';
  const allSkuList = Array.isArray(product.skuList) ? product.skuList : [];
  const allSkuIds = allSkuList.map(sku => sku.productSkuId || sku.skuId || '').filter(Boolean);
  const foundSkus = allSkuList
    .filter(sku => hasCustomizedSkuTemplate(sku))
    .map(sku => ({
      productSkuId: sku.productSkuId || sku.skuId || '',
      templateId: getCustomizedSkuTemplateCandidates(sku)[0] || '',
      templateIds: getCustomizedSkuTemplateCandidates(sku),
      specInfo: getCustomizedSkuSpecInfo(sku),
      surfaces: getCustomizedSkuSurfaces(sku)
    }));
  return {
    productId,
    goodsId,
    allSkuIds,
    foundSkus
  };
}

async function fetchCustomizedTemplateDataFallback(params = {}) {
  const skuIdOrSpuId = params.skuId || params.spuId;
  const pageSize = 100;
  let product = null;
  for (let pageNo = 1; pageNo <= 5 && !product; pageNo++) {
    const listResult = await fetchCustomizedProductList({
      pageNo,
      pageSize
    });
    if (!listResult?.success || !Array.isArray(listResult.products) || listResult.products.length === 0) {
      continue;
    }
    product = listResult.products.find(item => (
      String(item.goodsId || '') === String(skuIdOrSpuId)
      || String(item.productId || '') === String(skuIdOrSpuId)
      || String(item.skcId || '') === String(skuIdOrSpuId)
    ));
    if (product) break;
    if (listResult.products.length < pageSize) break;
  }
  if (!product) {
    return { success: false, error: '查询被 TEMU 拒绝，且商品列表接口未找到该商品。请先同步定制品商品列表后再试' };
  }
  return {
    success: true,
    data: buildCustomizedTemplateDataFromProduct(product, skuIdOrSpuId),
    source: 'product-list-fallback'
  };
}

// 查询某商品（SPU）下已配置定制品信息的 SKU 列表
async function fetchCustomizedTemplateData(params = {}) {
  const auth = await getAuth();
  try {
    const skuIdOrSpuId = params.skuId || params.spuId;
    if (!skuIdOrSpuId) {
      return { success: false, error: '请提供 SKU ID 或 SPU ID' };
    }

    console.log('[TEMU运营助手] 查询定制品模板数据, skuId/spuId:', skuIdOrSpuId);

    // 使用商品信息 API 查询该 SPU 下的所有 SKU 和定制品配置
    const data = await temuSellerPost('https://agentseller.temu.com/professional/goods/info/find/all/pageable/spu/by/multiple/params', {
        currentPage: 1,
        pageSize: 100,
        filter: {
          mallId: auth?.mallId || '',
          goodSpuList: [parseInt(skuIdOrSpuId)]
        }
      }, auth, 25000);
    console.log('[TEMU运营助手] 定制品查询响应:', JSON.stringify(data).substring(0, 500));

    if (data.code === 0 && data.detail) {
      const items = data.detail.items || [];
      if (items.length === 0) {
        return { success: false, error: '未找到该商品，请确认 SPU ID 是否正确' };
      }

      const templateData = buildCustomizedTemplateDataFromProduct(items[0], skuIdOrSpuId);

      console.log('[TEMU运营助手] 找到商品, productId:', templateData.productId, 'SKU总数:', templateData.allSkuIds.length, '已配置定制品:', templateData.foundSkus.length);

      return {
        success: true,
        data: templateData
      };
    } else {
      const errorText = data.message || data.error_msg || data.msg || '查询失败';
      if (/Request Not Allowed|not allowed|forbidden|拒绝|不允许/i.test(String(errorText))) {
        console.warn('[TEMU运营助手] 定制品详情接口被拒绝，改用商品列表接口兜底:', errorText);
        return await fetchCustomizedTemplateDataFallback(params);
      }
      return { success: false, error: errorText };
    }
  } catch (error) {
    console.error('[TEMU运营助手] fetchCustomizedTemplateData 出错:', error);
    return { success: false, error: error.message };
  }
}

// 将定制品模板应用到指定 SKU 列表
async function applyCustomizedTemplateToSkus(params = {}) {
  const auth = await getAuth();
  try {
    if (!auth?.mallId) {
      return { success: false, error: '请先连接 TEMU 店铺后再填写定制品信息' };
    }

    const { productId, spuId } = params;
    const targetProductId = String(productId || spuId || '').trim();
    if (!targetProductId) {
      return { success: false, error: '缺少目标 SPU ID' };
    }

    const templateResult = await resolveFreshCustomizedTemplateIds(auth, params);
    if (!templateResult.success) {
      return templateResult;
    }

    const targetResult = await queryCustomizedSkcPageFresh(auth, {
      page: 1,
      pageSize: 10,
      productIds: [targetProductId]
    }, 20000);
    if (!targetResult.success) {
      return { success: false, error: `目标 SPU ${targetProductId} 实时查询失败：${targetResult.error || '未知错误'}`, raw: targetResult.raw };
    }

    const currentProduct = targetResult.items.find(item => String(getCustomizedPageProductId(item)) === targetProductId)
      || targetResult.items[0];
    const freshProductId = String(getCustomizedPageProductId(currentProduct) || targetProductId).trim();
    const editBuildResult = buildFreshCustomizedEditList(currentProduct, templateResult.templateIds, params);
    if (!editBuildResult.success) {
      return editBuildResult;
    }

    const submitProductId = editBuildResult.productId || freshProductId || targetProductId;
    const editSkuCustomizationTmplList = editBuildResult.editSkuCustomizationTmplList;

    console.log('[TEMU运营助手] 应用定制品模板(实时SKU), productId:', submitProductId, 'editCount:', editSkuCustomizationTmplList.length, 'templateSource:', templateResult.source);

    const data = await temuSellerPagePost(
      CUSTOMIZED_TEMPLATE_EDIT_URL,
      {
        productId: normalizeTemuRequestId(submitProductId),
        editSkuCustomizationTmplList
      },
      auth,
      20000
    );
    console.log('[TEMU运营助手] 定制品模板应用响应:', JSON.stringify(data).substring(0, 500));

    if (isTemuApiSuccess(data)) {
      const result = {
        success: true,
        message: `成功应用模板到 ${editBuildResult.applyCount || editSkuCustomizationTmplList.length} 个 SKU`,
        productId: submitProductId,
        editCount: editSkuCustomizationTmplList.length,
        appliedSkuCount: editBuildResult.applyCount || editSkuCustomizationTmplList.length,
        templateSource: templateResult.source
      };

      if (params.applyStock === true) {
        try {
          const stockResult = await applyCustomizedProductStock(auth, currentProduct, submitProductId, params.stockQuantity);
          if (stockResult.success) {
            Object.assign(result, {
              stockApplied: true,
              stockAttempted: true,
              stockQuantity: stockResult.stockQuantity,
              stockNoChange: stockResult.stockNoChange === true,
              stockMode: stockResult.stockMode,
              stockUpdatedSkuCount: stockResult.stockUpdatedSkuCount || 0,
              stockWarehouseCount: stockResult.stockWarehouseCount || 0
            });
          } else {
            result.stockApplied = false;
            result.stockAttempted = stockResult.stockAttempted !== false;
            result.stockError = stockResult.error || '库存更新失败';
            result.stockRaw = stockResult.raw;
          }
        } catch (stockError) {
          result.stockApplied = false;
          result.stockAttempted = true;
          result.stockError = stockError?.message || '库存更新失败';
        }
      }

      return result;
    }

    const apiError = getTemuApiMessage(data, '应用模板失败');
    const hint = /sku|SKU|货品/i.test(String(apiError))
      ? `${apiError}。已按 TEMU 最新 SKU 重新查询后提交；如果仍失败，请关闭 TEMU 当前定制品窗口并重新保存模板 SKU。`
      : apiError;
    return { success: false, error: hint, raw: data };
  } catch (error) {
    console.error('[TEMU运营助手] applyCustomizedTemplateToSkus 出错:', error);
    return { success: false, error: error.message };
  }
}

// ========== 采集上架 API ==========

/**
 * 从TEMU买家端采集商品数据
 * 方式：通过注入 content script 到买家端页面提取数据
 */
async function collectProductFromBuyerUrl(url) {
  try {
    // 从链接提取 goodsId
    const match =
      url.match(/-p-(\d+)/) ||
      url.match(/-g-(\d+)/) ||
      url.match(/goods_id=(\d+)/) ||
      url.match(/goodsId=(\d+)/) ||
      url.match(/item_id=(\d+)/);
    const goodsId = match ? match[1] : null;
    
    if (!goodsId) {
      return { success: false, error: '无法从链接提取商品ID，请确认链接格式' };
    }

    const cachedByUrl = buyerCollectCache.get(url);
    if (cachedByUrl && cachedByUrl.data) {
      const ageMs = Date.now() - (cachedByUrl.updatedAt || 0);
      if (ageMs < 5 * 60 * 1000) {
        return { success: true, data: { ...cachedByUrl.data, sourceUrl: url || '', cacheHit: true } };
      }
    }

    const cached = buyerCollectCache.get(goodsId);
    if (cached && cached.data) {
      const ageMs = Date.now() - (cached.updatedAt || 0);
      if (ageMs < 5 * 60 * 1000) {
        return { success: true, data: { ...cached.data, sourceUrl: url || '', cacheHit: true } };
      }
    }

    // 稳定模式：只使用一个隐藏标签页串行采集，避免频繁开新页触发风控
    const now = Date.now();
    if (now < buyerCollectCooldownUntil) {
      await sleep(buyerCollectCooldownUntil - now);
    }
    buyerCollectCooldownUntil = Date.now() + 2500;

    let tabId = buyerCollectWorkerTabId;
    if (tabId) {
      try {
        await chrome.tabs.get(tabId);
      } catch (_) {
        tabId = null;
        buyerCollectWorkerTabId = null;
      }
    }
    if (!tabId) {
      const tab = await chrome.tabs.create({ url: 'about:blank', active: false });
      tabId = tab.id;
      buyerCollectWorkerTabId = tabId;
    }
    await chrome.tabs.update(tabId, { url, active: false });
    
    return new Promise((resolve) => {
      const timeout = setTimeout(() => {
        chrome.tabs.onUpdated.removeListener(listener);
        resolve({ success: false, error: '采集超时（15秒），可能是网络问题或页面未加载' });
      }, 15000);

      function listener(tabId, info) {
        if (tabId !== buyerCollectWorkerTabId || info.status !== 'complete') return;
        chrome.tabs.onUpdated.removeListener(listener);

        // 等待页面渲染完成
        setTimeout(async () => {
          try {
            const results = await chrome.scripting.executeScript({
              target: { tabId: buyerCollectWorkerTabId },
              func: extractProductFromPage
            });
            clearTimeout(timeout);
            
            if (results && results[0] && results[0].result) {
              const pageData = results[0].result;
              const normalized = { ...pageData, goodsId };
              if (pageData.title || pageData.images.length > 0 || pageData.skus?.length > 0) {
                const cacheEntry = { data: normalized, updatedAt: Date.now() };
                buyerCollectCache.set(goodsId, cacheEntry);
                buyerCollectCache.set(url, cacheEntry);
                resolve({ success: true, data: { ...normalized, sourceUrl: url || '', captureMode: 'single-tab' } });
              } else {
                const probe = await chrome.scripting.executeScript({
                  target: { tabId: buyerCollectWorkerTabId },
                  func: () => {
                    const text = (document.body?.innerText || '').slice(0, 1200);
                    return {
                      href: location.href,
                      title: document.title || '',
                      text
                    };
                  }
                });
                const state = probe?.[0]?.result || {};
                if (/login\.html|登录|验证码|验证/.test(state.href || state.title || state.text || '')) {
                  resolve({
                    success: false,
                    blockedByProtection: true,
                    pauseCollection: true,
                    error: 'Temu 已跳转到登录/验证页，建议停止批量采集并稍后再试'
                  });
                } else if (/售罄|已售罄|无货|缺货|out of stock/i.test(state.text || '')) {
                  resolve({
                    success: false,
                    blockedByProtection: true,
                    pauseCollection: true,
                    error: '当前商品页显示售罄或无货，已暂停后续采集'
                  });
                } else {
                  resolve({ success: false, error: '页面未提取到有效商品信息（可能是页面结构已变更）' });
                }
              }
            } else {
              resolve({ success: false, error: '页面脚本注入失败，请检查扩展权限' });
            }
          } catch (err) {
            clearTimeout(timeout);
            resolve({ success: false, error: '页面采集失败: ' + err.message });
          }
        }, 3000); // 等待3秒让动态内容加载
      }

      chrome.tabs.onUpdated.addListener(listener);
    });
  } catch (error) {
    return { success: false, error: error.message };
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function isTemuTransientNetworkError(error) {
  const text = typeof error === 'string'
    ? error
    : (error?.message || error?.error || String(error || ''));
  return /Failed to fetch|Load failed|NetworkError|ERR_NETWORK|ERR_FAILED|ERR_CONNECTION|ERR_TIMED_OUT|timeout|请求超时|请求失败|XMLHttpRequest 请求失败|XMLHttpRequest 请求超时/i.test(text);
}

async function retryTemuTransientOperation(operation, options = {}) {
  const retries = Math.max(0, Number(options.retries ?? 2));
  const delays = Array.isArray(options.delays) && options.delays.length ? options.delays : [800, 1600];
  let lastError = null;
  for (let attempt = 0; attempt <= retries; attempt += 1) {
    try {
      return await operation(attempt);
    } catch (error) {
      lastError = error;
      if (attempt >= retries || !isTemuTransientNetworkError(error)) throw error;
      const delay = Number(delays[attempt] || delays[delays.length - 1] || 800);
      if (delay > 0) await sleep(delay);
    }
  }
  throw lastError || new Error('TEMU 网络请求失败');
}

function getTemuUploadOfficialStepLabel(step = '') {
  const labels = {
    prepare: '准备提交数据',
    'category/template': '读取类目模板',
    'draft/add': '创建草稿',
    'image/upload': '上传商品图片',
    'draft/save': '保存草稿',
    'draft/verify': '校验草稿内容',
    'draft/query': '读取草稿详情',
    'product/add': '发布草稿'
  };
  return labels[String(step || '')] || String(step || 'TEMU 接口请求');
}

function formatTemuUploadOfficialStepError(step = '', message = '') {
  const rawMessage = String(message || '').trim() || 'TEMU 未返回错误原因';
  const label = getTemuUploadOfficialStepLabel(step);
  if (!label || rawMessage.includes(label)) return rawMessage;
  if (isTemuTransientNetworkError(rawMessage)) {
    return `${label}网络请求失败：${rawMessage}。请保持 TEMU 后台页面已登录，稍后重试。`;
  }
  return `${label}失败：${rawMessage}`;
}

async function collectProductFromCurrentTab(tabId, url, pageRawData = null) {
  try {
    if (pageRawData) {
      const goodsId = (url.match(/-p-(\d+)/) || url.match(/-g-(\d+)/) || url.match(/goods_id=(\d+)/) || url.match(/goodsId=(\d+)/) || url.match(/item_id=(\d+)/) || [])[1] || '';
      const parsed = parseTemuBuyerRawPageData(pageRawData, goodsId);
      if (parsed.title || parsed.images?.length > 0 || parsed.skus?.length > 0) {
        return { success: true, data: { ...parsed, sourceUrl: url || '' } };
      }
    }
    await sleep(1500);
    const results = await chrome.scripting.executeScript({
      target: { tabId },
      func: extractProductFromPage
    });

    const pageData = results?.[0]?.result;
    if (pageData && (pageData.title || pageData.images?.length > 0 || pageData.skus?.length > 0)) {
      return { success: true, data: { ...pageData, sourceUrl: url || '' } };
    }

    if (url) {
      return await collectProductFromBuyerUrl(url);
    }

    return { success: false, error: '当前页面未提取到有效商品信息' };
  } catch (error) {
    if (url) {
      try {
        return await collectProductFromBuyerUrl(url);
      } catch (fallbackError) {
        return { success: false, error: fallbackError.message || error.message };
      }
    }
    return { success: false, error: error.message };
  }
}

function parseTemuBuyerRawPageData(rawData, goodsId) {
  const state = rawData && typeof rawData === 'object' ? rawData : {};
  const store = state.store || state.data?.store || state.page?.store || state.pageData || state;
  const goods = store.goods || store.product || state.goods || state.product || {};
  const normalizeList = (value) => {
    if (Array.isArray(value)) return value;
    if (value && typeof value === 'object') {
      if (Array.isArray(value.items)) return value.items;
      if (Array.isArray(value.list)) return value.list;
      if (Array.isArray(value.data)) return value.data;
    }
    return [];
  };
  const pick = (...values) => {
    for (const value of values) {
      if (value !== undefined && value !== null && value !== '') return value;
    }
    return '';
  };

  const skuList = normalizeList(store.sku || store.skus || store.formatSkuData?.skuInfos || goods.skuList || goods.skus || goods.sku_list);
  const imageList = normalizeList(store.preloadFirstImgList || goods.images || goods.imageList || goods.bannerList || goods.gallery || goods.galleryList);
  const mainImage = pick(
    goods.mainImage,
    goods.primaryImageUrl,
    goods.image,
    goods.thumbUrl,
    imageList[0],
    store.mainImage,
    store.primaryImageUrl
  );
  const title = pick(
    goods.goodsName,
    goods.title,
    goods.name,
    state.title,
    store.title,
    store.goodsName
  );
  const category = pick(
    goods.catName,
    goods.categoryName,
    goods.category_path,
    store.catName,
    store.categoryName,
    state.categoryName,
    state.category
  );
  const price = pick(
    goods.price,
    goods.salePrice,
    goods.currentPrice,
    goods.minPrice,
    store.price,
    store.salePrice,
    state.price
  );
  const description = pick(
    goods.description,
    goods.goodsDesc,
    goods.goods_desc,
    store.description,
    store.goodsDesc
  );
  const rating = pick(
    goods.rating,
    goods.score,
    goods.starScore,
    store.rating,
    state.rating,
    state.score
  );
  const sales = pick(
    goods.sales,
    goods.saleCount,
    goods.soldCount,
    store.sales,
    store.saleCount,
    store.soldCount,
    state.sales
  );
  const stock = pick(
    goods.stock,
    goods.stockCnt,
    goods.stock_count,
    store.stock,
    store.stockCnt,
    state.stock
  );

  return {
    goodsId,
    title: title || '',
    images: [mainImage, ...imageList].filter(Boolean).slice(0, 20),
    skus: skuList.map(sku => ({
      id: pick(sku.id, sku.skuId, sku.goods_sku_id, sku.sku_id, sku.productSkuId, ''),
      name: Array.isArray(sku.spec)
        ? sku.spec.map(s => s?.spec_value || s?.value || s?.name || s).filter(Boolean).join(' / ')
        : pick(sku.specText, sku.specName, sku.spec_name, sku.name, sku.goodsSkuName, ''),
      price: pick(sku.price, sku.sale_price, sku.line_price, sku.current_price, sku.minPrice, 0),
      stock: pick(sku.stock, sku.stockCnt, sku.stock_count, sku.availableStock, sku.available_stock, null),
      image: pick(sku.thumbUrl, sku.sku_image, sku.image, sku.mainImage, ''),
      sales: pick(sku.sales, sku.saleCount, sku.soldCount, sku.sold_count, null)
    })),
    price: price || null,
    description: description || '',
    category: category || '',
    rating: rating || null,
    sales: sales || null,
    stock: stock || null,
    captureMethod: 'raw-data'
  };
}

function pickFirstValue(...values) {
  for (const value of values) {
    if (value !== undefined && value !== null && value !== '') return value;
  }
  return '';
}

/**
 * 解析TEMU买家端API返回的数据
 */
function parseTemuBuyerApiData(data, goodsId) {
  const item = data?.result?.goods || data?.result?.goodsInfo || data?.result || data?.data || data;
  const goodsInfo = data?.result?.goods_info || data?.result?.goodsInfo || item;
  
  // 提取图片
  const imageUrls = pickFirstValue(
    item.imageUrls,
    item.images,
    item.goods_gallery_urls,
    item.galleryUrls,
    item.gallery_urls,
    goodsInfo.imageUrls,
    goodsInfo.images,
    goodsInfo.goods_gallery_urls,
    []
  );
  const mainImg = pickFirstValue(
    item.primaryImageUrl,
    item.mainImage,
    item.thumbUrl,
    item.main_image_url,
    goodsInfo.primaryImageUrl,
    goodsInfo.mainImage,
    ''
  );

  const skuSource = pickFirstValue(item.skus, item.variants, item.sku_list, goodsInfo.skus, goodsInfo.variants, goodsInfo.sku_list, []);
  const skus = Array.isArray(skuSource) ? skuSource : [];

  return {
    goodsId,
    title: pickFirstValue(item.title, item.name, item.goods_name, item.goodsName, goodsInfo.title, goodsInfo.goods_name, goodsInfo.goodsName, ''),
    images: [
      ...(mainImg ? [mainImg] : []),
      ...[].concat(imageUrls || []).filter(url => url && url !== mainImg)
    ].slice(0, 20),
    skus: skus.map(sku => ({
      id: pickFirstValue(sku.id, sku.skuId, sku.goods_sku_id, sku.sku_id, ''),
      name: Array.isArray(sku.spec)
        ? sku.spec.map(s => s?.spec_value || s?.value || s?.name || s).filter(Boolean).join(' / ')
        : pickFirstValue(sku.specText, sku.specName, sku.spec_name, sku.name, ''),
      price: pickFirstValue(sku.price, sku.sale_price, sku.line_price, sku.current_price, sku.minPrice, 0),
      stock: pickFirstValue(sku.stock, sku.stockCnt, sku.stock_count, sku.availableStock, sku.available_stock, null),
      image: pickFirstValue(sku.thumbUrl, sku.sku_image, sku.image, sku.mainImage, ''),
      sales: pickFirstValue(sku.sales, sku.saleCount, sku.soldCount, sku.sold_count, null)
    })),
    price: pickFirstValue(item.price, item.salePrice, item.min_price, item.current_price, goodsInfo.price, goodsInfo.salePrice, 0),
    description: pickFirstValue(item.description, item.desc, item.goods_desc, goodsInfo.description, goodsInfo.desc, ''),
    category: pickFirstValue(item.categoryName, item.catName, item.category_path, goodsInfo.categoryName, goodsInfo.catName, goodsInfo.category_path, ''),
    rating: pickFirstValue(item.rating, item.score, item.starScore, goodsInfo.rating, goodsInfo.score, goodsInfo.starScore, null),
    sales: pickFirstValue(item.sales, item.saleCount, item.soldCount, goodsInfo.sales, goodsInfo.saleCount, goodsInfo.soldCount, null),
    stock: pickFirstValue(item.stock, item.stockCnt, item.stock_count, goodsInfo.stock, goodsInfo.stockCnt, goodsInfo.stock_count, null),
    captureMethod: 'api'
  };
}

/**
 * 注入到买家端页面的采集函数
 */
function extractProductFromPage() {
  const result = {
    title: '',
    images: [],
    skus: [],
    price: null,
    description: '',
    category: '',
    rating: null,
    sales: null,
    stock: null,
    captureMethod: 'page'
  };

  const pick = (...values) => {
    for (const value of values) {
      if (value !== undefined && value !== null && value !== '') return value;
    }
    return '';
  };

  const normalizeList = (value) => {
    if (Array.isArray(value)) return value;
    if (value && typeof value === 'object') {
      if (Array.isArray(value.items)) return value.items;
      if (Array.isArray(value.list)) return value.list;
      if (Array.isArray(value.data)) return value.data;
    }
    return [];
  };

  const extractFromTemuState = (state) => {
    if (!state || typeof state !== 'object') return null;
    const store = state.store || state.data?.store || state.page?.store || state.pageData || state;
    const goods = store.goods || store.product || state.goods || state.product || {};
    const skuList = normalizeList(store.sku || store.skus || store.formatSkuData?.skuInfos || goods.skuList || goods.skus || goods.sku_list);
    const imageList = normalizeList(store.preloadFirstImgList || goods.images || goods.imageList || goods.bannerList || goods.gallery || goods.galleryList);
    const mainImage = pick(
      goods.mainImage,
      goods.primaryImageUrl,
      goods.image,
      goods.thumbUrl,
      imageList[0],
      store.mainImage,
      store.primaryImageUrl
    );
    const title = pick(
      goods.goodsName,
      goods.title,
      goods.name,
      state.title,
      store.title,
      store.goodsName
    );
    const category = pick(
      goods.catName,
      goods.categoryName,
      goods.category_path,
      store.catName,
      store.categoryName,
      state.categoryName,
      state.category
    );
    const price = pick(
      goods.price,
      goods.salePrice,
      goods.currentPrice,
      goods.minPrice,
      store.price,
      store.salePrice,
      state.price
    );
    const description = pick(
      goods.description,
      goods.goodsDesc,
      goods.goods_desc,
      store.description,
      store.goodsDesc
    );
    const rating = pick(
      goods.rating,
      goods.score,
      goods.starScore,
      store.rating,
      state.rating,
      state.score
    );
    const sales = pick(
      goods.sales,
      goods.saleCount,
      goods.soldCount,
      store.sales,
      store.saleCount,
      store.soldCount,
      state.sales
    );
    const stock = pick(
      goods.stock,
      goods.stockCnt,
      goods.stock_count,
      store.stock,
      store.stockCnt,
      state.stock
    );

    const skus = skuList.map(sku => ({
      id: pick(sku.id, sku.skuId, sku.goods_sku_id, sku.sku_id, sku.productSkuId, ''),
      name: Array.isArray(sku.spec)
        ? sku.spec.map(s => s?.spec_value || s?.value || s?.name || s).filter(Boolean).join(' / ')
        : pick(sku.specText, sku.specName, sku.spec_name, sku.name, sku.goodsSkuName, ''),
      price: pick(sku.price, sku.sale_price, sku.line_price, sku.current_price, sku.minPrice, 0),
      stock: pick(sku.stock, sku.stockCnt, sku.stock_count, sku.availableStock, sku.available_stock, null),
      image: pick(sku.thumbUrl, sku.sku_image, sku.image, sku.mainImage, ''),
      sales: pick(sku.sales, sku.saleCount, sku.soldCount, sku.sold_count, null)
    }));

    return {
      title: title || '',
      images: [mainImage, ...imageList].filter(Boolean).slice(0, 20),
      skus,
      price: price || null,
      description: description || '',
      category: category || '',
      rating: rating || null,
      sales: sales || null,
      stock: stock || null,
      captureMethod: 'raw-data'
    };
  };

  const rawCandidates = [
    window.rawData,
    window.__INITIAL_STATE__,
    window.__NEXT_DATA__?.props?.pageProps,
    window.__PRELOADED_STATE__,
    window.__NUXT__,
    window.__APOLLO_STATE__
  ];

  for (const candidate of rawCandidates) {
    const parsed = extractFromTemuState(candidate);
    if (parsed && (parsed.title || parsed.images.length > 0 || parsed.skus.length > 0)) {
      return parsed;
    }
  }

  for (const script of Array.from(document.scripts || [])) {
    const text = script.innerText || script.textContent || '';
    const marker = 'window.rawData';
    const idx = text.indexOf(marker);
    if (idx === -1) continue;
    const assignIndex = text.indexOf('=', idx);
    if (assignIndex === -1) continue;
    const startIndex = assignIndex + 1;
    const extractBalancedObject = (source, start) => {
      let depth = 0;
      let inString = false;
      let quote = '';
      for (let i = start; i < source.length; i++) {
        const ch = source[i];
        const prev = source[i - 1];
        if (inString) {
          if (ch === quote && prev !== '\\') inString = false;
          continue;
        }
        if (ch === '"' || ch === '\'') {
          inString = true;
          quote = ch;
          continue;
        }
        if (ch === '{') depth++;
        if (ch === '}') {
          depth--;
          if (depth === 0) return source.slice(start, i + 1);
        }
      }
      return null;
    };
    const snippet = extractBalancedObject(text, startIndex);
    if (!snippet) continue;
    try {
      const parsedRawData = Function(`"use strict"; return (${snippet});`)();
      const parsed = extractFromTemuState(parsedRawData);
      if (parsed && (parsed.title || parsed.images.length > 0 || parsed.skus.length > 0)) {
        return parsed;
      }
    } catch (error) {
      // ignore parse failures and fall back to DOM scraping
    }
  }

  // 标题
  const titleEl = document.querySelector('h1, [class*="title"], [class*="Title"], [data-testid*="title"], [class*="product-name"], [class*="ProductName"]');
  if (titleEl) result.title = titleEl.textContent.trim();
  if (!result.title) {
    const ogTitle = document.querySelector('meta[property="og:title"], meta[name="title"]')?.content;
    if (ogTitle) result.title = ogTitle.trim();
  }
  if (!result.title && document.title) {
    result.title = document.title.replace(/\s*[\-|_]\s*Temu.*$/i, '').trim();
  }

  // 图片
  document.querySelectorAll('[class*="gallery"] img, [class*="carousel"] img, [class*="image"] img, [class*="slider"] img, [class*="thumb"] img, img').forEach(img => {
    const src = img.src || img.dataset.src;
    if (src && !src.includes('data:') && src.includes('http') && result.images.length < 20) {
      result.images.push(src.replace(/_\d+x\d+/, '_800x800'));
    }
  });

  // SKU 变体
  document.querySelectorAll('[class*="sku"] [class*="item"], [class*="variant"] [class*="item"], [class*="spec"] [class*="item"], [data-testid*="sku"] [data-testid*="item"]').forEach(el => {
    const name = el.getAttribute('aria-label') || el.textContent.trim();
    if (name && name.length < 50) {
      result.skus.push({ name, image: el.querySelector('img')?.src || '' });
    }
  });

  // 价格
  const priceEl = document.querySelector('[class*="price"] [class*="current"], [class*="price"]');
  if (priceEl) {
    const priceText = priceEl.textContent.replace(/[^\d.]/g, '');
    result.price = parseFloat(priceText) || null;
  }

  // 描述
  const descEl = document.querySelector('[class*="description"], [class*="detail"], [class*="desc"], [data-testid*="desc"]');
  if (descEl) {
    const descText = descEl.textContent.trim().slice(0, 2000);
    if (!/下载\s*App\s*Store|Download\s*on\s*the\s*App\s*Store/i.test(descText)) {
      result.description = descText;
    }
  }

  // 类目/评分/销量/库存的辅助抓取
  const categoryEl = document.querySelector('[class*="breadcrumb"], [class*="category"], [data-testid*="category"]');
  if (categoryEl) result.category = categoryEl.textContent.trim().slice(0, 100);

  const bodyText = document.body.innerText || '';
  const priceText = bodyText.match(/¥\s?(\d+(?:\.\d+)?)/)?.[1];
  if (!result.price && priceText) result.price = parseFloat(priceText) || null;

  const ratingText = bodyText.match(/(\d(?:\.\d+)?)\s*分/)?.[1];
  if (ratingText) result.rating = parseFloat(ratingText) || null;

  return result;
}

/**
 * 创建上传批次（采集上架第1步）
 */
async function createUploadLot(mallId, antiContent) {
  const url = 'https://seller.kuajingmaihuo.com/professional/temu/upload/two/create/lot';
  return temuApiRequest(url, { method: 'POST' }, mallId, antiContent);
}

/**
 * 保存采集数据到批次（采集上架第2步）
 */
async function saveCollectionData(lotId, productData, mallId, antiContent) {
  const url = 'https://seller.kuajingmaihuo.com/professional/temu/upload/two/add';
  return temuApiRequest(url, {
    method: 'POST',
    body: JSON.stringify({
      lotId,
      ...productData
    })
  }, mallId, antiContent);
}

/**
 * 获取商品元数据（采集上架第3步）
 */
async function getGoodsMetadata(goodsId, mallId, antiContent) {
  const url = 'https://seller.kuajingmaihuo.com/professional/temu/upload/two/get/goods/metadata';
  return temuApiRequest(url, {
    method: 'POST',
    body: JSON.stringify({ goodsId })
  }, mallId, antiContent);
}

function getMoveProductDetailPayload(result = {}) {
  if (!result || typeof result !== 'object') return null;
  return result.result || result.data || result.detail || result;
}

function hasMoveProductDetailPayload(detail = {}) {
  if (!detail || typeof detail !== 'object') return false;
  if (Array.isArray(detail.productSkcList) && detail.productSkcList.length > 0) return true;
  if (Array.isArray(detail.productSkuList) && detail.productSkuList.length > 0) return true;
  return Boolean(detail.productName && (detail.productId || detail.goodsId || detail.goods_id));
}

function hasMoveProductOfficialEditDetail(detail = {}) {
  if (!detail || typeof detail !== 'object') return false;
  const hasSkus = Array.isArray(detail.productSkcList)
    && detail.productSkcList.some(skc => Array.isArray(skc?.productSkuList) && skc.productSkuList.length > 0);
  const hasEditExtAttrs = detail.productWhExtAttr && typeof detail.productWhExtAttr === 'object';
  const hasEditableAttributes = Array.isArray(detail.productPropertyList)
    || Array.isArray(detail.productSpecPropertyVOS)
    || Boolean(detail.productSaleExtAttr && typeof detail.productSaleExtAttr === 'object')
    || Boolean(detail.productNonAuditExtAttr && typeof detail.productNonAuditExtAttr === 'object');
  return hasSkus && hasEditExtAttrs && hasEditableAttributes;
}

async function queryMoveProductEditDetail(productId, auth = {}) {
  const normalizedProductId = normalizeTemuIdText(productId);
  if (!normalizedProductId) return { success: false, error: '缺少 productId' };
  const url = 'https://agentseller.temu.com/visage-agent-seller/product/query';
  return temuSellerExactPost(url, {
    productId: Number(normalizedProductId),
    productEditTaskUid: ''
  }, auth, 30000);
}

async function tryGetMoveProductDetailByProductId(productId, auth = {}, source = 'product/query') {
  const normalizedProductId = normalizeTemuIdText(productId);
  if (!normalizedProductId) return { success: false, source, id: '', error: '缺少 productId' };
  const result = await queryMoveProductEditDetail(normalizedProductId, auth);
  const detail = getMoveProductDetailPayload(result);
  const apiSuccess = result?.success !== false && result?.code !== -1 && result?.errorCode !== -1;
  const hasDetail = apiSuccess && hasMoveProductOfficialEditDetail(detail);
  if (hasDetail) {
    detail.detailSource = 'temu_product_query';
    detail.sourceId = normalizedProductId;
    detail.sourceIdType = 'spu';
    detail.missingProductAttributes = false;
  }
  return {
    success: hasDetail,
    source,
    id: normalizedProductId,
    result,
    detail,
    error: hasDetail ? '' : getTemuApiMessage(result, 'product/query 未返回完整商品编辑详情')
  };
}

function addMoveDetailCandidate(candidates, value, source = '') {
  const id = normalizeTemuIdText(value);
  if (!id || candidates.some(item => item.id === id)) return;
  candidates.push({ id, source });
}

function moveDetailProductMatchesInput(product = {}, inputId = '') {
  const id = normalizeTemuIdText(inputId);
  if (!id) return false;
  const skuList = Array.isArray(product.skuList) ? product.skuList : [];
  const values = [
    product.goodsId,
    product.productId,
    product.spuId,
    product.skcId,
    product.raw?.goodsId,
    product.raw?.goods_id,
    product.raw?.productId,
    product.raw?.product_id,
    product.raw?.productSkcId,
    product.raw?.skcId,
    ...skuList.flatMap(sku => [sku?.skuId, sku?.productSkuId])
  ].map(normalizeTemuIdText).filter(Boolean);
  return values.includes(id);
}

function summarizeMoveDetailAttempts(attempts = []) {
  return attempts
    .map(item => {
      const id = item.id ? `ID ${item.id}` : '无ID';
      const status = item.success ? '成功' : (item.error || '未返回完整详情');
      return `${item.source || 'unknown'} ${id}: ${status}`;
    })
    .join('；');
}

function collectTemuUploadOfficialOuterPackageImagesFromSources(sources = []) {
  const rows = [];
  const push = (item) => {
    const url = getTemuDraftPublishImageUrlFromValue(item);
    if (!url) return;
    const normalizedUrl = /^\/\//.test(url) ? `https:${url}` : url;
    if (!/^https?:\/\//i.test(normalizedUrl)) return;
    if (rows.some(row => String(row.imageUrl || row.signedImageUrl || '').trim() === normalizedUrl)) return;
    const row = item && typeof item === 'object' && !Array.isArray(item)
      ? cloneTemuUploadOfficialValue(item)
      : {};
    rows.push({
      ...row,
      imageUrl: row.imageUrl || normalizedUrl,
      signedImageUrl: row.signedImageUrl || normalizedUrl
    });
  };
  const pushList = (source) => {
    if (!source) return;
    (Array.isArray(source) ? source : [source]).forEach(push);
  };
  sources.forEach(pushList);
  return rows;
}

function buildMoveProductDetailFromProductManagement(product = {}, sourceId = '', sourceIdType = 'spu') {
  const skuList = Array.isArray(product.skuList) ? product.skuList : [];
  const raw = product.raw && typeof product.raw === 'object' ? product.raw : {};
  const images = Array.from(new Set([
    product.mainImage,
    ...(Array.isArray(product.imageList) ? product.imageList : []),
    ...(Array.isArray(product.productSkcImageExtList) ? product.productSkcImageExtList.map(item => item?.imageUrl || item?.url) : [])
  ].map(url => String(url || '').trim()).filter(Boolean)));
  const propertyList = Array.isArray(product.productPropertyList) ? product.productPropertyList : [];
  const skcImage = product.mainImage || images[0] || '';
  const productSkcId = product.productId || product.skcId || (sourceIdType === 'skc' ? sourceId : '');
  const productId = product.goodsId || product.spuId || (sourceIdType === 'spu' ? sourceId : '');
  const productWhExtAttr = [
    product.productWhExtAttr,
    product.productWhExtAttrReq,
    raw.productWhExtAttr,
    raw.productWhExtAttrReq
  ].find(item => item && typeof item === 'object' && !Array.isArray(item));
  const productOuterPackage = [
    product.productOuterPackage,
    product.productOuterPackageReq,
    raw.productOuterPackage,
    raw.productOuterPackageReq,
    productWhExtAttr?.productOuterPackage,
    productWhExtAttr?.outerPackage
  ].find(item => item && typeof item === 'object' && !Array.isArray(item));
  const outerPackageImages = collectTemuUploadOfficialOuterPackageImagesFromSources([
    product.outerPackageImages,
    product.productOuterPackageImages,
    product.productOuterPackageImageReqs,
    product.productOuterPackageImageList,
    product.outerPackageImageReqs,
    product.outerPackageImageList,
    product.packageImageList,
    raw.outerPackageImages,
    raw.productOuterPackageImages,
    raw.productOuterPackageImageReqs,
    raw.productOuterPackageImageList,
    raw.outerPackageImageReqs,
    raw.outerPackageImageList,
    raw.packageImageList,
    productWhExtAttr?.outerPackageImages,
    productWhExtAttr?.productOuterPackageImages,
    productWhExtAttr?.productOuterPackageImageReqs,
    productWhExtAttr?.productOuterPackageImageList,
    productWhExtAttr?.outerPackageImageReqs,
    productWhExtAttr?.outerPackageImageList,
    productWhExtAttr?.packageImageList,
    productOuterPackage?.outerPackageImages,
    productOuterPackage?.productOuterPackageImages,
    productOuterPackage?.productOuterPackageImageReqs,
    productOuterPackage?.productOuterPackageImageList,
    productOuterPackage?.outerPackageImageReqs,
    productOuterPackage?.outerPackageImageList,
    productOuterPackage?.packageImageList,
    productOuterPackage?.packageImages,
    productOuterPackage?.imageList,
    productOuterPackage?.images
  ]);
  return {
    productId,
    goodsId: product.goodsId || product.spuId || '',
    productName: product.productName || product.title || '',
    categoryId: product.categoryId || '',
    categoryName: product.categoryName || '',
    carouselImageUrls: images,
    materialImgUrl: skcImage,
    productPropertyList: propertyList,
    productProperties: propertyList,
    missingProductAttributes: propertyList.length === 0,
    ...(productWhExtAttr ? { productWhExtAttr: cloneTemuUploadOfficialValue(productWhExtAttr) } : {}),
    ...(productOuterPackage ? { productOuterPackage: cloneTemuUploadOfficialValue(productOuterPackage) } : {}),
    ...(outerPackageImages.length ? { outerPackageImages: cloneTemuUploadOfficialValue(outerPackageImages) } : {}),
    ...(product.raw ? { raw: cloneTemuUploadOfficialValue(product.raw) } : {}),
    detailSource: 'temu_product_skc_pageQuery',
    sourceId,
    sourceIdType,
    productSkcList: [{
      productSkcId,
      colorImageUrl: skcImage,
      previewImgUrls: images,
      productSkcImageExtList: images.map(url => ({ imageUrl: url })),
      productSkuList: skuList.map((sku, index) => {
        const specText = sku?.skuSpec || sku?.skuSpecText || sku?.name || sku?.skuName || `SKU ${index + 1}`;
        return {
          productSkuId: sku?.skuId || sku?.productSkuId || `${productSkcId || sourceId}_${index + 1}`,
          extCode: sku?.skuCode || sku?.extCode || '',
          supplierPrice: sku?.price || product.price || '',
          thumbUrl: sku?.skuImage || sku?.imageUrl || sku?.thumbUrl || sku?.productSkuImage || skcImage,
          productSkuQuantity: sku?.stockText || sku?.showStockText || sku?.stock || '',
          productSkuSpecList: [{ specValue: specText, value: specText, name: specText }]
        };
      })
    }]
  };
}

async function fetchMoveProductManagementProduct(sourceId, sourceIdType, attempts = []) {
  const inputId = normalizeTemuIdText(sourceId);
  if (!inputId) return null;
  try {
    const listResult = await fetchCustomizedProductList({
      pageNo: 1,
      pageSize: 100,
      productId: inputId
    });
    const products = (Array.isArray(listResult?.products) ? listResult.products : [])
      .filter(product => moveDetailProductMatchesInput(product, inputId));
    const product = products.find(item => Array.isArray(item.productPropertyList) && item.productPropertyList.length > 0)
      || products.find(item => Array.isArray(item.skuList) && item.skuList.length > 0)
      || products[0]
      || null;
    attempts.push({
      source: 'product/skc/pageQuery detail',
      id: inputId,
      success: !!product,
      count: products.length,
      propertyCount: Array.isArray(product?.productPropertyList) ? product.productPropertyList.length : 0,
      skuCount: Array.isArray(product?.skuList) ? product.skuList.length : 0,
      error: product ? '' : (listResult?.error || '商品管理未返回匹配商品')
    });
    if (!product) return null;
    return buildMoveProductDetailFromProductManagement(product, inputId, sourceIdType);
  } catch (error) {
    attempts.push({
      source: 'product/skc/pageQuery detail',
      id: inputId,
      success: false,
      error: error?.message || String(error)
    });
    return null;
  }
}

async function tryGetMoveProductDetailByGoodsId(goodsId, auth = {}, source = 'metadata') {
  const normalizedGoodsId = normalizeTemuIdText(goodsId);
  if (!normalizedGoodsId) return { success: false, source, id: '', error: '缺少 goodsId' };
  const result = await getGoodsMetadata(normalizedGoodsId, auth.mallId, auth.antiContent);
  const detail = getMoveProductDetailPayload(result);
  const apiSuccess = result?.success !== false && result?.code !== -1;
  const hasDetail = apiSuccess && hasMoveProductDetailPayload(detail);
  return {
    success: hasDetail,
    source,
    id: normalizedGoodsId,
    result,
    detail,
    error: hasDetail ? '' : getTemuApiMessage(result, 'metadata 未返回完整商品详情')
  };
}

async function collectMoveDetailGoodsIdCandidates(sourceId, sourceIdType, auth = {}, attempts = []) {
  const candidates = [];
  const inputId = normalizeTemuIdText(sourceId);
  if (!inputId) return candidates;

  addMoveDetailCandidate(candidates, inputId, `${sourceIdType || 'input'} direct`);

  try {
    const listResult = await fetchCustomizedProductList({
      pageNo: 1,
      pageSize: 100,
      productId: inputId
    });
    const products = (Array.isArray(listResult?.products) ? listResult.products : [])
      .filter(product => moveDetailProductMatchesInput(product, inputId));
    attempts.push({
      source: 'product/skc/pageQuery',
      id: inputId,
      success: !!listResult?.success,
      count: products.length,
      error: listResult?.success ? '' : (listResult?.error || '商品列表未返回')
    });
    products.forEach(product => {
      const ids = [
        product.goodsId,
        product.productId,
        product.spuId,
        product.skcId,
        product.raw?.goodsId,
        product.raw?.goods_id,
        product.raw?.productId,
        product.raw?.product_id
      ];
      ids.forEach(id => addMoveDetailCandidate(candidates, id, 'product/skc/pageQuery'));
    });
  } catch (error) {
    attempts.push({ source: 'product/skc/pageQuery', id: inputId, success: false, error: error?.message || String(error) });
  }

  try {
    const compliance = await resolveComplianceProductForUpload({ spuId: inputId }, auth);
    attempts.push({
      source: 'compliance_property/page_query',
      id: inputId,
      success: !!compliance?.goodsId,
      error: compliance?.goodsId ? '' : (compliance?.resolveError || '未解析到 goodsId')
    });
    addMoveDetailCandidate(candidates, compliance?.goodsId, 'compliance_property/page_query');
    addMoveDetailCandidate(candidates, compliance?.spuId, 'compliance_property/page_query');
  } catch (error) {
    attempts.push({ source: 'compliance_property/page_query', id: inputId, success: false, error: error?.message || String(error) });
  }

  try {
    const livePhoto = await getLivePhotoList({
      pageNum: 1,
      pageSize: 100,
      ...(sourceIdType === 'skc' ? { goodsId: inputId, idField: 'goods_id' } : { productId: inputId, idField: 'product_id' })
    });
    const list = Array.isArray(livePhoto?.list) ? livePhoto.list : [];
    attempts.push({
      source: 'real_picture/list',
      id: inputId,
      success: !!livePhoto?.success,
      count: list.length,
      error: livePhoto?.success ? '' : (livePhoto?.error || '实拍图列表未返回')
    });
    list.forEach(item => {
      const info = normalizeLivePhotoProductInfo(item, inputId, 'real_picture/list');
      addMoveDetailCandidate(candidates, info?.goodsId, 'real_picture/list');
      addMoveDetailCandidate(candidates, info?.spuId, 'real_picture/list');
    });
  } catch (error) {
    attempts.push({ source: 'real_picture/list', id: inputId, success: false, error: error?.message || String(error) });
  }

  return candidates;
}

async function fetchMoveProductDetailForTemplate(request = {}, auth = {}) {
  const sourceIdType = String(request.sourceIdType || (request.goodsId ? 'skc' : 'spu')).toLowerCase();
  const sourceId = normalizeTemuIdText(sourceIdType === 'skc'
    ? (request.goodsId || request.productId || request.spuId)
    : (request.productId || request.spuId || request.goodsId));
  if (!sourceId) return { success: false, error: '请填写 SPU ID 或 SKC ID' };

  const attempts = [];
  const candidates = await collectMoveDetailGoodsIdCandidates(sourceId, sourceIdType, auth, attempts);
  for (const candidate of candidates) {
    try {
      const result = await tryGetMoveProductDetailByProductId(candidate.id, auth, candidate.source);
      attempts.push({
        source: `product/query via ${candidate.source}`,
        id: candidate.id,
        success: result.success,
        error: result.error || ''
      });
      if (result.success) {
        result.detail.sourceId = sourceId;
        result.detail.sourceIdType = sourceIdType;
        return {
          success: true,
          productDetail: result.detail,
          data: result.detail,
          sourceId,
          sourceIdType,
          resolvedGoodsId: result.detail.goodsId || '',
          resolvedBy: 'product/query',
          attempts
        };
      }
    } catch (error) {
      attempts.push({
        source: `product/query via ${candidate.source}`,
        id: candidate.id,
        success: false,
        error: error?.message || String(error)
      });
    }
  }

  for (const candidate of candidates) {
    try {
      const result = await tryGetMoveProductDetailByGoodsId(candidate.id, auth, candidate.source);
      attempts.push({
        source: `metadata via ${candidate.source}`,
        id: candidate.id,
        success: result.success,
        error: result.error || ''
      });
      if (result.success) {
        return {
          success: true,
          productDetail: result.detail,
          data: result.detail,
          sourceId,
          sourceIdType,
          resolvedGoodsId: candidate.id,
          resolvedBy: candidate.source,
          attempts
        };
      }
    } catch (error) {
      attempts.push({
        source: `metadata via ${candidate.source}`,
        id: candidate.id,
        success: false,
        error: error?.message || String(error)
      });
    }
  }

  const productManagementDetail = await fetchMoveProductManagementProduct(sourceId, sourceIdType, attempts);
  if (hasMoveProductOfficialEditDetail(productManagementDetail)) {
    return {
      success: true,
      productDetail: productManagementDetail,
      data: productManagementDetail,
      sourceId,
      sourceIdType,
      resolvedGoodsId: productManagementDetail.goodsId || productManagementDetail.productId || '',
      resolvedBy: 'product/skc/pageQuery',
      attempts
    };
  }

  return {
    success: false,
    sourceId,
    sourceIdType,
    attempts,
    error: `读取商品详情失败：TEMU 未返回可保存的商品详情。${summarizeMoveDetailAttempts(attempts)}`
  };
}

function cloneTemuUploadOfficialValue(value) {
  if (value === undefined) return undefined;
  try {
    return JSON.parse(JSON.stringify(value));
  } catch (_) {
    return value;
  }
}

function cleanTemuUploadOfficialObject(value) {
  if (Array.isArray(value)) {
    return value
      .map(cleanTemuUploadOfficialObject)
      .filter(item => item !== undefined);
  }
  if (!value || typeof value !== 'object') return value;
  const result = {};
  Object.entries(value).forEach(([key, item]) => {
    const next = cleanTemuUploadOfficialObject(item);
    if (next !== undefined) result[key] = next;
  });
  return result;
}

function normalizeTemuUploadOfficialUrlForCompare(value = '') {
  const text = String(value || '').trim();
  if (!text) return '';
  try {
    return new URL(text).href;
  } catch (_) {
    return text;
  }
}

function createTemuUploadOfficialAllowedUrlSet(urls = []) {
  const raw = new Set();
  const normalized = new Set();
  (Array.isArray(urls) ? urls : []).forEach(url => {
    const text = String(url || '').trim();
    if (!text) return;
    raw.add(text);
    normalized.add(normalizeTemuUploadOfficialUrlForCompare(text));
  });
  return { raw, normalized };
}

function isTemuUploadOfficialUrlLikeKey(key = '') {
  return /(url|uri|img|image|video|file)$/i.test(String(key || ''))
    || /(url|uri|imgUrl|imageUrl|videoUrl|fileUrl)/i.test(String(key || ''));
}

function isTemuUploadOfficialUrlLikeText(value = '') {
  const text = String(value || '').trim();
  return /^https?:\/\//i.test(text) || /^data:/i.test(text) || /https?:\/\//i.test(text);
}

function isTemuUploadOfficialAllowedUploadedUrl(value = '', allowed = createTemuUploadOfficialAllowedUrlSet()) {
  const text = String(value || '').trim();
  if (!text) return false;
  return allowed.raw.has(text) || allowed.normalized.has(normalizeTemuUploadOfficialUrlForCompare(text));
}

function sanitizeTemuUploadOfficialSaveUrls(value, allowed, path = []) {
  if (Array.isArray(value)) {
    return value
      .map((item, index) => sanitizeTemuUploadOfficialSaveUrls(item, allowed, path.concat(String(index))))
      .filter(item => item !== undefined);
  }
  if (value && typeof value === 'object') {
    const result = {};
    Object.entries(value).forEach(([key, item]) => {
      const next = sanitizeTemuUploadOfficialSaveUrls(item, allowed, path.concat(key));
      if (next !== undefined) result[key] = next;
    });
    return result;
  }
  if (typeof value === 'string') {
    const key = path[path.length - 1] || '';
    const text = value.trim();
    if (isTemuUploadOfficialUrlLikeText(text) || isTemuUploadOfficialUrlLikeKey(key)) {
      return isTemuUploadOfficialAllowedUploadedUrl(text, allowed) ? text : undefined;
    }
  }
  return value;
}

function pickTemuUploadOfficialFields(source = {}, keys = []) {
  const result = {};
  keys.forEach(key => {
    if (Object.prototype.hasOwnProperty.call(source || {}, key) && source[key] !== undefined) {
      result[key] = cloneTemuUploadOfficialValue(source[key]);
    }
  });
  return result;
}

function normalizeTemuUploadOfficialNumber(value) {
  if (value === null || value === undefined || value === '') return undefined;
  if (typeof value === 'number' && Number.isFinite(value)) return value;
  const text = String(value).trim();
  if (!text) return undefined;
  const num = Number(text);
  return Number.isFinite(num) ? num : undefined;
}

function getTemuUploadOfficialVolumeInputKey(key = '') {
  if (key === 'len') return 'inputLen';
  if (key === 'width') return 'inputWidth';
  if (key === 'height') return 'inputHeight';
  return '';
}

function normalizeTemuUploadOfficialVolumeDimension(source = {}, key = '') {
  const inputKey = getTemuUploadOfficialVolumeInputKey(key);
  const inputValue = inputKey ? normalizeTemuUploadOfficialNumber(source?.[inputKey]) : undefined;
  if (inputValue !== undefined) {
    return {
      inputValue,
      rawValue: Math.round(inputValue * 10)
    };
  }
  const rawValue = normalizeTemuUploadOfficialNumber(source?.[key]);
  if (rawValue !== undefined) {
    return {
      inputValue: undefined,
      rawValue
    };
  }
  return {
    inputValue: undefined,
    rawValue: undefined
  };
}

function buildTemuUploadOfficialSkuVolumeReq(sourceVolume) {
  if (sourceVolume === undefined || sourceVolume === null) return undefined;
  if (typeof sourceVolume !== 'object') return cloneTemuUploadOfficialValue(sourceVolume);
  const result = cloneTemuUploadOfficialValue(sourceVolume) || {};
  ['len', 'width', 'height'].forEach(key => {
    const inputKey = getTemuUploadOfficialVolumeInputKey(key);
    const normalized = normalizeTemuUploadOfficialVolumeDimension(sourceVolume, key);
    if (normalized.rawValue === undefined) return;
    result[key] = normalized.rawValue;
    if (inputKey && normalized.inputValue !== undefined) {
      result[inputKey] = normalized.inputValue;
    }
  });
  return cleanTemuUploadOfficialObject(result);
}

function buildTemuUploadOfficialSkuWeightReq(sourceWeight) {
  if (sourceWeight === undefined || sourceWeight === null) return undefined;
  if (typeof sourceWeight !== 'object') return cloneTemuUploadOfficialValue(sourceWeight);
  const result = cloneTemuUploadOfficialValue(sourceWeight) || {};
  const inputValue = normalizeTemuUploadOfficialNumber(sourceWeight.inputValue);
  if (inputValue !== undefined) {
    result.inputValue = inputValue;
    result.value = Math.round(inputValue * 1000);
  } else {
    const rawValue = normalizeTemuUploadOfficialNumber(sourceWeight.value);
    if (rawValue !== undefined) result.value = rawValue;
  }
  return cleanTemuUploadOfficialObject(result);
}

function normalizeTemuUploadOfficialActualPrice(value) {
  const num = normalizeTemuUploadOfficialNumber(value);
  if (num === undefined) return undefined;
  return Math.round(num * 100);
}

function buildTemuUploadOfficialSiteSupplierPrices(sourcePrices, fixedSupplierPrice) {
  if (!Array.isArray(sourcePrices)) return undefined;
  return sourcePrices.map(item => {
    if (!item || typeof item !== 'object') return item;
    const result = cloneTemuUploadOfficialValue(item) || {};
    const supplierPrice = fixedSupplierPrice !== undefined
      ? fixedSupplierPrice
      : normalizeTemuUploadOfficialActualPrice(item.supplierPrice ?? item.supplierPriceValue);
    if (supplierPrice !== undefined) result.supplierPrice = supplierPrice;
    if (supplierPrice !== undefined && Object.prototype.hasOwnProperty.call(result, 'supplierPriceValue')) {
      result.supplierPriceValue = supplierPrice;
    }
    return result;
  });
}

function getTemuUploadOfficialResult(data = {}) {
  return data?.result || data?.data || data?.detail || data || {};
}

function getTemuUploadOfficialPayload(data = {}) {
  const result = getTemuUploadOfficialResult(data);
  if (result?.res && typeof result.res === 'object') return result.res;
  if (data?.res && typeof data.res === 'object') return data.res;
  return result;
}

function getTemuUploadOfficialLeafCatId(detail = {}) {
  const direct = normalizeTemuUploadOfficialNumber(detail.catId || detail.categoryId || detail.leafCatId);
  if (direct) return direct;
  const categories = detail.categories && typeof detail.categories === 'object' ? detail.categories : null;
  if (categories) {
    for (let i = 10; i >= 1; i--) {
      const catId = normalizeTemuUploadOfficialNumber(categories[`cat${i}`]?.catId);
      if (catId) return catId;
    }
  }
  const categoryList = Array.isArray(detail.categoryList) ? detail.categoryList : [];
  for (let i = categoryList.length - 1; i >= 0; i--) {
    const catId = normalizeTemuUploadOfficialNumber(categoryList[i]?.catId || categoryList[i]?.id);
    if (catId) return catId;
  }
  return undefined;
}

function buildTemuUploadOfficialCategoryIds(detail = {}) {
  const result = {};
  const categories = detail.categories && typeof detail.categories === 'object' ? detail.categories : null;
  if (categories) {
    for (let i = 1; i <= 10; i++) {
      result[`cat${i}Id`] = normalizeTemuUploadOfficialNumber(categories[`cat${i}`]?.catId) || 0;
    }
    return result;
  }
  const categoryList = Array.isArray(detail.categoryList) ? detail.categoryList : [];
  categoryList.slice(0, 10).forEach((item, index) => {
    result[`cat${index + 1}Id`] = normalizeTemuUploadOfficialNumber(item?.catId || item?.id) || 0;
  });
  const leafCatId = getTemuUploadOfficialLeafCatId(detail);
  if (leafCatId && !Object.values(result).some(Boolean)) result.cat1Id = leafCatId;
  return result;
}

function buildTemuUploadOfficialDraftAddBody(detail = {}) {
  const catId = getTemuUploadOfficialLeafCatId(detail);
  if (!catId) throw new Error('模板缺少 TEMU 官方类目 ID，不能创建草稿');
  const body = { catId };
  const semiReq = detail.productSemiManagedReq || detail.productSemiManaged || null;
  if (semiReq && typeof semiReq === 'object') {
    const bindSiteIds = Array.isArray(semiReq.bindSiteIds) ? semiReq.bindSiteIds.filter(Boolean) : [];
    if (bindSiteIds.length) {
      body.productSemiManagedReq = cleanTemuUploadOfficialObject({
        ...cloneTemuUploadOfficialValue(semiReq),
        bindSiteIds
      });
    }
  }
  const routeReq = detail.productWarehouseRouteReq || detail.productWarehouseRoute || null;
  if (routeReq && typeof routeReq === 'object') body.productWarehouseRouteReq = cloneTemuUploadOfficialValue(routeReq);
  return cleanTemuUploadOfficialObject(body);
}

async function fetchTemuUploadOfficialCategoryTemplate(detail = {}, auth = {}) {
  const catId = getTemuUploadOfficialLeafCatId(detail);
  if (!catId) throw new Error('模板缺少 TEMU 官方类目 ID，不能读取类目规格');
  const body = cleanTemuUploadOfficialObject({
    catId,
    productCreateTime: detail.productCreateTime
  });
  const data = await temuSellerPost(
    'https://agentseller.temu.com/anniston-agent-seller/category/template/query',
    body,
    auth,
    30000
  );
  if (!isTemuApiSuccess(data)) {
    throw new Error(getTemuApiMessage(data, 'TEMU 类目模板接口读取失败'));
  }
  const categoryTemplate = getTemuUploadOfficialPayload(data);
  if (!categoryTemplate || typeof categoryTemplate !== 'object') {
    throw new Error('TEMU 类目模板接口未返回可用数据');
  }
  if (!Array.isArray(categoryTemplate.properties)) {
    throw new Error('TEMU 类目模板接口未返回规格属性列表');
  }
  return categoryTemplate;
}

function isTemuUploadOfficialTruthy(value) {
  if (value === true || value === 1 || value === '1') return true;
  if (typeof value === 'string') return value.trim().toLowerCase() === 'true';
  return false;
}

function getTemuUploadOfficialCategoryProperties(categoryTemplate = {}) {
  if (Array.isArray(categoryTemplate?.properties)) return categoryTemplate.properties;
  if (Array.isArray(categoryTemplate?.res?.properties)) return categoryTemplate.res.properties;
  if (Array.isArray(categoryTemplate?.result?.properties)) return categoryTemplate.result.properties;
  return [];
}

function collectTemuUploadOfficialSkuSpecParentIds(detail = {}, categoryTemplate = {}) {
  const ids = [];
  const addId = (value) => {
    const id = normalizeTemuUploadOfficialNumber(value);
    if (id && !ids.includes(id)) ids.push(id);
  };
  const categoryProperties = getTemuUploadOfficialCategoryProperties(categoryTemplate);
  const saleParentIds = categoryProperties
    .filter(item => isTemuUploadOfficialTruthy(item?.isSale))
    .map(item => normalizeTemuUploadOfficialNumber(item?.parentSpecId))
    .filter(Boolean);
  const categoryParentIds = categoryProperties
    .map(item => normalizeTemuUploadOfficialNumber(item?.parentSpecId))
    .filter(Boolean);
  const allowParentId = (parentSpecId) => {
    if (!parentSpecId) return false;
    if (saleParentIds.length) return saleParentIds.includes(parentSpecId);
    if (categoryParentIds.length) return categoryParentIds.includes(parentSpecId);
    return true;
  };
  (Array.isArray(detail.productSkcList) ? detail.productSkcList : []).forEach(sourceSkc => {
    (Array.isArray(sourceSkc?.productSkuList) ? sourceSkc.productSkuList : []).forEach(sourceSku => {
      getTemuUploadOfficialSkuSpecSource(sourceSku).forEach(spec => {
        const parentSpecId = normalizeTemuUploadOfficialNumber(spec?.parentSpecId);
        const specId = normalizeTemuUploadOfficialNumber(spec?.specId);
        const specName = getTemuUploadOfficialSpecName(spec);
        if (parentSpecId && specId && specName && allowParentId(parentSpecId)) addId(parentSpecId);
      });
    });
  });
  if (ids.length && categoryProperties.length) {
    const order = new Map(categoryProperties.map((item, index) => [normalizeTemuUploadOfficialNumber(item?.parentSpecId), index]));
    ids.sort((a, b) => (order.get(a) ?? 9999) - (order.get(b) ?? 9999));
  }
  return ids;
}

function getTemuUploadOfficialMainParentSpecIds(detail = {}, categoryTemplate = {}) {
  const ids = [];
  const addId = (value) => {
    const id = normalizeTemuUploadOfficialNumber(value);
    if (id && !ids.includes(id)) ids.push(id);
  };
  if (Array.isArray(detail.mainParentSpecIds)) {
    detail.mainParentSpecIds.forEach(addId);
  } else {
    addId(detail.mainParentSpecIds || detail.mainParentSpecId);
  }
  getTemuUploadOfficialCategoryProperties(categoryTemplate)
    .filter(item => isTemuUploadOfficialTruthy(item?.isSale) && isTemuUploadOfficialTruthy(item?.mainSale))
    .forEach(item => addId(item.parentSpecId));
  if (!ids.length) collectTemuUploadOfficialSkuSpecParentIds(detail, categoryTemplate).forEach(addId);
  if (!ids.length) {
    throw new Error('模板 SKU 未包含可用 TEMU 销售规格，无法保存草稿');
  }
  return ids;
}

function buildTemuUploadOfficialProductI18nReqs(detail = {}) {
  const source = Array.isArray(detail.productI18nReqs)
    ? detail.productI18nReqs
    : Array.isArray(detail.productI18nList)
      ? detail.productI18nList
      : [];
  const rows = source.map(item => {
    const language = item?.language || item?.lang;
    const productName = String(item?.productName || '').trim();
    if (!language || !productName) return null;
    return cleanTemuUploadOfficialObject({
      ...pickTemuUploadOfficialFields(item, ['language', 'lang']),
      productName
    });
  }).filter(Boolean);
  if (rows.length) return rows;
  return undefined;
}

function getTemuUploadOfficialPersonalizationSwitch(detail = {}) {
  const value = detail.personalizationSwitch
    ?? detail.productWhExtAttr?.personalizationSwitch
    ?? detail.productWhExtAttrReq?.personalizationSwitch
    ?? detail.productSaleExtAttr?.personalizationSwitch
    ?? detail.productSaleExtAttrReq?.personalizationSwitch;
  const num = normalizeTemuUploadOfficialNumber(value);
  return num === undefined ? undefined : num;
}

function buildTemuUploadOfficialProductSaleExtAttrReq(detail = {}) {
  const source = detail.productSaleExtAttrReq || detail.productSaleExtAttr || {};
  const result = source && typeof source === 'object' ? cloneTemuUploadOfficialValue(source) : {};
  const technology = result.customizedTechnologyReq || result.productCustomizationTechnology || detail.customizedTechnologyReq;
  if (technology && typeof technology === 'object') {
    result.customizedTechnologyReq = cleanTemuUploadOfficialObject({
      twiceType: cloneTemuUploadOfficialValue(technology.twiceType),
      firstType: normalizeTemuUploadOfficialNumber(technology.firstType),
      technologyType: normalizeTemuUploadOfficialNumber(technology.technologyType)
    });
  }
  delete result.productCustomizationTechnology;
  return cleanTemuUploadOfficialObject(result);
}

function buildTemuUploadOfficialPropertyReqs(detail = {}) {
  if (Array.isArray(detail.productPropertyReqs)) return cloneTemuUploadOfficialValue(detail.productPropertyReqs);
  const list = Array.isArray(detail.productPropertyList) ? detail.productPropertyList : [];
  return list.map(item => pickTemuUploadOfficialFields(item, [
    'templatePid', 'pid', 'refPid', 'propName', 'vid', 'propValue',
    'valueUnit', 'valueExtendInfo', 'numberInputValue'
  ])).filter(item => item.refPid || item.pid || item.templatePid);
}

function buildTemuUploadOfficialSpecPropertyReqs(detail = {}, categoryTemplate = {}, options = {}) {
  if (Array.isArray(detail.productSpecPropertyReqs) && detail.productSpecPropertyReqs.length) {
    return cloneTemuUploadOfficialValue(detail.productSpecPropertyReqs);
  }
  const list = Array.isArray(detail.productSpecPropertyVOS) ? detail.productSpecPropertyVOS : [];
  const directReqs = list.map(item => pickTemuUploadOfficialFields(item, [
    'templatePid', 'pid', 'refPid', 'propName', 'vid', 'propValue',
    'valueUnit', 'valueExtendInfo', 'numberInputValue', 'parentSpecId',
    'specId', 'valueGroupId', 'valueGroupName'
  ])).filter(item => item.refPid || item.pid || item.templatePid);
  if (directReqs.length) return directReqs;
  const categoryProperties = getTemuUploadOfficialCategoryProperties(categoryTemplate);
  if (!categoryProperties.length) return [];
  return buildTemuUploadOfficialSpecPropertyReqsFromSkus(detail, {
    ...options,
    productSpecPropertyVOS: list,
    categoryProperties
  });
}

function getTemuUploadOfficialSpecName(spec = {}) {
  return String(spec.specName ?? spec.specValue ?? spec.value ?? spec.name ?? '').trim();
}

function getTemuUploadOfficialSpecParentName(spec = {}) {
  return String(spec.parentSpecName ?? spec.parentName ?? spec.namePath ?? '').trim();
}

function findTemuUploadOfficialSpecMeta(spec = {}, options = {}) {
  const productSpecPropertyVOS = Array.isArray(options.productSpecPropertyVOS) ? options.productSpecPropertyVOS : [];
  const categoryProperties = Array.isArray(options.categoryProperties) ? options.categoryProperties : [];
  const specId = normalizeTemuUploadOfficialNumber(spec.specId);
  const parentSpecId = normalizeTemuUploadOfficialNumber(spec.parentSpecId);
  const groupId = normalizeTemuUploadOfficialNumber(spec.groupId || spec.valueGroupId);
  const vid = normalizeTemuUploadOfficialNumber(spec.vid);
  const fromTemplate = productSpecPropertyVOS.find(item => {
    const itemSpecId = normalizeTemuUploadOfficialNumber(item?.specId);
    if (specId && itemSpecId !== specId) return false;
    if (parentSpecId && normalizeTemuUploadOfficialNumber(item?.parentSpecId) && normalizeTemuUploadOfficialNumber(item?.parentSpecId) !== parentSpecId) return false;
    if (vid && normalizeTemuUploadOfficialNumber(item?.vid) && normalizeTemuUploadOfficialNumber(item?.vid) !== vid) return false;
    return itemSpecId || normalizeTemuUploadOfficialNumber(item?.vid);
  });
  const property = categoryProperties.find(item => normalizeTemuUploadOfficialNumber(item?.parentSpecId) === parentSpecId);
  const values = Array.isArray(property?.values) ? property.values : [];
  const matchedValues = values.filter(item => {
    const itemSpecId = normalizeTemuUploadOfficialNumber(item?.specId);
    const itemGroupId = normalizeTemuUploadOfficialNumber(item?.group?.id || item?.groupId || item?.valueGroupId);
    if (specId && itemSpecId !== specId) return false;
    if (groupId && itemGroupId && itemGroupId !== groupId) return false;
    return itemSpecId || normalizeTemuUploadOfficialNumber(item?.vid);
  });
  let value = matchedValues[0] || null;
  if (matchedValues.length > 1 && vid) {
    value = matchedValues.find(item => normalizeTemuUploadOfficialNumber(item?.vid) === vid) || value;
  }
  return {
    property,
    value,
    groupId: normalizeTemuUploadOfficialNumber(spec.groupId || spec.valueGroupId || fromTemplate?.groupId || fromTemplate?.valueGroupId || value?.group?.id || value?.groupId || value?.valueGroupId),
    groupName: spec.groupName || spec.valueGroupName || fromTemplate?.groupName || fromTemplate?.valueGroupName || value?.group?.name || value?.groupName || value?.valueGroupName || '',
    vid: normalizeTemuUploadOfficialNumber(spec.vid || fromTemplate?.vid || value?.vid),
    valueExtendInfo: spec.valueExtendInfo ?? fromTemplate?.valueExtendInfo ?? value?.extendInfo ?? ''
  };
}

function toTemuUploadOfficialSpecReq(spec = {}, options = {}) {
  const meta = findTemuUploadOfficialSpecMeta(spec, options);
  return cleanTemuUploadOfficialObject({
    parentSpecId: normalizeTemuUploadOfficialNumber(spec.parentSpecId) || 0,
    parentSpecName: getTemuUploadOfficialSpecParentName(spec),
    specId: normalizeTemuUploadOfficialNumber(spec.specId) || 0,
    specName: getTemuUploadOfficialSpecName(spec),
    groupId: meta.groupId,
    vid: meta.vid
  });
}

function isTemuUploadOfficialValidSpecReq(spec = {}) {
  return Boolean(
    normalizeTemuUploadOfficialNumber(spec.parentSpecId)
    && normalizeTemuUploadOfficialNumber(spec.specId)
    && String(spec.specName || '').trim()
  );
}

function uniqueTemuUploadOfficialSpecs(specs = []) {
  const seen = new Set();
  return specs.filter(spec => {
    const key = [
      normalizeTemuUploadOfficialNumber(spec.parentSpecId) || 0,
      normalizeTemuUploadOfficialNumber(spec.specId) || 0,
      normalizeTemuUploadOfficialNumber(spec.groupId || spec.valueGroupId) || 0,
      normalizeTemuUploadOfficialNumber(spec.vid) || 0,
      String(spec.specName || '').trim()
    ].join(':');
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
}

function getTemuUploadOfficialSkuSpecSource(sourceSku = {}) {
  const specs = Array.isArray(sourceSku.productSkuSpecReqs)
    ? sourceSku.productSkuSpecReqs
    : Array.isArray(sourceSku.productSkuSpecList)
      ? sourceSku.productSkuSpecList
      : [];
  return specs;
}

function buildTemuUploadOfficialSkuSpecReqs(sourceSku = {}, options = {}) {
  return uniqueTemuUploadOfficialSpecs(
    getTemuUploadOfficialSkuSpecSource(sourceSku)
      .map(spec => toTemuUploadOfficialSpecReq(spec, options))
      .filter(isTemuUploadOfficialValidSpecReq)
  );
}

function buildTemuUploadOfficialSkcMainSpecReqs(sourceSkc = {}, options = {}) {
  const explicitSpecs = Array.isArray(sourceSkc.mainProductSkuSpecReqs)
    ? sourceSkc.mainProductSkuSpecReqs
    : Array.isArray(sourceSkc.mainSpec)
      ? sourceSkc.mainSpec
      : [];
  const explicitReqs = uniqueTemuUploadOfficialSpecs(
    explicitSpecs
      .map(spec => toTemuUploadOfficialSpecReq(spec, options))
      .filter(isTemuUploadOfficialValidSpecReq)
  );
  if (explicitReqs.length) return explicitReqs;

  const mainParentSpecIds = Array.isArray(options.mainParentSpecIds) ? options.mainParentSpecIds : [];
  const sourceSkus = Array.isArray(sourceSkc.productSkuList) ? sourceSkc.productSkuList : [];
  const derivedReqs = [];
  sourceSkus.forEach(sourceSku => {
    getTemuUploadOfficialSkuSpecSource(sourceSku).forEach(spec => {
      const parentSpecId = normalizeTemuUploadOfficialNumber(spec?.parentSpecId);
      if (!parentSpecId || !mainParentSpecIds.includes(parentSpecId)) return;
      const req = toTemuUploadOfficialSpecReq(spec, options);
      if (isTemuUploadOfficialValidSpecReq(req)) derivedReqs.push(req);
    });
  });
  const uniqueReqs = uniqueTemuUploadOfficialSpecs(derivedReqs);
  if (!uniqueReqs.length) {
    throw new Error('模板 SKU 未包含 TEMU 主销售规格，无法保存草稿');
  }
  return uniqueReqs;
}

function toTemuUploadOfficialSpecPropertyReq(spec = {}, options = {}) {
  const categoryProperties = Array.isArray(options.categoryProperties) ? options.categoryProperties : [];
  const meta = findTemuUploadOfficialSpecMeta(spec, options);
  const property = meta.property || categoryProperties.find(item => normalizeTemuUploadOfficialNumber(item?.parentSpecId) === normalizeTemuUploadOfficialNumber(spec.parentSpecId));
  if (!property?.pid || !property?.templatePid) return null;
  const req = toTemuUploadOfficialSpecReq(spec, options);
  if (!isTemuUploadOfficialValidSpecReq(req)) return null;
  return cleanTemuUploadOfficialObject({
    ...req,
    refPid: normalizeTemuUploadOfficialNumber(property.refPid) || 0,
    pid: normalizeTemuUploadOfficialNumber(property.pid) || 0,
    templatePid: normalizeTemuUploadOfficialNumber(property.templatePid) || 0,
    propName: req.parentSpecName || property.name || '',
    vid: meta.vid || 0,
    propValue: req.specName || '',
    valueUnit: '',
    valueGroupId: meta.groupId || 0,
    valueGroupName: meta.groupName || '',
    valueExtendInfo: meta.valueExtendInfo || ''
  });
}

function buildTemuUploadOfficialSpecPropertyReqsFromSkus(detail = {}, options = {}) {
  const reqs = [];
  (Array.isArray(detail.productSkcList) ? detail.productSkcList : []).forEach(sourceSkc => {
    (Array.isArray(sourceSkc?.productSkuList) ? sourceSkc.productSkuList : []).forEach(sourceSku => {
      getTemuUploadOfficialSkuSpecSource(sourceSku).forEach(spec => {
        const req = toTemuUploadOfficialSpecPropertyReq(spec, options);
        if (req) reqs.push(req);
      });
    });
  });
  return uniqueTemuUploadOfficialSpecs(reqs);
}

function buildTemuUploadOfficialSkuWhExtAttrReq(sourceSku = {}) {
  const wh = sourceSku.productSkuWhExtAttrReq || sourceSku.productSkuWhExtAttr || {};
  return cleanTemuUploadOfficialObject({
    productSkuVolumeReq: buildTemuUploadOfficialSkuVolumeReq(wh.productSkuVolumeReq || wh.productSkuVolume),
    productSkuWeightReq: buildTemuUploadOfficialSkuWeightReq(wh.productSkuWeightReq || wh.productSkuWeight),
    productSkuNetWeightReq: cloneTemuUploadOfficialValue(wh.productSkuNetWeightReq || wh.productSkuNetWeight),
    productSkuBarCodeReqs: cloneTemuUploadOfficialValue(wh.productSkuBarCodeReqs || wh.productSkuBarCodes),
    productSkuSensitiveAttrReq: cloneTemuUploadOfficialValue(
      wh.productSkuSensitiveAttrReq ||
      wh.productSkuSensitiveAttr ||
      (wh.isSensitive !== undefined || Array.isArray(wh.sensitiveList) ? {
        isSensitive: wh.isSensitive,
        sensitiveList: wh.sensitiveList || []
      } : undefined)
    ),
    productSkuSensitiveLimitReq: cloneTemuUploadOfficialValue(wh.productSkuSensitiveLimitReq || wh.productSkuSensitiveLimit)
  });
}

function getTemuUploadOfficialSkuPrice(sourceSku = {}) {
  const price = normalizeTemuUploadOfficialActualPrice(sourceSku.supplierPrice ?? sourceSku.supplierPriceValue);
  if (price !== undefined) return price;
  const sitePrice = Array.isArray(sourceSku.siteSupplierPrices)
    ? normalizeTemuUploadOfficialActualPrice(sourceSku.siteSupplierPrices[0]?.supplierPrice ?? sourceSku.siteSupplierPrices[0]?.supplierPriceValue)
    : undefined;
  return sitePrice;
}

function buildTemuUploadOfficialSkuReq(sourceSku = {}, options = {}) {
  const {
    skuIndex = 0,
    row = {},
    skuImagePlan = [],
    uploadedImageUrls = [],
    currencyType = ''
  } = options;
  const plan = Array.isArray(skuImagePlan) ? skuImagePlan[skuIndex] : null;
  const selectedIndex = normalizeTemuUploadOfficialNumber(plan?.carouselImageIndex);
  const imageUrl = Number.isInteger(selectedIndex) && selectedIndex >= 0
    ? uploadedImageUrls[selectedIndex]
    : uploadedImageUrls[skuIndex % Math.max(uploadedImageUrls.length, 1)];
  if (!imageUrl) throw new Error(`第 ${skuIndex + 1} 个 SKU 未匹配到已上传的 SKU 图片`);
  const extCodeBase = String(row.spuCode || sourceSku.extCode || '').trim();
  const extCode = extCodeBase
    ? (skuImagePlan.length > 1 ? `${extCodeBase}-${skuIndex + 1}` : extCodeBase)
    : String(sourceSku.extCode || '').trim();
  const supplierPrice = getTemuUploadOfficialSkuPrice(sourceSku);
  const siteSupplierPrices = Array.isArray(sourceSku.siteSupplierPrices)
    ? buildTemuUploadOfficialSiteSupplierPrices(sourceSku.siteSupplierPrices, supplierPrice)
    : undefined;
  const productSkuSpecReqs = buildTemuUploadOfficialSkuSpecReqs(sourceSku, options);
  if (!productSkuSpecReqs.length) throw new Error(`第 ${skuIndex + 1} 个 SKU 缺少 TEMU 官方规格，无法保存草稿`);
  return cleanTemuUploadOfficialObject({
    thumbUrl: imageUrl,
    productSkuThumbUrlI18nReqs: [],
    extCode,
    supplierPrice,
    siteSupplierPrices,
    currencyType: sourceSku.currencyType || currencyType || undefined,
    productSkuSpecReqs,
    productSkuId: 0,
    productSkuSuggestedPriceReq: cloneTemuUploadOfficialValue(sourceSku.productSkuSuggestedPriceReq || sourceSku.productSkuSuggestedPrice),
    productSkuUsSuggestedPriceReq: cloneTemuUploadOfficialValue(sourceSku.productSkuUsSuggestedPriceReq || sourceSku.productSkuUsSuggestedPrice),
    productSkuWhExtAttrReq: buildTemuUploadOfficialSkuWhExtAttrReq(sourceSku),
    productSkuMultiPackReq: cloneTemuUploadOfficialValue(sourceSku.productSkuMultiPackReq || sourceSku.productSkuMultiPack),
    productSkuStockQuantityReq: cloneTemuUploadOfficialValue(sourceSku.productSkuStockQuantityReq || sourceSku.productSkuQuantity),
    productSkuAccessoriesReq: cloneTemuUploadOfficialValue(sourceSku.productSkuAccessoriesReq || sourceSku.productSkuAccessories),
    productSkuNonAuditExtAttrReq: cloneTemuUploadOfficialValue(sourceSku.productSkuNonAuditExtAttrReq || sourceSku.productSkuNonAuditExtAttr)
  });
}

function buildTemuUploadOfficialSkcReqs(detail = {}, options = {}) {
  const sourceSkcs = Array.isArray(detail.productSkcList) ? detail.productSkcList : [];
  let skuIndex = 0;
  const uploadedImageUrls = options.uploadedImageUrls || [];
  if (!sourceSkcs.length) throw new Error('模板缺少 TEMU 官方 SKC/SKU 信息');
  return sourceSkcs.map(sourceSkc => {
    const sourceSkus = Array.isArray(sourceSkc.productSkuList) ? sourceSkc.productSkuList : [];
    const productSkuReqs = sourceSkus.map(sourceSku => buildTemuUploadOfficialSkuReq(sourceSku, {
      ...options,
      skuIndex: skuIndex++
    }));
    return cleanTemuUploadOfficialObject({
      previewImgUrls: uploadedImageUrls,
      productSkcCarouselImageI18nReqs: [],
      extCode: String(options.row?.spuCode || sourceSkc.extCode || '').trim(),
      mainProductSkuSpecReqs: buildTemuUploadOfficialSkcMainSpecReqs(sourceSkc, options),
      productSkuReqs,
      productSkcId: 0,
      colorImageUrl: uploadedImageUrls[0],
      bomId: sourceSkc.bomId,
      isBasePlate: sourceSkc.isBasePlate || sourceSkc.productSkcWhExtAttr?.isBasePlate
    });
  });
}

function replaceTemuUploadOfficialUrlFields(value, uploadedUrl = '', path = []) {
  if (!uploadedUrl) return cloneTemuUploadOfficialValue(value);
  if (Array.isArray(value)) {
    return value.map((item, index) => replaceTemuUploadOfficialUrlFields(item, uploadedUrl, path.concat(String(index))));
  }
  if (value && typeof value === 'object') {
    const result = {};
    Object.entries(value).forEach(([key, item]) => {
      if (typeof item === 'string' && (isTemuUploadOfficialUrlLikeKey(key) || isTemuUploadOfficialUrlLikeText(item))) {
        result[key] = uploadedUrl;
      } else {
        result[key] = replaceTemuUploadOfficialUrlFields(item, uploadedUrl, path.concat(key));
      }
    });
    return cleanTemuUploadOfficialObject(result);
  }
  if (typeof value === 'string' && isTemuUploadOfficialUrlLikeText(value)) return uploadedUrl;
  return value;
}

function normalizeTemuUploadOfficialOuterPackageImageReq(item, uploadedUrl = '') {
  if (!uploadedUrl) return undefined;
  const source = item && typeof item === 'object' ? item : {};
  const normalized = replaceTemuUploadOfficialUrlFields(source, uploadedUrl);
  const result = normalized && typeof normalized === 'object' ? normalized : {};
  if (!Object.values(result).some(value => String(value || '').trim() === uploadedUrl)) {
    result.imageUrl = uploadedUrl;
  }
  return cleanTemuUploadOfficialObject(result);
}

function buildTemuUploadOfficialOuterPackageImageReqs(detail = {}, uploadedImageUrls = []) {
  const uploadedUrl = String((Array.isArray(uploadedImageUrls) ? uploadedImageUrls[0] : '') || '').trim();
  if (!uploadedUrl) return undefined;
  const sourceImages = Array.isArray(detail.productOuterPackageImageReqs) && detail.productOuterPackageImageReqs.length
    ? detail.productOuterPackageImageReqs
    : Array.isArray(detail.outerPackageImages) && detail.outerPackageImages.length
      ? detail.outerPackageImages
      : Array.isArray(detail.productOuterPackageImages) && detail.productOuterPackageImages.length
        ? detail.productOuterPackageImages
        : [];
  const reqs = sourceImages
    .map(item => normalizeTemuUploadOfficialOuterPackageImageReq(item, uploadedUrl))
    .filter(Boolean);
  return reqs.length ? reqs : [{ imageUrl: uploadedUrl }];
}

function buildTemuUploadOfficialOuterPackageReq(detail = {}) {
  if (detail.productOuterPackageReq && typeof detail.productOuterPackageReq === 'object') {
    return cloneTemuUploadOfficialValue(detail.productOuterPackageReq);
  }
  const source = detail.productWhExtAttr?.productOuterPackage || detail.productOuterPackage || detail.productWhExtAttr?.outerPackage || {};
  return cleanTemuUploadOfficialObject({
    packageShape: source.packageShape ?? source.shape,
    packageType: source.packageType ?? source.type
  });
}

function buildTemuUploadOfficialWhExtAttrReq(detail = {}) {
  if (detail.productWhExtAttrReq && typeof detail.productWhExtAttrReq === 'object') {
    return cloneTemuUploadOfficialValue(detail.productWhExtAttrReq);
  }
  const wh = detail.productWhExtAttr || {};
  return cleanTemuUploadOfficialObject({
    outerGoodsUrl: wh.outerGoodsUrl || '',
    productOrigin: cloneTemuUploadOfficialValue(wh.productOrigin)
  });
}

function buildTemuUploadOfficialSaveBody(params = {}) {
  const detail = params.detail || {};
  const row = params.row || {};
  const uploadedImageUrls = params.uploadedImageUrls || [];
  const productDraftId = normalizeTemuUploadOfficialNumber(params.productDraftId);
  if (!productDraftId) throw new Error('TEMU 未返回 productDraftId，不能保存草稿');
  if (!String(row.title || '').trim()) throw new Error('缺少上传标题');
  if (!uploadedImageUrls.length) throw new Error('图片尚未上传到 TEMU');
  const currencyType = detail.supplierCurrencyInfo?.currencyType || '';
  const productSaleExtAttrReq = buildTemuUploadOfficialProductSaleExtAttrReq(detail);
  const productNonAuditExtAttrReq = detail.productNonAuditExtAttrReq || {};
  const productNonAuditExtAttr = detail.productNonAuditExtAttr || {};
  const categoryTemplate = params.categoryTemplate || {};
  const categoryProperties = getTemuUploadOfficialCategoryProperties(categoryTemplate);
  const mainParentSpecIds = Array.isArray(params.mainParentSpecIds) ? params.mainParentSpecIds : [];
  const specBuildOptions = {
    mainParentSpecIds,
    productSpecPropertyVOS: Array.isArray(detail.productSpecPropertyVOS) ? detail.productSpecPropertyVOS : [],
    categoryProperties
  };
  const saveBody = cleanTemuUploadOfficialObject({
    ...buildTemuUploadOfficialCategoryIds(detail),
    materialMultiLanguages: Array.isArray(detail.materialMultiLanguages)
      ? cloneTemuUploadOfficialValue(detail.materialMultiLanguages)
      : Array.isArray(detail.imageLanguageList)
        ? cloneTemuUploadOfficialValue(detail.imageLanguageList)
        : undefined,
    productName: String(row.title || '').trim(),
    productI18nReqs: buildTemuUploadOfficialProductI18nReqs(detail),
    goodsI18nReqs: cloneTemuUploadOfficialValue(detail.goodsI18nReqs || detail.goodsI18nList),
    productPropertyReqs: buildTemuUploadOfficialPropertyReqs(detail),
    productSkcReqs: buildTemuUploadOfficialSkcReqs(detail, {
      row,
      uploadedImageUrls,
      skuImagePlan: params.skuImagePlan || [],
      currencyType,
      ...specBuildOptions
    }),
    productSpecPropertyReqs: buildTemuUploadOfficialSpecPropertyReqs(detail, categoryTemplate, specBuildOptions),
    carouselImageUrls: uploadedImageUrls,
    carouselImageI18nReqs: [],
    materialImgUrl: uploadedImageUrls[0],
    goodsLayerDecorationReqs: undefined,
    goodsLayerDecorationCustomizeI18nReqs: undefined,
    sizeTemplateIds: cloneTemuUploadOfficialValue(detail.sizeTemplateIds) || [],
    showSizeTemplateIds: cloneTemuUploadOfficialValue(detail.showSizeTemplateIds) || [],
    goodsModelReqs: cloneTemuUploadOfficialValue(detail.goodsModelReqs || detail.goodsModelList) || [],
    productWhExtAttrReq: buildTemuUploadOfficialWhExtAttrReq(detail),
    productCarouseVideoReqList: undefined,
    goodsAdvantageLabelTypes: Array.isArray(detail.goodsAdvantageLabelTypes)
      ? cloneTemuUploadOfficialValue(detail.goodsAdvantageLabelTypes)
      : Array.isArray(detail.goodsAdvantageLabelVOList)
        ? detail.goodsAdvantageLabelVOList.map(item => item?.type || item?.labelType).filter(Boolean)
        : undefined,
    productDetailVideoReqList: undefined,
    productOuterPackageImageReqs: undefined,
    productOuterPackageReq: buildTemuUploadOfficialOuterPackageReq(detail),
    sensitiveTransNormalFileReqs: undefined,
    personalizationSwitch: getTemuUploadOfficialPersonalizationSwitch(detail),
    productSaleExtAttrReq,
    productNonAuditExtAttrReq: {
      ...cloneTemuUploadOfficialValue(productNonAuditExtAttrReq),
      cosmeticInfoReq: cloneTemuUploadOfficialValue(productNonAuditExtAttr.cosmeticInfoReq || productNonAuditExtAttr.cosmeticInfoVO)
    },
    productShipmentReq: cloneTemuUploadOfficialValue(detail.productShipmentReq),
    productWarehouseRouteReq: cloneTemuUploadOfficialValue(detail.productWarehouseRouteReq || detail.productWarehouseRoute),
    productSemiManagedReq: cloneTemuUploadOfficialValue(detail.productSemiManagedReq || detail.productSemiManaged),
    productComplianceStatementReq: cloneTemuUploadOfficialValue(detail.productComplianceStatementReq),
    productOriginCertFileReqs: [],
    productAssembleReq: cloneTemuUploadOfficialValue(detail.productAssembleReq),
    vehicleLibraryRelationDTOList: cloneTemuUploadOfficialValue(detail.vehicleLibraryRelationDTOList),
    productDraftId
  });
  const allowedUrls = createTemuUploadOfficialAllowedUrlSet(uploadedImageUrls);
  return cleanTemuUploadOfficialObject(sanitizeTemuUploadOfficialSaveUrls(saveBody, allowedUrls));
}

function hasTemuUploadDraftDetailSkuContent(detail = {}) {
  if (Array.isArray(detail.productSkcReqs)
    && detail.productSkcReqs.some(skc => Array.isArray(skc?.productSkuReqs) && skc.productSkuReqs.length)) {
    return true;
  }
  if (Array.isArray(detail.productSkcList)
    && detail.productSkcList.some(skc => Array.isArray(skc?.productSkuList) && skc.productSkuList.length)) {
    return true;
  }
  return false;
}

function hasTemuUploadDraftDetailImageContent(detail = {}, uploadedImageUrls = []) {
  const uploadedSet = createTemuUploadOfficialAllowedUrlSet(uploadedImageUrls);
  const found = [];
  const scan = (value, depth = 0) => {
    if (!value || depth > 5 || found.length) return;
    if (typeof value === 'string') {
      if (isTemuUploadOfficialUrlLikeText(value) && (
        !uploadedImageUrls.length || isTemuUploadOfficialAllowedUploadedUrl(value, uploadedSet)
      )) {
        found.push(value);
      }
      return;
    }
    if (Array.isArray(value)) {
      value.forEach(item => scan(item, depth + 1));
      return;
    }
    if (typeof value === 'object') {
      Object.entries(value).forEach(([key, item]) => {
        if (found.length) return;
        if (typeof item === 'string' && (isTemuUploadOfficialUrlLikeKey(key) || isTemuUploadOfficialUrlLikeText(item))) {
          scan(item, depth + 1);
        } else if (/(carousel|material|thumb|image|img|preview|skc|sku)/i.test(key)) {
          scan(item, depth + 1);
        }
      });
    }
  };
  scan({
    carouselImageUrls: detail.carouselImageUrls,
    materialImgUrl: detail.materialImgUrl,
    productSkcReqs: detail.productSkcReqs,
    productSkcList: detail.productSkcList
  });
  return found.length > 0;
}

async function verifyTemuUploadSavedDraft(productDraftId, row = {}, uploadedImageUrls = [], auth = {}) {
  try {
    const { detail, raw } = await retryTemuTransientOperation(
      () => fetchTemuProductDraftDetail(productDraftId, auth),
      { retries: 2 }
    );
    const title = String(detail?.productName || '').trim();
    const hasTitle = title && (!row.title || title === String(row.title || '').trim());
    const hasSku = hasTemuUploadDraftDetailSkuContent(detail);
    const hasImage = hasTemuUploadDraftDetailImageContent(detail, uploadedImageUrls);
    if (hasTitle && hasSku && hasImage) return { success: true, detail, raw };
    const missing = [];
    if (!hasTitle) missing.push('标题');
    if (!hasSku) missing.push('SKU');
    if (!hasImage) missing.push('轮播图/SKU图');
    return {
      success: false,
      raw,
      error: `TEMU 草稿已创建 ${productDraftId}，但保存后读取不到完整${missing.join('、')}，未按成功处理；请删除该空草稿后重试。`
    };
  } catch (error) {
    return {
      success: false,
      error: `TEMU 草稿已创建 ${productDraftId}，但保存后读取详情失败：${error?.message || String(error)}；未按成功处理。`
    };
  }
}

async function createTemuUploadProductDraft(payload = {}, auth = {}) {
  let productDraftId = '';
  let step = 'prepare';
  try {
    const detail = payload.sourceProductDetail || payload.productDetail || payload.templateDetail || null;
    const row = payload.row || {};
    const images = Array.isArray(payload.images) ? payload.images : [];
    if (!detail || typeof detail !== 'object') return { success: false, error: '模板缺少 TEMU 官方商品详情，不能上传' };
    if (!images.length) return { success: false, error: '缺少待上传图片' };

    step = 'category/template';
    const categoryTemplate = await retryTemuTransientOperation(
      () => fetchTemuUploadOfficialCategoryTemplate(detail, auth),
      { retries: 2 }
    );
    const mainParentSpecIds = getTemuUploadOfficialMainParentSpecIds(detail, categoryTemplate);

    step = 'draft/add';
    const addBody = buildTemuUploadOfficialDraftAddBody(detail);
    const addData = await retryTemuTransientOperation(
      () => temuSellerPost(
        'https://agentseller.temu.com/visage-agent-seller/product/draft/add',
        addBody,
        auth,
        30000
      ),
      { retries: 1 }
    );
    if (!isTemuApiSuccess(addData)) {
      return { success: false, error: getTemuApiMessage(addData, 'TEMU 创建草稿失败'), step: 'draft/add', response: addData };
    }
    const addResult = getTemuUploadOfficialResult(addData);
    productDraftId = String(addResult.productDraftId || addResult.draftId || addResult.id || '');
    if (!productDraftId) {
      return { success: false, error: 'TEMU 创建草稿成功但未返回 productDraftId', step: 'draft/add', response: addData };
    }

    step = 'image/upload';
    const uploadedImageUrls = [];
    for (let i = 0; i < images.length; i++) {
      const image = images[i] || {};
      const imageUrl = await retryTemuTransientOperation(
        () => uploadProductImageToTemuAndGetUrl(image.imageData, image.filename || `image-${i + 1}.jpg`, auth),
        { retries: 2 }
      );
      if (!imageUrl) {
        return { success: false, error: `第 ${i + 1} 张图片上传 TEMU 失败`, step: 'image/upload', productDraftId };
      }
      uploadedImageUrls.push(imageUrl);
    }

    step = 'draft/save';
    const saveBody = buildTemuUploadOfficialSaveBody({
      detail,
      row,
      uploadedImageUrls,
      skuImagePlan: payload.skuImagePlan || [],
      productDraftId,
      categoryTemplate,
      mainParentSpecIds
    });
    const saveData = await retryTemuTransientOperation(
      () => temuSellerPost(
        'https://agentseller.temu.com/visage-agent-seller/product/draft/save',
        saveBody,
        auth,
        60000
      ),
      { retries: 2 }
    );
    if (!isTemuApiSuccess(saveData)) {
      return {
        success: false,
        error: getTemuApiMessage(saveData, 'TEMU 保存草稿失败'),
        step: 'draft/save',
        productDraftId,
        response: saveData
      };
    }

    step = 'draft/verify';
    const verifyResult = await verifyTemuUploadSavedDraft(productDraftId, row, uploadedImageUrls, auth);
    if (!verifyResult.success) {
      return {
        success: false,
        error: verifyResult.error || 'TEMU 草稿保存后校验失败',
        step,
        productDraftId,
        response: verifyResult.raw || null
      };
    }

    return {
      success: true,
      productDraftId,
      editUrl: `https://agentseller.temu.com/goods/edit?productDraftId=${encodeURIComponent(productDraftId)}&from=productDraftList`,
      uploadedImageUrls,
      data: getTemuUploadOfficialResult(saveData)
    };
  } catch (error) {
    return {
      success: false,
      error: formatTemuUploadOfficialStepError(step, error?.message || String(error)),
      productDraftId,
      step
    };
  }
}

function normalizeTemuDraftPublishIds(ids = []) {
  return Array.from(new Set(
    (Array.isArray(ids) ? ids : [ids])
      .flat()
      .map(id => String(id || '').trim())
      .filter(id => /^\d{6,}$/.test(id))
  ));
}

function looksLikeTemuDraftDetailPayload(value = {}) {
  if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
  if (Array.isArray(value.productSkcReqs) && value.productSkcReqs.length) return true;
  if (Array.isArray(value.productSkcList) && value.productSkcList.length) return true;
  if (value.productName && (value.cat1Id || value.catId || value.categoryId || value.leafCatId || value.categories || value.categoryList)) return true;
  return false;
}

function unwrapTemuDraftDetailPayload(value, depth = 0) {
  if (!value || typeof value !== 'object' || depth > 4) return null;
  if (looksLikeTemuDraftDetailPayload(value)) return value;
  const candidates = [
    value.res,
    value.result,
    value.data,
    value.detail,
    value.productDraft,
    value.productDraftInfo,
    value.draftInfo,
    value.productInfo,
    value.sourceProductInfo,
    value.product,
    value.formData,
    value.value
  ].filter(item => item && typeof item === 'object');
  for (const candidate of candidates) {
    const unwrapped = unwrapTemuDraftDetailPayload(candidate, depth + 1);
    if (unwrapped) return unwrapped;
  }
  return null;
}

async function fetchTemuProductDraftDetail(productDraftId, auth = {}) {
  const id = normalizeTemuUploadOfficialNumber(productDraftId);
  if (!id) throw new Error('缺少 TEMU 草稿 ID');
  const data = await temuSellerPost(TEMU_PRODUCT_DRAFT_QUERY_URL, { productDraftId: id }, auth, 30000);
  if (!isTemuApiSuccess(data)) {
    throw new Error(getTemuApiMessage(data, 'TEMU 草稿详情读取失败'));
  }
  const detail = unwrapTemuDraftDetailPayload(getTemuUploadOfficialPayload(data)) || unwrapTemuDraftDetailPayload(data);
  if (!detail) throw new Error('TEMU 未返回可发布的草稿详情');
  return { detail, raw: data };
}

function hasTemuDraftPublishRequestSkcReqs(detail = {}) {
  return Array.isArray(detail.productSkcReqs)
    && detail.productSkcReqs.some(skc => Array.isArray(skc?.productSkuReqs) && skc.productSkuReqs.length);
}

function buildTemuDraftPublishCategoryIds(detail = {}) {
  const direct = {};
  for (let i = 1; i <= 10; i++) {
    const key = `cat${i}Id`;
    if (Object.prototype.hasOwnProperty.call(detail, key)) {
      const value = normalizeTemuUploadOfficialNumber(detail[key]);
      if (value !== undefined) direct[key] = value;
    }
  }
  if (Object.values(direct).some(value => value)) return direct;
  return buildTemuUploadOfficialCategoryIds(detail);
}

function pickTemuDraftPublishOfficialFields(detail = {}) {
  return pickTemuUploadOfficialFields(detail, [
    'materialMultiLanguages',
    'productName',
    'productI18nReqs',
    'goodsI18nReqs',
    'productPropertyReqs',
    'productSkcReqs',
    'productSpecPropertyReqs',
    'carouselImageUrls',
    'carouselImageI18nReqs',
    'materialImgUrl',
    'goodsLayerDecorationReqs',
    'goodsLayerDecorationCustomizeI18nReqs',
    'sizeTemplateIds',
    'showSizeTemplateIds',
    'goodsModelReqs',
    'productWhExtAttrReq',
    'productCarouseVideoReqList',
    'goodsAdvantageLabelTypes',
    'productDetailVideoReqList',
    'productOuterPackageReq',
    'sensitiveTransNormalFileReqs',
    'personalizationSwitch',
    'productSaleExtAttrReq',
    'productNonAuditExtAttrReq',
    'productShipmentReq',
    'productWarehouseRouteReq',
    'productSemiManagedReq',
    'productComplianceStatementReq',
    'productOriginCertFileReqs',
    'productAssembleReq',
    'vehicleLibraryRelationDTOList',
    'productGuideFileI18nReqs',
    'productGuideFileNewReqList',
    'productGuideFilePageImages',
    'productImageProcessExtReqs',
    'productImageProcessExtReqList'
  ]);
}

function getTemuDraftPublishImageUrlFromValue(value) {
  if (!value) return '';
  if (typeof value === 'string') return value.trim();
  if (typeof value !== 'object') return '';
  return String(
    value.url ||
    value.imageUrl ||
    value.imgUrl ||
    value.thumbUrl ||
    value.previewUrl ||
    value.signedImageUrl ||
    value.skcImgUrl ||
    ''
  ).trim();
}

function getTemuDraftPublishImageUrlsFromList(list) {
  if (!Array.isArray(list)) return [];
  return Array.from(new Set(list.map(getTemuDraftPublishImageUrlFromValue).filter(Boolean)));
}

function getTemuDraftPublishSkcPreviewUrls(sourceSkc = {}) {
  const urls = [
    ...getTemuDraftPublishImageUrlsFromList(sourceSkc.previewImgUrls),
    ...getTemuDraftPublishImageUrlsFromList(sourceSkc.carouselImageUrls),
    ...getTemuDraftPublishImageUrlsFromList(sourceSkc.productSkcImageExtList),
    ...getTemuDraftPublishImageUrlsFromList(sourceSkc.productSkcImageProcessExtVOList),
    getTemuDraftPublishImageUrlFromValue(sourceSkc.colorImageUrl),
    getTemuDraftPublishImageUrlFromValue(sourceSkc.colorImage),
    getTemuDraftPublishImageUrlFromValue(sourceSkc.thumbUrl)
  ].filter(Boolean);
  return Array.from(new Set(urls));
}

function getTemuDraftPublishSkuThumbUrl(sourceSku = {}, fallbackUrl = '') {
  return getTemuDraftPublishImageUrlFromValue(sourceSku.thumbUrl)
    || getTemuDraftPublishImageUrlFromValue(sourceSku.productSkuThumbUrl)
    || getTemuDraftPublishImageUrlFromValue(sourceSku.productSkuImageUrl)
    || getTemuDraftPublishImageUrlFromValue(sourceSku.productSkuImage)
    || getTemuDraftPublishImageUrlFromValue(sourceSku.skuImage)
    || fallbackUrl
    || '';
}

function buildTemuDraftPublishSkuReq(sourceSku = {}, options = {}) {
  const skuIndex = Number(options.skuIndex || 0);
  const fallbackUrl = String(options.fallbackUrl || '').trim();
  const thumbUrl = getTemuDraftPublishSkuThumbUrl(sourceSku, fallbackUrl);
  const productSkuSpecReqs = buildTemuUploadOfficialSkuSpecReqs(sourceSku, options);
  if (!productSkuSpecReqs.length) throw new Error(`第 ${skuIndex + 1} 个 SKU 缺少 TEMU 官方规格，无法发布草稿`);
  if (!thumbUrl) throw new Error(`第 ${skuIndex + 1} 个 SKU 缺少 TEMU SKU 图片，无法发布草稿`);
  const siteSupplierPrices = Array.isArray(sourceSku.siteSupplierPrices)
    ? buildTemuUploadOfficialSiteSupplierPrices(sourceSku.siteSupplierPrices, getTemuUploadOfficialSkuPrice(sourceSku))
    : undefined;
  return cleanTemuUploadOfficialObject({
    thumbUrl,
    productSkuThumbUrlI18nReqs: cloneTemuUploadOfficialValue(sourceSku.productSkuThumbUrlI18nReqs || sourceSku.productSkuThumbUrlI18nList) || [],
    extCode: String(sourceSku.extCode || sourceSku.skuCode || '').trim(),
    supplierPrice: getTemuUploadOfficialSkuPrice(sourceSku),
    siteSupplierPrices,
    currencyType: sourceSku.currencyType || options.currencyType || undefined,
    productSkuSpecReqs,
    productSkuId: normalizeTemuUploadOfficialNumber(sourceSku.productSkuId) || 0,
    productSkuSuggestedPriceReq: cloneTemuUploadOfficialValue(sourceSku.productSkuSuggestedPriceReq || sourceSku.productSkuSuggestedPrice),
    productSkuUsSuggestedPriceReq: cloneTemuUploadOfficialValue(sourceSku.productSkuUsSuggestedPriceReq || sourceSku.productSkuUsSuggestedPrice),
    productSkuWhExtAttrReq: buildTemuUploadOfficialSkuWhExtAttrReq(sourceSku),
    productSkuMultiPackReq: cloneTemuUploadOfficialValue(sourceSku.productSkuMultiPackReq || sourceSku.productSkuMultiPack),
    productSkuStockQuantityReq: cloneTemuUploadOfficialValue(sourceSku.productSkuStockQuantityReq || sourceSku.productSkuQuantity),
    productSkuAccessoriesReq: cloneTemuUploadOfficialValue(sourceSku.productSkuAccessoriesReq || sourceSku.productSkuAccessories),
    productSkuNonAuditExtAttrReq: cloneTemuUploadOfficialValue(sourceSku.productSkuNonAuditExtAttrReq || sourceSku.productSkuNonAuditExtAttr)
  });
}

function buildTemuDraftPublishSkcReqs(detail = {}, options = {}) {
  const sourceSkcs = Array.isArray(detail.productSkcList) ? detail.productSkcList : [];
  if (!sourceSkcs.length) throw new Error('草稿详情缺少 TEMU 官方 SKC/SKU 信息，无法发布');
  let skuIndex = 0;
  return sourceSkcs.map((sourceSkc, skcIndex) => {
    const previewImgUrls = getTemuDraftPublishSkcPreviewUrls(sourceSkc);
    const fallbackUrl = previewImgUrls[0] || '';
    const sourceSkus = Array.isArray(sourceSkc.productSkuList) ? sourceSkc.productSkuList : [];
    if (!sourceSkus.length) throw new Error(`第 ${skcIndex + 1} 个 SKC 缺少 SKU，无法发布草稿`);
    const productSkuReqs = sourceSkus.map(sourceSku => buildTemuDraftPublishSkuReq(sourceSku, {
      ...options,
      skuIndex: skuIndex++,
      fallbackUrl
    }));
    return cleanTemuUploadOfficialObject({
      previewImgUrls,
      productSkcCarouselImageI18nReqs: cloneTemuUploadOfficialValue(sourceSkc.productSkcCarouselImageI18nReqs || sourceSkc.productSkcCarouselImageI18nList) || [],
      extCode: String(sourceSkc.extCode || sourceSkc.skcCode || '').trim(),
      mainProductSkuSpecReqs: buildTemuUploadOfficialSkcMainSpecReqs(sourceSkc, options),
      productSkuReqs,
      productSkcId: normalizeTemuUploadOfficialNumber(sourceSkc.productSkcId) || 0,
      colorImageUrl: getTemuDraftPublishImageUrlFromValue(sourceSkc.colorImageUrl)
        || getTemuDraftPublishImageUrlFromValue(sourceSkc.colorImage)
        || fallbackUrl,
      bomId: sourceSkc.bomId,
      isBasePlate: sourceSkc.isBasePlate || sourceSkc.productSkcWhExtAttr?.isBasePlate
    });
  });
}

function limitTemuDraftPublishPrimarySpecReqs(productSkcReqs = []) {
  if (!Array.isArray(productSkcReqs)) return productSkcReqs;
  return productSkcReqs.map(sourceSkc => {
    if (!sourceSkc || typeof sourceSkc !== 'object') return sourceSkc;
    const skc = cloneTemuUploadOfficialValue(sourceSkc) || {};
    if (Array.isArray(skc.mainProductSkuSpecReqs) && skc.mainProductSkuSpecReqs.length > 1) {
      skc.mainProductSkuSpecReqs = skc.mainProductSkuSpecReqs.slice(0, 1);
    }
    return skc;
  });
}

function validateTemuDraftPublishBody(body = {}, productDraftId = '') {
  if (!normalizeTemuUploadOfficialNumber(productDraftId || body.productDraftId)) {
    throw new Error('TEMU 草稿 ID 无效，无法发布');
  }
  if (!String(body.productName || '').trim()) {
    throw new Error('草稿缺少商品标题，无法发布');
  }
  if (!Array.isArray(body.productSkcReqs) || !body.productSkcReqs.length) {
    throw new Error('草稿缺少 SKC/SKU 信息，无法发布');
  }
  body.productSkcReqs.forEach((skc, skcIndex) => {
    if (!Array.isArray(skc?.mainProductSkuSpecReqs) || !skc.mainProductSkuSpecReqs.length) {
      throw new Error(`第 ${skcIndex + 1} 个 SKC 缺少主销售规格，无法发布`);
    }
    if (!Array.isArray(skc?.productSkuReqs) || !skc.productSkuReqs.length) {
      throw new Error(`第 ${skcIndex + 1} 个 SKC 缺少 SKU，无法发布`);
    }
    skc.productSkuReqs.forEach((sku, skuIndex) => {
      if (!Array.isArray(sku?.productSkuSpecReqs) || !sku.productSkuSpecReqs.length) {
        throw new Error(`第 ${skcIndex + 1} 个 SKC 的第 ${skuIndex + 1} 个 SKU 缺少销售规格，无法发布`);
      }
      if (!String(sku?.thumbUrl || '').trim()) {
        throw new Error(`第 ${skcIndex + 1} 个 SKC 的第 ${skuIndex + 1} 个 SKU 缺少 SKU 图片，无法发布`);
      }
    });
  });
}

function buildTemuDraftPublishBodyFromDetail(detail = {}, productDraftId, options = {}) {
  const id = normalizeTemuUploadOfficialNumber(productDraftId || detail.productDraftId);
  if (!id) throw new Error('缺少 TEMU 草稿 ID，无法发布');
  const directFields = pickTemuDraftPublishOfficialFields(detail);
  const categoryTemplate = options.categoryTemplate || {};
  const categoryProperties = getTemuUploadOfficialCategoryProperties(categoryTemplate);
  const specBuildOptions = {
    mainParentSpecIds: Array.isArray(options.mainParentSpecIds) ? options.mainParentSpecIds : [],
    productSpecPropertyVOS: Array.isArray(detail.productSpecPropertyVOS) ? detail.productSpecPropertyVOS : [],
    categoryProperties
  };
  const productSaleExtAttrReq = directFields.productSaleExtAttrReq
    || buildTemuUploadOfficialProductSaleExtAttrReq(detail);
  const productNonAuditExtAttrReq = directFields.productNonAuditExtAttrReq || detail.productNonAuditExtAttrReq || {};
  const productNonAuditExtAttr = detail.productNonAuditExtAttr || {};
  const body = cleanTemuUploadOfficialObject({
    ...buildTemuDraftPublishCategoryIds(detail),
    ...directFields,
    materialMultiLanguages: directFields.materialMultiLanguages
      || (Array.isArray(detail.imageLanguageList) ? cloneTemuUploadOfficialValue(detail.imageLanguageList) : undefined),
    productName: String(directFields.productName || detail.productName || '').trim(),
    productI18nReqs: directFields.productI18nReqs || buildTemuUploadOfficialProductI18nReqs(detail),
    goodsI18nReqs: directFields.goodsI18nReqs || cloneTemuUploadOfficialValue(detail.goodsI18nList),
    productPropertyReqs: directFields.productPropertyReqs || buildTemuUploadOfficialPropertyReqs(detail),
    productSkcReqs: hasTemuDraftPublishRequestSkcReqs(detail)
      ? cloneTemuUploadOfficialValue(detail.productSkcReqs)
      : buildTemuDraftPublishSkcReqs(detail, {
        currencyType: detail.supplierCurrencyInfo?.currencyType || '',
        ...specBuildOptions
      }),
    productSpecPropertyReqs: directFields.productSpecPropertyReqs
      || buildTemuUploadOfficialSpecPropertyReqs(detail, categoryTemplate, specBuildOptions),
    carouselImageUrls: directFields.carouselImageUrls || cloneTemuUploadOfficialValue(detail.carouselImageUrls),
    carouselImageI18nReqs: directFields.carouselImageI18nReqs || cloneTemuUploadOfficialValue(detail.carouselImageI18nList),
    materialImgUrl: directFields.materialImgUrl || getTemuDraftPublishImageUrlFromValue(detail.materialImgUrl),
    goodsModelReqs: directFields.goodsModelReqs || cloneTemuUploadOfficialValue(detail.goodsModelList),
    productWhExtAttrReq: directFields.productWhExtAttrReq || buildTemuUploadOfficialWhExtAttrReq(detail),
    goodsAdvantageLabelTypes: directFields.goodsAdvantageLabelTypes
      || (Array.isArray(detail.goodsAdvantageLabelVOList)
        ? detail.goodsAdvantageLabelVOList.map(item => item?.type || item?.labelType).filter(Boolean)
        : undefined),
    productOuterPackageImageReqs: undefined,
    productOuterPackageReq: directFields.productOuterPackageReq || buildTemuUploadOfficialOuterPackageReq(detail),
    personalizationSwitch: directFields.personalizationSwitch ?? getTemuUploadOfficialPersonalizationSwitch(detail),
    productSaleExtAttrReq,
    productNonAuditExtAttrReq: cleanTemuUploadOfficialObject({
      ...cloneTemuUploadOfficialValue(productNonAuditExtAttrReq),
      cosmeticInfoReq: cloneTemuUploadOfficialValue(productNonAuditExtAttr.cosmeticInfoReq || productNonAuditExtAttr.cosmeticInfoVO)
    }),
    productShipmentReq: directFields.productShipmentReq || cloneTemuUploadOfficialValue(detail.productShipment),
    productWarehouseRouteReq: directFields.productWarehouseRouteReq || cloneTemuUploadOfficialValue(detail.productWarehouseRoute),
    productSemiManagedReq: directFields.productSemiManagedReq || cloneTemuUploadOfficialValue(detail.productSemiManaged),
    productDraftId: id
  });
  validateTemuDraftPublishBody(body, id);
  return body;
}

async function publishTemuProductDraft(productDraftId, auth = {}) {
  const id = normalizeTemuUploadOfficialNumber(productDraftId);
  if (!id) return { success: false, productDraftId, error: '草稿 ID 无效' };
  let step = 'draft/query';
  try {
    const { detail } = await retryTemuTransientOperation(
      () => fetchTemuProductDraftDetail(id, auth),
      { retries: 2 }
    );
    let categoryTemplate = null;
    let mainParentSpecIds = [];
    if (!hasTemuDraftPublishRequestSkcReqs(detail)) {
      step = 'category/template';
      categoryTemplate = await retryTemuTransientOperation(
        () => fetchTemuUploadOfficialCategoryTemplate(detail, auth),
        { retries: 2 }
      );
      mainParentSpecIds = getTemuUploadOfficialMainParentSpecIds(detail, categoryTemplate);
    }
    step = 'product/add';
    const body = buildTemuDraftPublishBodyFromDetail(detail, id, {
      categoryTemplate,
      mainParentSpecIds
    });
    const data = await retryTemuTransientOperation(
      () => temuSellerPost(TEMU_PRODUCT_ADD_URL, body, auth, 90000),
      { retries: 2 }
    );
    if (!isTemuApiSuccess(data)) {
      return {
        success: false,
        productDraftId: String(id),
        step,
        error: getTemuApiMessage(data, 'TEMU 发布草稿失败'),
        response: data
      };
    }
    const result = getTemuUploadOfficialPayload(data);
    return {
      success: true,
      productDraftId: String(id),
      productId: String(result.productId || result.goodsId || ''),
      step,
      response: result
    };
  } catch (error) {
    return {
      success: false,
      productDraftId: String(id),
      step,
      error: formatTemuUploadOfficialStepError(step, error?.message || String(error))
    };
  }
}

async function batchPublishTemuDrafts(params = {}, auth = {}) {
  const progressTaskId = String(params.progressTaskId || '').trim();
  const productDraftIds = normalizeTemuDraftPublishIds(params.productDraftIds || params.ids || []);
  if (!auth?.mallId) {
    return { success: false, error: '请先连接/登录 TEMU 店铺后再发布草稿' };
  }
  if (!productDraftIds.length) {
    return { success: false, error: '请先勾选要发布的草稿' };
  }
  updateCustomizedBatchActionProgress(progressTaskId, {
    action: 'publishDraft',
    status: 'running',
    total: productDraftIds.length,
    completed: 0,
    successCount: 0,
    failCount: 0,
    results: [],
    message: `准备发布 ${productDraftIds.length} 条草稿`
  });

  const results = [];
  for (const productDraftId of productDraftIds) {
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: 'publishDraft',
      status: 'running',
      total: productDraftIds.length,
      completed: results.length,
      successCount: results.filter(item => item.success).length,
      failCount: results.filter(item => !item.success).length,
      currentDraftId: productDraftId,
      message: `正在发布草稿 ${productDraftId}`
    });
    await sleep(600);
    const result = await publishTemuProductDraft(productDraftId, auth);
    results.push(result);
    updateCustomizedBatchActionProgress(progressTaskId, {
      action: 'publishDraft',
      status: 'running',
      total: productDraftIds.length,
      completed: results.length,
      successCount: results.filter(item => item.success).length,
      failCount: results.filter(item => !item.success).length,
      results,
      message: `已处理 ${results.length}/${productDraftIds.length}`
    });
  }

  const successCount = results.filter(item => item.success).length;
  const failCount = results.length - successCount;
  const finalStatus = failCount ? (successCount ? 'partial' : 'failed') : 'success';
  const response = {
    success: failCount === 0,
    partialSuccess: successCount > 0 && failCount > 0,
    total: productDraftIds.length,
    successCount,
    failCount,
    results,
    error: failCount ? results.filter(item => !item.success).map(item => `${item.productDraftId}：${item.error || '发布失败'}`).join('；') : ''
  };
  updateCustomizedBatchActionProgress(progressTaskId, {
    action: 'publishDraft',
    status: finalStatus,
    total: productDraftIds.length,
    completed: results.length,
    successCount,
    failCount,
    results,
    error: response.error,
    message: failCount ? `发布完成，成功 ${successCount} 条，失败 ${failCount} 条` : `发布完成，成功 ${successCount} 条`
  });
  return response;
}

/**
 * 创建草稿（采集上架第4步）
 */
async function createProductDraft(draftData, mallId, antiContent) {
  const url = 'https://seller.kuajingmaihuo.com/visage-agent-seller/product/draft/add';
  return temuApiRequest(url, {
    method: 'POST',
    body: JSON.stringify(draftData)
  }, mallId, antiContent);
}

/**
 * 提交商品（采集上架第5步）
 */
async function submitProduct(productData, mallId, antiContent) {
  const url = 'https://seller.kuajingmaihuo.com/visage-agent-seller/product/add';
  return temuApiRequest(url, {
    method: 'POST',
    body: JSON.stringify(productData)
  }, mallId, antiContent);
}

/**
 * 智能推荐类目（根据图片）
 */
async function getRecommendedCategory(imageUrl, mallId, antiContent) {
  const url = 'https://seller.kuajingmaihuo.com/professional/temu/api/goods/photorecommendationcategory/get';
  return temuApiRequest(url, {
    method: 'POST',
    body: JSON.stringify({ imageUrl })
  }, mallId, antiContent);
}

// ========== 财务数据 API ==========
const FINANCE_API_ENDPOINTS = {
  balance: [
    'https://agentseller.temu.com/visage-agent-seller/finance/account/balance',
    'https://seller.kuajingmaihuo.com/visage-agent-seller/finance/account/balance'
  ],
  detail: [
    'https://agentseller.temu.com/visage-agent-seller/finance/account/detail',
    'https://seller.kuajingmaihuo.com/visage-agent-seller/finance/account/detail'
  ]
};

function isFinanceApiSuccess(result) {
  return !!result && (
    result.success === true
    || result.code === 0
    || result.errorCode === 1000000
    || result.error_code === 1000000
  );
}

function getFinanceApiErrorMessage(result, fallback = 'TEMU 接口请求失败') {
  if (!result || typeof result !== 'object') return fallback;
  const message = result.errorMsg
    || result.error_msg
    || result.message
    || result.msg
    || result.error
    || fallback;
  const code = result.errorCode ?? result.error_code ?? result.code;
  if (code === undefined || code === null || code === 0 || code === 1000000) return message;
  return `${message}（${code}）`;
}

function pickFinanceNumber(source = {}, keys = []) {
  for (const key of keys) {
    const value = source?.[key];
    if (value === undefined || value === null || value === '') continue;
    const parsed = Number(value);
    if (Number.isFinite(parsed)) return parsed;
  }
  return 0;
}

async function requestFinanceApiWithFallback(urls, body, mallId, antiContent, fallbackError) {
  const errors = [];
  for (const url of urls) {
    try {
      const result = await temuApiRequest(url, {
        method: 'POST',
        body: JSON.stringify(body || {})
      }, mallId, antiContent);
      if (isFinanceApiSuccess(result)) {
        return { success: true, result, sourceUrl: url, errors };
      }
      errors.push(`${url}: ${getFinanceApiErrorMessage(result, fallbackError)}`);
    } catch (error) {
      errors.push(`${url}: ${error?.message || String(error)}`);
    }
  }
  return {
    success: false,
    error: errors.length ? errors.join('；') : fallbackError,
    errors
  };
}

/**
 * 获取账户资金信息
 */
async function getFinanceData(mallId, antiContent) {
  try {
    const financeResult = await requestFinanceApiWithFallback(
      FINANCE_API_ENDPOINTS.balance,
      {},
      mallId,
      antiContent,
      '获取财务数据失败'
    );

    if (financeResult.success) {
      const result = financeResult.result || {};
      const data = result.result || result.data || {};
      return {
        success: true,
        data: {
          available: pickFinanceNumber(data, ['availableBalance', 'availableAmount', 'availableAmt', 'available', 'balance']),
          frozen: pickFinanceNumber(data, ['frozenBalance', 'frozenAmount', 'frozenAmt', 'frozen']),
          pending: pickFinanceNumber(data, ['pendingSettlement', 'pendingAmount', 'pendingAmt', 'pending']),
          source: financeResult.sourceUrl?.includes('agentseller.temu.com') ? 'TEMU 财务接口（agentseller）' : 'TEMU 财务接口（legacy）',
          partialErrors: financeResult.errors || [],
          history: []
        }
      };
    }
    return { success: false, error: financeResult.error || '获取财务数据失败' };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

/**
 * 获取资金流水
 */
async function getFinanceHistory(mallId, antiContent, startDate, endDate, page = 1, pageSize = 50) {
  try {
    const financeResult = await requestFinanceApiWithFallback(
      FINANCE_API_ENDPOINTS.detail,
      {
        startDate,
        endDate,
        page,
        pageSize
      },
      mallId,
      antiContent,
      '获取流水失败'
    );

    if (financeResult.success) {
      const result = financeResult.result || {};
      const payload = result.result || result.data || {};
      const rawItems = payload.list || payload.records || payload.items || payload.detailList || [];
      const items = (Array.isArray(rawItems) ? rawItems : []).map(item => ({
        date: item.createTime || item.createdAt || item.date || item.time || '',
        type: item.typeName || item.bizTypeName || item.type || item.bizType || '',
        description: item.remark || item.description || item.title || item.bizDesc || '',
        amount: pickFinanceNumber(item, ['amount', 'changeAmount', 'transactionAmount', 'incomeAmount', 'expenseAmount']),
        balance: pickFinanceNumber(item, ['balance', 'afterBalance', 'availableBalance', 'accountBalance'])
      }));
      return { success: true, data: items };
    }
    return { success: false, error: financeResult.error || '获取流水失败' };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

// ========== 通用 TEMU API 请求封装 ==========
async function temuApiRequest(url, options = {}, mallId, antiContent) {
  const resolvedMallId = mallId || state.mallId || '';
  const resolvedAntiContent = antiContent || state.antiContent || '';
  const headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'anti-content': resolvedAntiContent,
  };
  if (resolvedMallId) {
    headers.mallid = resolvedMallId;
    headers['Mall-Id'] = resolvedMallId;
  }

  const response = await fetch(url, {
    credentials: 'include',
    ...options,
    headers: { ...headers, ...(options.headers || {}) }
  });

  const text = await response.text();
  let data = {};
  try {
    data = text ? JSON.parse(text) : {};
  } catch (error) {
    data = { success: false, error: `接口返回非 JSON：${text.slice(0, 200)}` };
  }

  if (!response.ok && !isTemuApiSuccess(data)) {
    return {
      ...data,
      success: false,
      httpStatus: response.status,
      error: getFinanceApiErrorMessage(data, `HTTP ${response.status}`)
    };
  }

  return data;
}

