(() => {
  const GUARD = "__MMW_ORIGINAL_ECOMMERCE_SYNC_OUTBOX__";
  if (globalThis[GUARD]) return;
  globalThis[GUARD] = true;

  const STORAGE_KEY = "mmwOriginalEcommerceSyncOutboxV1";
  const ALARM_NAME = "mmw-original-ecommerce-sync-outbox";
  const RETRY_MESSAGE = "MMW_ORIGINAL_SYNC_RETRY";
  const STATUS_MESSAGE = "MMW_ORIGINAL_SYNC_STATUS";
  const MAX_ITEMS = 120;
  const MAX_ENTRY_BYTES = 2.5 * 1024 * 1024;
  const BASE_RETRY_MS = 60 * 1000;
  const MAX_RETRY_MS = 30 * 60 * 1000;
  const BLOCKED_KEYS = new Set([
    "authorization", "cookie", "cookies", "headers", "token", "user_token",
    "access_token", "refresh_token", "password", "secret", "app_secret"
  ]);

  let flushing = null;

  function cleanText(value, limit = 240) {
    return String(value || "")
      .replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [hidden]")
      .replace(/[\r\n\t]+/g, " ")
      .trim()
      .slice(0, limit);
  }

  function safeValue(value, depth = 0, seen = new WeakSet()) {
    if (value === null || value === undefined) return value;
    if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
    if (depth > 14) return undefined;
    if (Array.isArray(value)) {
      return value.map((item) => safeValue(item, depth + 1, seen)).filter((item) => item !== undefined);
    }
    if (typeof value !== "object" || seen.has(value)) return undefined;
    seen.add(value);
    const result = {};
    for (const [key, item] of Object.entries(value)) {
      if (BLOCKED_KEYS.has(String(key).toLowerCase())) continue;
      const clean = safeValue(item, depth + 1, seen);
      if (clean !== undefined) result[key] = clean;
    }
    return result;
  }

  function byteLength(value) {
    const text = JSON.stringify(value ?? {});
    if (typeof TextEncoder === "function") return new TextEncoder().encode(text).byteLength;
    return unescape(encodeURIComponent(text)).length;
  }

  function normalizeEntry(input = {}) {
    const operation = cleanText(input.operation, 80);
    const idempotencyKey = cleanText(input.idempotencyKey, 320);
    const path = cleanText(input.path, 240);
    const method = String(input.method || "POST").toUpperCase() === "GET" ? "GET" : "POST";
    if (!operation || !idempotencyKey) throw new Error("云端同步任务缺少操作类型或幂等键");
    const payload = safeValue(input.payload || {});
    const entry = {
      id: cleanText(input.id, 120) || `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
      operation,
      idempotencyKey,
      path,
      method,
      payload,
      attempts: Math.max(0, Number(input.attempts || 0)),
      nextRetryAt: Math.max(Date.now() + BASE_RETRY_MS, Number(input.nextRetryAt || 0)),
      lastError: cleanText(input.lastError || "云端同步暂未完成", 300),
      createdAt: Number(input.createdAt || Date.now()),
      updatedAt: Date.now()
    };
    if (byteLength(entry) > MAX_ENTRY_BYTES) throw new Error("商品数据超过云端缓存队列容量，请保留本地采集结果");
    return entry;
  }

  async function readQueue() {
    const stored = await chrome.storage.local.get([STORAGE_KEY]);
    return Array.isArray(stored?.[STORAGE_KEY]) ? stored[STORAGE_KEY] : [];
  }

  async function writeQueue(queue) {
    const clean = Array.isArray(queue) ? queue.slice(-MAX_ITEMS) : [];
    await chrome.storage.local.set({ [STORAGE_KEY]: clean });
    return clean;
  }

  async function schedule(queueInput) {
    if (!chrome.alarms?.create) return;
    const queue = Array.isArray(queueInput) ? queueInput : await readQueue();
    if (!queue.length) {
      await chrome.alarms.clear?.(ALARM_NAME);
      return;
    }
    const earliest = Math.min(...queue.map((item) => Number(item.nextRetryAt || Date.now() + BASE_RETRY_MS)));
    await chrome.alarms.create(ALARM_NAME, { when: Math.max(Date.now() + 30_000, earliest) });
  }

  async function enqueue(input = {}) {
    const entry = normalizeEntry(input);
    const queue = await readQueue();
    const index = queue.findIndex((item) => item?.idempotencyKey === entry.idempotencyKey);
    if (index >= 0) {
      entry.id = queue[index].id || entry.id;
      entry.createdAt = Number(queue[index].createdAt || entry.createdAt);
      queue.splice(index, 1, entry);
    } else {
      queue.push(entry);
    }
    const saved = await writeQueue(queue);
    await schedule(saved);
    return { queued: true, id: entry.id, pending: saved.length, nextRetryAt: entry.nextRetryAt };
  }

  async function cloudRequest(payload) {
    if (typeof requestNativeEcommerceCloud !== "function") {
      throw new Error("MMWGZT电商云服务尚未加载");
    }
    return requestNativeEcommerceCloud(payload);
  }

  async function execute(entry) {
    if (entry.operation === "product-cache-delete-by-source") {
      const cached = await cloudRequest({
        path: "/api/ecommerce/product-cache",
        method: "GET",
        query: entry.payload
      });
      const id = Number(cached?.id || cached?.record?.id || 0);
      if (!id) return { deleted: false, missing: true };
      return cloudRequest({ path: "/api/ecommerce/product-cache/delete", method: "POST", body: { id } });
    }
    if (!entry.path) throw new Error("云端同步任务缺少接口地址");
    return cloudRequest({
      path: entry.path,
      method: entry.method,
      ...(entry.method === "GET" ? { query: entry.payload } : { body: entry.payload })
    });
  }

  function retryDelay(attempts) {
    return Math.min(MAX_RETRY_MS, BASE_RETRY_MS * (2 ** Math.min(5, Math.max(0, attempts - 1))));
  }

  async function broadcast(detail) {
    if (!chrome.tabs?.query || !chrome.tabs?.sendMessage) return;
    let tabs = [];
    try {
      tabs = await chrome.tabs.query({});
    } catch (_) {
      return;
    }
    await Promise.allSettled(tabs
      .filter((tab) => Number.isInteger(tab?.id))
      .map((tab) => chrome.tabs.sendMessage(tab.id, { type: STATUS_MESSAGE, ...detail })));
  }

  async function flush(options = {}) {
    if (flushing) return flushing;
    flushing = (async () => {
      const force = options.force === true;
      const onlyKey = cleanText(options.idempotencyKey, 320);
      const now = Date.now();
      const queue = await readQueue();
      const next = [];
      let synced = 0;
      let failed = 0;
      let lastError = "";

      for (const raw of queue) {
        const entry = { ...raw };
        const selected = (!onlyKey || entry.idempotencyKey === onlyKey)
          && (force || Number(entry.nextRetryAt || 0) <= now);
        if (!selected) {
          next.push(entry);
          continue;
        }
        try {
          await execute(entry);
          synced += 1;
        } catch (error) {
          failed += 1;
          entry.attempts = Math.max(0, Number(entry.attempts || 0)) + 1;
          entry.lastError = cleanText(error?.message || error || "云端同步失败", 300);
          entry.nextRetryAt = Date.now() + retryDelay(entry.attempts);
          entry.updatedAt = Date.now();
          lastError = entry.lastError;
          next.push(entry);
        }
      }

      const saved = await writeQueue(next);
      await schedule(saved);
      const result = { synced, failed, pending: saved.length, lastError };
      if (options.notify === true || synced > 0) {
        await broadcast({
          status: failed ? "warning" : "success",
          message: failed
            ? `云端缓存仍未同步：${lastError || "请检查账号登录和网络"}`
            : synced
              ? `已补同步 ${synced} 条云端缓存`
              : "当前没有待同步的云端缓存",
          ...result
        });
      }
      return result;
    })().finally(() => {
      flushing = null;
    });
    return flushing;
  }

  async function status() {
    const queue = await readQueue();
    return {
      pending: queue.length,
      lastError: cleanText(queue[0]?.lastError || "", 300),
      nextRetryAt: queue.length ? Math.min(...queue.map((item) => Number(item.nextRetryAt || 0))) : 0
    };
  }

  chrome.alarms?.onAlarm?.addListener((alarm) => {
    if (alarm?.name !== ALARM_NAME) return;
    flush().catch(() => {});
  });

  chrome.runtime?.onMessage?.addListener((message, _sender, sendResponse) => {
    if (message?.type === RETRY_MESSAGE) {
      flush({ force: true, notify: true })
        .then((result) => sendResponse({ ok: true, ...result }))
        .catch((error) => sendResponse({ ok: false, error: cleanText(error?.message || error) }));
      return true;
    }
    if (message?.type === "MMW_ORIGINAL_SYNC_STATUS_REQUEST") {
      status()
        .then((result) => sendResponse({ ok: true, ...result }))
        .catch((error) => sendResponse({ ok: false, error: cleanText(error?.message || error) }));
      return true;
    }
    return false;
  });

  globalThis.MMWOriginalEcommerceSyncOutbox = Object.freeze({ enqueue, flush, status });
  schedule().catch(() => {});
})();
