(() => {
  if (window.MMW_QIANCHUAN_MATERIAL_UPLOADER) return;

  const MAX_BATCH_SIZE = 20;
  const SDK_CHUNK_ID = "3146";
  const SDK_MODULE_ID = 703;
  const SDK_FALLBACK_URL = "https://lf3-ad-platform.byteadverts.com/obj/ad-platform/ad/qc/uni-creation/static/js/async/3146.895bc1b6.js";
  const UPLOAD_HELPER_MODULE_ID = 27482;
  const ACCOUNT_HELPER_MODULE_ID = 61111;
  const MATERIAL_API_MODULE_IDS = [75993, 11781];
  const CREATION_FRAME_ID = "mmw-qianchuan-upload-runtime-frame";
  const CREATION_RUNTIME_CACHE_KEY = "mmw_upload_runtime";
  const CREATION_RUNTIME_TIMEOUT_MS = 45000;
  const UPLOAD_STALL_TIMEOUT_MS = 5 * 60 * 1000;
  const UPLOAD_TOTAL_TIMEOUT_MS = 20 * 60 * 1000;
  const UPLOAD_REQUEST_TIMEOUT_MS = 90 * 1000;
  let runtimePromise = null;
  let runtimeAccountId = "";
  let runtimeWindowPromise = null;
  let runtimeFrameAccountId = "";
  let uploaderLoadError = "";

  function getAccountId(aavid) {
    const explicit = String(aavid || "").trim();
    if (explicit) return explicit;
    try {
      return String(new URL(location.href).searchParams.get("aavid") || "").trim();
    } catch {
      return "";
    }
  }

  function getRuntimeWindow(targetWindow) {
    try {
      return Array.isArray(targetWindow?.webpackChunkuni_creation) ? targetWindow : null;
    } catch {
      return null;
    }
  }

  function isAccountCreationRuntime(targetWindow, accountId) {
    try {
      const url = new URL(targetWindow.location.href);
      return url.pathname === "/uni-creation/product"
        && String(url.searchParams.get("aavid") || "").trim() === accountId;
    } catch {
      return false;
    }
  }

  function removeRuntimeFrame() {
    document.getElementById(CREATION_FRAME_ID)?.remove();
    runtimeFrameAccountId = "";
  }

  function createRuntimeFrame(aavid) {
    removeRuntimeFrame();
    const frame = document.createElement("iframe");
    frame.id = CREATION_FRAME_ID;
    frame.title = "";
    frame.tabIndex = -1;
    frame.setAttribute("aria-hidden", "true");
    frame.referrerPolicy = "strict-origin-when-cross-origin";
    frame.style.cssText = [
      "position:fixed",
      "left:-10000px",
      "top:-10000px",
      "width:1px",
      "height:1px",
      "border:0",
      "opacity:0",
      "pointer-events:none",
      "overflow:hidden"
    ].join(";");
    const url = new URL("/uni-creation/product", location.origin);
    if (aavid) url.searchParams.set("aavid", aavid);
    url.searchParams.set(CREATION_RUNTIME_CACHE_KEY, String(Date.now()));
    frame.src = url.href;
    runtimeFrameAccountId = aavid;
    (document.body || document.documentElement).appendChild(frame);
    return frame;
  }

  function resetRuntimeWindow() {
    runtimeWindowPromise = null;
    removeRuntimeFrame();
  }

  async function ensureRuntimeWindow(aavid, forceFresh = false) {
    const accountId = getAccountId(aavid);
    const current = getRuntimeWindow(window);
    if (!forceFresh && current && isAccountCreationRuntime(window, accountId)) return current;

    if (forceFresh) resetRuntimeWindow();

    if (runtimeWindowPromise && runtimeFrameAccountId === accountId) return runtimeWindowPromise;

    runtimeWindowPromise = new Promise((resolve, reject) => {
      const existing = document.getElementById(CREATION_FRAME_ID);
      const frame = existing && runtimeFrameAccountId === accountId ? existing : createRuntimeFrame(accountId);
      const startedAt = Date.now();
      let timer = 0;
      let settled = false;

      const finish = (error, runtimeWindow) => {
        if (settled) return;
        settled = true;
        clearTimeout(timer);
        if (error) reject(error);
        else resolve(runtimeWindow);
      };

      const probe = () => {
        const runtimeWindow = getRuntimeWindow(frame.contentWindow);
        let readyState = "";
        try {
          readyState = frame.contentDocument?.readyState || "";
        } catch {
          finish(new Error("千川官方上传运行时无法访问"));
          return;
        }
        if (runtimeWindow && readyState === "complete") {
          finish(null, runtimeWindow);
          return;
        }
        if (Date.now() - startedAt >= CREATION_RUNTIME_TIMEOUT_MS) {
          finish(new Error("千川官方上传运行时加载超时，请确认当前账号已登录"));
          return;
        }
        timer = setTimeout(probe, 120);
      };

      frame.addEventListener("error", () => finish(new Error("千川官方上传运行时加载失败")), { once: true });
      probe();
    }).catch((error) => {
      runtimeWindowPromise = null;
      removeRuntimeFrame();
      throw error;
    });
    return runtimeWindowPromise;
  }

  function getWebpackRequire(runtimeWindow) {
    const chunks = runtimeWindow?.webpackChunkuni_creation;
    if (!Array.isArray(chunks)) {
      throw new Error("千川官方上传运行时未就绪");
    }
    let webpackRequire = null;
    chunks.push([[
      `mmw-qianchuan-${Date.now()}-${Math.random().toString(36).slice(2)}`
    ], {}, (require) => {
      webpackRequire = require;
    }]);
    if (typeof webpackRequire !== "function") {
      throw new Error("未能连接千川原生上传组件，请刷新页面后重试");
    }
    return webpackRequire;
  }

  function tryRequireModule(require, moduleId) {
    try {
      return require(moduleId);
    } catch {
      return null;
    }
  }

  function hasFunctionExports(module, exportNames) {
    return Boolean(module) && exportNames.every((name) => typeof module?.[name] === "function");
  }

  function functionSource(value) {
    if (typeof value !== "function") return "";
    try {
      return Function.prototype.toString.call(value);
    } catch {
      return "";
    }
  }

  function findFunctionExport(module, sourceTerms, predicate = null) {
    for (const value of Object.values(module || {})) {
      if (typeof value !== "function") continue;
      const source = functionSource(value);
      if (!sourceTerms.every((term) => source.includes(term))) continue;
      if (!predicate || predicate(value, source)) return value;
    }
    return null;
  }

  function moduleFunctionSource(module) {
    return Object.values(module || {})
      .filter((value) => typeof value === "function")
      .map(functionSource)
      .join("\n");
  }

  function knownModuleIds(knownIds) {
    return Array.isArray(knownIds) ? knownIds : [knownIds];
  }

  function findRuntimeModuleBySource(require, knownIds, sourceTerms) {
    for (const knownId of knownModuleIds(knownIds)) {
      const knownModule = tryRequireModule(require, knownId);
      const knownSource = moduleFunctionSource(knownModule);
      if (sourceTerms.every((term) => knownSource.includes(term))) return knownModule;

      const factorySource = functionSource(require?.m?.[knownId]);
      if (!sourceTerms.every((term) => factorySource.includes(term))) continue;
      if (knownModule) return knownModule;
    }

    for (const [moduleId, factory] of Object.entries(require?.m || {})) {
      const source = functionSource(factory);
      if (!sourceTerms.every((term) => source.includes(term))) continue;
      const candidate = tryRequireModule(require, moduleId);
      if (candidate) return candidate;
    }
    return null;
  }

  function findRuntimeModule(require, knownIds, exportNames) {
    for (const knownId of knownModuleIds(knownIds)) {
      const knownModule = tryRequireModule(require, knownId);
      if (hasFunctionExports(knownModule, exportNames)) return knownModule;
    }

    const factories = require?.m || {};
    for (const [moduleId, factory] of Object.entries(factories)) {
      let source = "";
      try {
        source = Function.prototype.toString.call(factory);
      } catch {
        continue;
      }
      if (!exportNames.every((name) => source.includes(`${name}:`))) continue;
      const candidate = tryRequireModule(require, moduleId);
      if (hasFunctionExports(candidate, exportNames)) return candidate;
    }
    return null;
  }

  function isUploaderConstructor(candidate) {
    return typeof candidate === "function"
      && typeof candidate.prototype?.addFile === "function"
      && typeof candidate.prototype?.start === "function";
  }

  function getUploaderConstructor(sdkModule) {
    const candidate = sdkModule?.default || sdkModule;
    return isUploaderConstructor(candidate) ? candidate : null;
  }

  function findUploaderConstructor(require) {
    const known = require?.m?.[SDK_MODULE_ID]
      ? getUploaderConstructor(tryRequireModule(require, SDK_MODULE_ID))
      : null;
    if (known) return known;

    for (const [moduleId, factory] of Object.entries(require?.m || {})) {
      const source = functionSource(factory);
      if (!source.includes("addFile") || !source.includes("refreshSTSToken")) continue;
      const candidate = getUploaderConstructor(tryRequireModule(require, moduleId));
      if (candidate) return candidate;
    }
    return null;
  }

  function loadRuntimeScript(runtimeWindow, url) {
    return new Promise((resolve, reject) => {
      let document;
      try {
        document = runtimeWindow?.document;
      } catch {
        reject(new Error("千川官方上传运行时无法访问"));
        return;
      }
      if (!document?.createElement) {
        reject(new Error("千川官方上传运行时未就绪"));
        return;
      }
      const script = document.createElement("script");
      const nonceScript = document.querySelector?.("script[nonce]");
      const nonce = nonceScript?.nonce || nonceScript?.getAttribute?.("nonce") || "";
      script.src = url;
      script.async = true;
      if (nonce) script.nonce = nonce;
      script.onload = () => {
        script.remove?.();
        resolve();
      };
      script.onerror = () => {
        script.remove?.();
        reject(new Error("千川上传 SDK 加载失败"));
      };
      (document.head || document.documentElement || document.body)?.appendChild(script);
    });
  }

  async function registerRuntimeScriptFactories(runtimeWindow, require, url) {
    const fetch = runtimeWindow?.fetch;
    const evaluate = runtimeWindow?.eval;
    if (typeof fetch !== "function" || typeof evaluate !== "function") {
      throw new Error("千川官方上传运行时不支持脚本恢复");
    }
    const response = await fetch.call(runtimeWindow, url, { credentials: "omit" });
    if (!response?.ok) throw new Error(`千川上传 SDK 请求失败（HTTP ${response?.status || 0}）`);
    const source = await response.text();
    if (!source?.includes("webpackChunkuni_creation")) {
      throw new Error("千川上传 SDK 返回内容异常");
    }
    const chunks = runtimeWindow?.webpackChunkuni_creation;
    if (!Array.isArray(chunks) || !require?.m) {
      throw new Error("千川官方上传运行时未就绪");
    }
    const captured = [];
    const originalPush = chunks.push;
    chunks.push = (payload) => {
      captured.push(payload);
      return chunks.length;
    };
    try {
      evaluate.call(runtimeWindow, `${source}\n//# sourceURL=${url}`);
    } finally {
      chunks.push = originalPush;
    }
    for (const payload of captured) {
      Object.assign(require.m, payload?.[1] || {});
    }
    if (!captured.some((payload) => payload?.[1]?.[SDK_MODULE_ID])) {
      throw new Error("千川上传 SDK 未返回上传器模块");
    }
    if (require.c?.[SDK_MODULE_ID]) delete require.c[SDK_MODULE_ID];
  }

  async function ensureUploaderConstructor(require, runtimeWindow) {
    uploaderLoadError = "";
    const errors = [];
    let Uploader = findUploaderConstructor(require);
    if (Uploader) return Uploader;

    if (typeof require.e === "function") {
      try {
        await require.e(SDK_CHUNK_ID);
      } catch (error) {
        errors.push(error?.message || "Webpack 分包加载失败");
      }
      Uploader = findUploaderConstructor(require);
      if (Uploader) return Uploader;
    }

    try {
      await loadRuntimeScript(runtimeWindow, SDK_FALLBACK_URL);
    } catch (error) {
      errors.push(error?.message || "官方脚本加载失败");
    }
    Uploader = findUploaderConstructor(require);
    if (Uploader) return Uploader;

    try {
      await registerRuntimeScriptFactories(runtimeWindow, require, SDK_FALLBACK_URL);
    } catch (error) {
      errors.push(error?.message || "官方脚本注册失败");
    }
    Uploader = findUploaderConstructor(require);
    if (!Uploader) uploaderLoadError = [...new Set(errors.filter(Boolean))].join("；") || "官方上传器未注册";
    return Uploader;
  }

  function normalizeUploadHelpers(module) {
    const EI = typeof module?.EI === "function"
      ? module.EI
      : findFunctionExport(module, ["videoHost", "appId", "spaceName"]);
    const Pc = typeof module?.Pc === "function"
      ? module.Pc
      : findFunctionExport(module, ["code", "data"]);
    const pk = typeof module?.pk === "function"
      ? module.pk
      : findFunctionExport(module, ["uploadResult", "fileName"]);
    return { EI, Pc, pk };
  }

  function normalizeMaterialApi(module) {
    const DS = typeof module?.DS === "function"
      ? module.DS
      : findFunctionExport(module, ["bind-video-to-owner"]);
    return { DS };
  }

  async function resolveRuntime(aavid, forceFresh = false) {
    const runtimeWindow = await ensureRuntimeWindow(aavid, forceFresh);
    const require = getWebpackRequire(runtimeWindow);
    const Uploader = await ensureUploaderConstructor(require, runtimeWindow);

    const helperModule = findRuntimeModule(require, UPLOAD_HELPER_MODULE_ID, ["EI", "Pc", "pk"])
      || findRuntimeModuleBySource(require, UPLOAD_HELPER_MODULE_ID, ["videoHost", "uploadResult"]);
    const accountHelpers = findRuntimeModule(require, ACCOUNT_HELPER_MODULE_ID, ["Ao"])
      || findRuntimeModuleBySource(require, ACCOUNT_HELPER_MODULE_ID, ["aavid"])
      || {};
    const materialModule = findRuntimeModule(require, MATERIAL_API_MODULE_IDS, ["DS"])
      || findRuntimeModuleBySource(require, MATERIAL_API_MODULE_IDS, ["bind-video-to-owner"]);
    const helpers = normalizeUploadHelpers(helperModule);
    const materialApi = normalizeMaterialApi(materialModule);
    const missing = [];
    if (!Uploader) missing.push(`上传 SDK${uploaderLoadError ? `：${uploaderLoadError}` : ""}`);
    if (typeof helpers.EI !== "function") missing.push("上传配置");
    if (typeof helpers.Pc !== "function") missing.push("上传授权");
    if (typeof helpers.pk !== "function") missing.push("素材格式化");
    if (typeof materialApi.DS !== "function") missing.push("素材归属绑定");
    return { Uploader, helpers, accountHelpers, materialApi, runtimeWindow, missing };
  }

  async function loadRuntime(aavid) {
    const accountId = getAccountId(aavid);
    if (runtimePromise && runtimeAccountId !== accountId) runtimePromise = null;
    if (!runtimePromise) {
      runtimeAccountId = accountId;
      runtimePromise = (async () => {
        let runtime = await resolveRuntime(aavid);
        if (runtime.missing.length) runtime = await resolveRuntime(aavid, true);
        if (runtime.missing.length) {
          throw new Error(`千川原生上传组件自动重连失败（${runtime.missing.join("、")}），请刷新千川页面后重试`);
        }
        return runtime;
      })().catch((error) => {
        runtimePromise = null;
        runtimeAccountId = "";
        resetRuntimeWindow();
        throw error;
      });
    }
    const runtime = await runtimePromise;
    const userId = runtime.accountHelpers?.Ao?.() || String(aavid || "");
    if (!userId) throw new Error("未获取到千川账户 ID");
    return {
      ...runtime,
      userId,
      config: runtime.helpers.EI(userId)
    };
  }

  function uploadErrorMessage(event) {
    const extra = event?.extra || {};
    return extra.message || extra.error || event?.message || "素材上传失败，请稍后重试";
  }

  async function requestToken(helpers) {
    const response = await helpers.Pc();
    if (Number(response?.code) !== 0 || !response?.data) {
      throw new Error(response?.msg || "千川上传授权获取失败");
    }
    return response.data;
  }

  function timeoutValue(value, fallback) {
    const number = Number(value);
    return Number.isFinite(number) && number > 0 ? number : fallback;
  }

  function withTimeout(task, timeoutMs, message) {
    return new Promise((resolve, reject) => {
      const timer = setTimeout(() => reject(new Error(message)), timeoutMs);
      Promise.resolve(task).then(
        (value) => {
          clearTimeout(timer);
          resolve(value);
        },
        (error) => {
          clearTimeout(timer);
          reject(error);
        }
      );
    });
  }

  async function bindVideosToOwner(materialApi, uploaded) {
    const vids = uploaded.map(({ item, videoInfo }) => ({
      file_name: String(videoInfo?.fileName || item?.name || "video.mp4"),
      video_id: String(videoInfo?.videoId || "").trim()
    }));
    const response = await materialApi.DS({ vids });
    const statusCode = Number(response?.status_code ?? response?.code ?? -1);
    if (statusCode !== 0) {
      throw new Error(response?.message || response?.msg || "千川视频素材归属绑定失败");
    }

    const materialIds = Object.entries(response?.data?.vidToMidMap || {}).reduce((result, [videoId, materialId]) => {
      if (videoId && materialId) result[String(videoId).toLowerCase()] = String(materialId);
      return result;
    }, {});
    const missing = [];
    uploaded.forEach(({ item, videoInfo }) => {
      const materialId = materialIds[String(videoInfo.videoId).toLowerCase()];
      if (materialId) videoInfo.materialId = materialId;
      else missing.push(item?.name || "视频");
    });
    if (missing.length) {
      throw new Error(`千川未返回素材库 ID：${missing.join("、")}，请稍后重试`);
    }
  }

  async function uploadBatch(items, options = {}) {
    const list = Array.from(items || []).filter((item) => item?.file instanceof Blob);
    if (!list.length) return [];
    if (list.length > MAX_BATCH_SIZE) throw new Error(`单个后台上传批次不能超过 ${MAX_BATCH_SIZE} 条`);

    const runtime = await loadRuntime(options.aavid);
    const stallTimeoutMs = timeoutValue(options.stallTimeoutMs, UPLOAD_STALL_TIMEOUT_MS);
    const totalTimeoutMs = timeoutValue(options.totalTimeoutMs, UPLOAD_TOTAL_TIMEOUT_MS);
    const requestTimeoutMs = timeoutValue(options.requestTimeoutMs, UPLOAD_REQUEST_TIMEOUT_MS);
    let token = await withTimeout(
      requestToken(runtime.helpers),
      requestTimeoutMs,
      "千川上传授权请求超时，请检查网络后重试"
    );
    const uploader = new runtime.Uploader(runtime.config);
    const records = new Map();

    const settleRecord = (record, error, value) => {
      if (!record || record.settled) return;
      record.settled = true;
      clearTimeout(record.stallTimer);
      clearTimeout(record.totalTimer);
      records.delete(record.key);
      if (error) record.reject(error);
      else record.resolve(value);
    };

    const failStalledRecord = (record, message) => {
      if (!record || record.settled) return;
      try {
        options.onStall?.(record.item, message);
      } catch {}
      settleRecord(record, new Error(message));
    };

    const armStallWatchdog = (record) => {
      clearTimeout(record.stallTimer);
      record.stallTimer = setTimeout(() => {
        failStalledRecord(
          record,
          `${record.item?.name || "视频"} 长时间没有上传进度，已标记失败，请检查网络后重试`
        );
      }, stallTimeoutMs);
    };

    uploader.on("progress", (event) => {
      const record = records.get(event?.key);
      if (!record || record.settled) return;
      const progress = Math.max(0, Math.min(100, Number(event?.percent) || 0));
      if (progress > record.lastProgress) {
        record.lastProgress = progress;
        armStallWatchdog(record);
      }
      options.onProgress?.(record.item, progress);
    });

    uploader.on("error", async (event) => {
      const record = records.get(event?.key);
      if (!record || record.settled) return;
      const errorCode = Number(event?.extra?.errorCode);
      if (errorCode === 100026 && record.tokenRetries < 1) {
        record.tokenRetries += 1;
        armStallWatchdog(record);
        try {
          token = await withTimeout(
            requestToken(runtime.helpers),
            requestTimeoutMs,
            "千川上传授权刷新超时，请检查网络后重试"
          );
          if (record.settled) return;
          uploader.refreshSTSToken(token);
          uploader.start(event.key);
          return;
        } catch (error) {
          settleRecord(record, error);
          return;
        }
      }
      settleRecord(record, new Error(uploadErrorMessage(event)));
    });

    uploader.on("complete", async (event) => {
      const record = records.get(event?.key);
      if (!record || record.settled) return;
      armStallWatchdog(record);
      try {
        const formatted = await withTimeout(
          runtime.helpers.pk({
            ...event,
            file: record.uploadFile,
            fileName: event?.fileName || record.item.name || record.uploadFile?.name || "video.mp4"
          }),
          requestTimeoutMs,
          `${record.item?.name || "视频"} 上传完成后的素材处理超时，请重试`
        );
        if (record.settled) return;
        if (Number(formatted?.code) !== 0 || !formatted?.data?.videoInfo?.videoId) {
          throw new Error(formatted?.msg || "千川未返回有效的视频素材 ID");
        }
        settleRecord(record, null, formatted.data.videoInfo);
      } catch (error) {
        settleRecord(record, error);
      }
    });

    const tasks = list.map((item) => new Promise((resolve, reject) => {
      let key = "";
      let uploadFile = item.file;
      try {
        const RuntimeFile = runtime.runtimeWindow?.File;
        if (typeof RuntimeFile === "function" && !(uploadFile instanceof RuntimeFile)) {
          uploadFile = new RuntimeFile([uploadFile], item.name || uploadFile.name || "video.mp4", {
            type: uploadFile.type || "video/mp4",
            lastModified: Number(uploadFile.lastModified) || Date.now()
          });
        }
        key = uploader.addFile({ file: uploadFile, stsToken: token, type: "video" });
      } catch (error) {
        reject(error);
        return;
      }
      if (!key) {
        reject(new Error(`${item.name || "视频"} 未能加入千川上传队列`));
        return;
      }
      const record = {
        key,
        item,
        uploadFile,
        resolve,
        reject,
        settled: false,
        tokenRetries: 0,
        lastProgress: 0,
        stallTimer: 0,
        totalTimer: 0
      };
      records.set(key, record);
      armStallWatchdog(record);
      record.totalTimer = setTimeout(() => {
        failStalledRecord(
          record,
          `${item.name || "视频"} 上传时间超过上限，已标记失败，请检查网络后重试`
        );
      }, totalTimeoutMs);
      options.onProgress?.(item, 0);
      try {
        uploader.start(key);
      } catch (error) {
        settleRecord(record, error);
      }
    }));

    const results = await Promise.allSettled(tasks);
    const uploaded = results.flatMap((result, index) => result.status === "fulfilled"
      ? [{ item: list[index], videoInfo: result.value, index }]
      : []);
    if (!uploaded.length) return results;

    try {
      await withTimeout(
        bindVideosToOwner(runtime.materialApi, uploaded),
        requestTimeoutMs,
        "千川素材归属绑定超时，已停止本批任务，请重试"
      );
    } catch (error) {
      uploaded.forEach(({ index }) => {
        results[index] = { status: "rejected", reason: error };
      });
    }
    return results;
  }

  window.MMW_QIANCHUAN_MATERIAL_UPLOADER = Object.freeze({
    version: "4.44.0",
    maxBatchSize: MAX_BATCH_SIZE,
    uploadBatch
  });
})();
