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

  const API_BASE = "https://qianchuan.jinritemai.com";
  const UPLOAD_PATH = "/ad/api/creation/v1/material/upload-image-by-mode";
  const BIND_PATH = "/ad/api/creation/material/bind-image-to-owner";
  const APP_ID = "ef06410935c24ec387a926f34b3a70f3";
  const IMAGE_MODE = 155;
  const MAX_BATCH_SIZE = 20;
  const MAX_FILE_SIZE = 10 * 1024 * 1024;
  const MIN_SIDE = 600;
  const MAX_SIDE = 3000;
  const REQUEST_TIMEOUT_MS = 90 * 1000;

  function csrfToken() {
    const value = String(document.cookie || "")
      .split(";")
      .map((item) => item.trim())
      .find((item) => item.startsWith("csrftoken="));
    return value ? decodeURIComponent(value.slice("csrftoken=".length)) : "";
  }

  function isImageFile(file) {
    const type = String(file?.type || "").toLowerCase();
    const name = String(file?.name || "").toLowerCase();
    return ["image/jpeg", "image/png"].includes(type) || /\.(jpe?g|png)$/i.test(name);
  }

  async function imageDimensions(file) {
    if (typeof createImageBitmap === "function") {
      const bitmap = await createImageBitmap(file);
      try {
        return { width: Number(bitmap.width), height: Number(bitmap.height) };
      } finally {
        bitmap.close?.();
      }
    }
    return new Promise((resolve, reject) => {
      const url = URL.createObjectURL(file);
      const image = new Image();
      image.onload = () => {
        URL.revokeObjectURL(url);
        resolve({ width: Number(image.naturalWidth), height: Number(image.naturalHeight) });
      };
      image.onerror = () => {
        URL.revokeObjectURL(url);
        reject(new Error("无法读取图片尺寸"));
      };
      image.src = url;
    });
  }

  async function validateImage(file) {
    if (!isImageFile(file)) throw new Error("仅支持 JPG、JPEG、PNG 图片");
    if (Number(file.size) > MAX_FILE_SIZE) throw new Error("图片不能超过 10 MB");
    const { width, height } = await imageDimensions(file);
    if (width !== height) throw new Error(`图片需为 1:1 方图，当前为 ${width}×${height}`);
    if (width < MIN_SIDE || width > MAX_SIDE) {
      throw new Error(`图片尺寸需在 600×600 至 3000×3000，当前为 ${width}×${height}`);
    }
    return { width, height };
  }

  async function uploadOne(item, options) {
    await validateImage(item.file);
    const token = csrfToken();
    if (!token) throw new Error("未获取到千川上传校验信息，请刷新页面后重试");

    const form = new FormData();
    form.append("fileName", item.name || item.file.name || "image.jpg");
    form.append("imageMode", String(IMAGE_MODE));
    form.append("Filedata", item.file, item.name || item.file.name || "image.jpg");

    const url = new URL(UPLOAD_PATH, API_BASE);
    if (options.aavid) url.searchParams.set("aavid", String(options.aavid));
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), Number(options.requestTimeoutMs) || REQUEST_TIMEOUT_MS);
    options.onProgress?.(item, 5);
    try {
      const response = await fetch(url.toString(), {
        method: "POST",
        credentials: "include",
        headers: { App: APP_ID, "X-CSRFToken": token },
        body: form,
        signal: controller.signal
      });
      const text = await response.text();
      let json = null;
      try {
        json = text ? JSON.parse(text) : {};
      } catch {
        throw new Error(text.slice(0, 160) || `图片上传失败（HTTP ${response.status}）`);
      }
      if (!response.ok) throw new Error(json?.message || json?.msg || `图片上传失败（HTTP ${response.status}）`);
      const data = json?.data && typeof json.data === "object" ? json.data : json;
      const statusCode = Number(json?.status_code ?? data?.status_code ?? 0);
      if (statusCode === 40002) throw new Error("当前千川账号没有图片上传权限");
      if (statusCode !== 0) throw new Error(json?.status_message || json?.message || data?.message || `图片上传失败（错误码 ${statusCode}）`);

      const image = (Array.isArray(data?.images) ? data.images : []).find(
        (entry) => Number(entry?.usedImageMode) === IMAGE_MODE
      );
      const imageUrl = String(image?.signUrl?.mainUrl || image?.imageWebUrl || "");
      const webUri = String(image?.imageWebUri || "");
      const materialId = String(image?.materialId || "");
      if (!image || !webUri || !materialId) throw new Error("千川未返回可用于投放的商品方图素材");
      options.onProgress?.(item, 85);
      return {
        materialId,
        imageMode: IMAGE_MODE,
        width: Number(image.width || data.originWidth) || 0,
        height: Number(image.height || data.originHeight) || 0,
        imageUrl,
        webUri
      };
    } catch (error) {
      if (error?.name === "AbortError") throw new Error("图片上传超时，请检查网络后重试");
      throw error;
    } finally {
      clearTimeout(timer);
    }
  }

  async function bindImagesToOwner(uploaded, options) {
    const token = csrfToken();
    if (!token) throw new Error("未获取到千川素材入库校验信息，请刷新页面后重试");
    const vids = uploaded.map(({ item, imageInfo }) => ({
      file_name: String(item.name || item.file?.name || "image.jpg"),
      web_uri: String(imageInfo.webUri || ""),
      original_image_uri: String(imageInfo.imageUrl || "")
    })).filter((item) => item.web_uri);
    if (!vids.length) throw new Error("千川未返回可绑定到图片素材库的资源地址");

    const url = new URL(BIND_PATH, API_BASE);
    if (options.aavid) url.searchParams.set("aavid", String(options.aavid));
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), Number(options.requestTimeoutMs) || REQUEST_TIMEOUT_MS);
    try {
      const response = await fetch(url.toString(), {
        method: "POST",
        credentials: "include",
        headers: {
          "Content-Type": "application/json",
          "X-CSRFToken": token
        },
        body: JSON.stringify({ vids }),
        signal: controller.signal
      });
      const text = await response.text();
      let json = null;
      try {
        json = text ? JSON.parse(text) : {};
      } catch {
        throw new Error(text.slice(0, 160) || `图片素材入库失败（HTTP ${response.status}）`);
      }
      if (!response.ok) {
        throw new Error(json?.message || json?.msg || `图片素材入库失败（HTTP ${response.status}）`);
      }
      const statusCode = Number(json?.status_code ?? json?.code ?? 0);
      if (statusCode !== 0) {
        throw new Error(json?.status_message || json?.message || json?.msg || `图片素材入库失败（错误码 ${statusCode}）`);
      }
    } catch (error) {
      if (error?.name === "AbortError") throw new Error("图片素材入库超时，请检查网络后重试");
      throw new Error(`千川图片素材入库失败：${error?.message || String(error)}`);
    } finally {
      clearTimeout(timer);
    }
  }

  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 results = await Promise.allSettled(list.map((item) => uploadOne(item, options)));
    const uploaded = results.flatMap((result, index) => result.status === "fulfilled"
      ? [{ index, item: list[index], imageInfo: result.value }]
      : []);
    if (!uploaded.length) return results;

    try {
      await bindImagesToOwner(uploaded, options);
      uploaded.forEach(({ index, item, imageInfo }) => {
        options.onProgress?.(item, 100);
        results[index] = { status: "fulfilled", value: { ...imageInfo, libraryBound: true } };
      });
    } catch (error) {
      uploaded.forEach(({ index }) => {
        results[index] = { status: "rejected", reason: error };
      });
    }
    return results;
  }

  window.MMW_QIANCHUAN_IMAGE_UPLOADER = Object.freeze({
    version: "4.32.1",
    imageMode: IMAGE_MODE,
    maxBatchSize: MAX_BATCH_SIZE,
    maxFileSize: MAX_FILE_SIZE,
    uploadBatch
  });
})();
