(() => {
  if (typeof window !== "undefined" && window.MMWQianchuanDataReport) return;

  const CONTRACT_VERSION = "1.1.0";
  const PLAN_ID = /^\d{10,24}$/;
  const SCOPES = new Set(["overall_promotion", "live_room", "multiplier_product", "multiplier_live_room"]);
  const DEFAULT_SETTINGS = Object.freeze({
    enabled: false,
    intervalMinutes: 30,
    includeDashboard: true,
    includePlans: true,
    deliveryMode: "aggregate"
  });

  function normalizeSettings(value = {}) {
    const source = value && typeof value === "object" ? value : {};
    const interval = Number(source.intervalMinutes);
    return {
      enabled: source.enabled === true,
      intervalMinutes: Number.isInteger(interval) && interval >= 1 && interval <= 1440
        ? interval : DEFAULT_SETTINGS.intervalMinutes,
      includeDashboard: source.includeDashboard !== false,
      includePlans: source.includePlans !== false,
      deliveryMode: source.deliveryMode === "per_account" ? "per_account" : "aggregate"
    };
  }

  function isDue(lastReportAt, intervalMinutes, now = Date.now()) {
    const settings = normalizeSettings({ intervalMinutes });
    return !Number(lastReportAt) || now - Number(lastReportAt) >= settings.intervalMinutes * 60_000;
  }

  function buildReport(options = {}) {
    const config = options.config && typeof options.config === "object" ? options.config : {};
    const settings = normalizeSettings(config.dataReport);
    if (!settings.enabled) throw new Error("定时数据通知未启用");
    if (!settings.includeDashboard && !settings.includePlans) throw new Error("请至少选择一种数据通知类型");
    const accountKey = identifier(options.accountKey, 128);
    const scope = String(options.scope || "").trim().toLowerCase();
    const workerInstanceId = identifier(options.workerInstanceId, 128);
    if (!accountKey || !workerInstanceId || !SCOPES.has(scope)) throw new Error("数据通知缺少可信页面身份");

    const now = Math.max(1, Number(options.now) || Date.now());
    const snapshot = options.snapshot && typeof options.snapshot === "object" ? options.snapshot : {};
    const targetMode = config.targetMode === "selected" ? "selected" : "all";
    const planIds = selectedPlanIds(config);
    const planId = planIds[0] || "";
    if (targetMode === "selected" && !planIds.length) throw new Error("指定计划数据通知缺少完整计划 ID");

    const dashboardMetrics = settings.includeDashboard ? collectDashboardMetrics(snapshot) : [];
    const plans = settings.includePlans ? collectPlans(snapshot.rows, targetMode, planIds) : [];
    if (!dashboardMetrics.length && !plans.length) throw new Error("当前页面还没有可发送的千川数据");
    const scheduleBucket = Math.floor(now / (settings.intervalMinutes * 60_000));
    const reportId = makeReportId(options.randomUUID, now);
    const dataFingerprint = hashText(JSON.stringify({ dashboardMetrics, plans }));

    return {
      contractVersion: CONTRACT_VERSION,
      reportId,
      workerInstanceId,
      accountKey,
      accountName: cleanText(options.accountName, 160),
      scope,
      targetMode,
      planId,
      scheduleBucket,
      capturedAt: now,
      pageUpdatedAt: cleanText(snapshot.pageUpdatedText, 80),
      dataRange: cleanText(snapshot.dataRange, 40),
      dataSource: "qianchuan_dom",
      dataFingerprint,
      deliveryMode: settings.deliveryMode,
      channels: {
        client: true,
        weixin: false,
        feishu: false
      },
      dashboardMetrics,
      plans
    };
  }

  function collectDashboardMetrics(snapshot) {
    const values = [];
    const balance = finite(snapshot.accountBalance);
    if (balance != null) values.push({ label: "账户余额", value: balance });
    const source = Array.isArray(snapshot.summaryMetrics) ? snapshot.summaryMetrics : [];
    const seen = new Set(values.map((item) => item.label));
    for (const item of source) {
      const label = cleanText(item?.label, 48).replace(/\(元\)$/g, "");
      const value = reportMetricValue(item);
      if (!label || value == null || seen.has(label)) continue;
      seen.add(label);
      values.push({ label, value });
      if (values.length >= 20) break;
    }
    return values;
  }

  function selectedPlanIds(config) {
    const listed = Array.isArray(config?.planIds) ? config.planIds : [];
    const source = listed.some((value) => String(value || "").trim()) ? listed : [config?.planId];
    const planIds = source.map((value) => String(value || "").trim()).filter(Boolean);
    if (planIds.length > 20) throw new Error("指定计划数据通知最多支持 20 条计划 ID");
    if (planIds.some((planId) => !PLAN_ID.test(planId))) throw new Error("指定计划数据通知包含无效计划 ID");
    if (new Set(planIds).size !== planIds.length) throw new Error("指定计划数据通知包含重复计划 ID");
    return planIds;
  }

  function collectPlans(rowsValue, targetMode, planIds) {
    const rows = (Array.isArray(rowsValue) ? rowsValue : [])
      .filter((row) => PLAN_ID.test(String(row?.id || "")))
      .slice(0, 40);
    let selected = rows;
    if (targetMode === "selected") {
      selected = [];
      for (const planId of planIds) {
        const matches = rows.filter((row) => String(row.id) === planId);
        if (matches.length !== 1) {
          throw new Error(matches.length
            ? `指定计划 ${planId} 在当前列表重复，数据通知已停止`
            : `当前列表没有找到指定计划 ${planId}，数据通知已停止`);
        }
        selected.push(matches[0]);
      }
    }
    const seen = new Set();
    return selected.map((row) => {
      const id = String(row.id);
      if (seen.has(id)) throw new Error(`计划 ${id} 在当前列表重复，数据通知已停止`);
      seen.add(id);
      const text = cleanText(row.text, 2400);
      const metrics = normalizeMetrics(row.metrics);
      return {
        planId: id,
        planName: cleanText(row.name, 80) || planName(text, id),
        status: ["active", "paused"].includes(row.status) ? row.status : "unknown",
        netRevenue: planMetric(metrics, text, ["用户实际支付净成交金额", "净成交金额"]),
        netRoi: planMetric(metrics, text, ["净成交ROI", "净ROI", "综合营销ROI"]),
        spend: planMetric(metrics, text, ["整体消耗", "消耗"]),
        targetRoi: finite(row.roi) ?? metric(text, ["净成交ROI目标", "综合营销ROI目标", "目标ROI", "ROI目标"]),
        metrics
      };
    });
  }

  function normalizeMetrics(value) {
    const seen = new Set();
    const metrics = [];
    for (const item of Array.isArray(value) ? value : []) {
      const label = cleanText(item?.label, 48).replace(/\(元\)$/g, "");
      const metricValue = reportMetricValue(item);
      if (!label || metricValue == null || seen.has(label)) continue;
      seen.add(label);
      metrics.push({ label, value: metricValue });
      if (metrics.length >= 24) break;
    }
    return metrics;
  }

  function planMetric(metrics, text, labels) {
    for (const label of labels) {
      const item = metrics.find((candidate) => candidate.label === label);
      if (!item) continue;
      const value = finite(String(item?.value ?? "").replace(/[%￥¥,]/g, ""));
      if (value != null) return value;
    }
    return metric(text, labels);
  }

  function reportMetricValue(item) {
    const display = cleanText(item?.value, 32);
    if (display === "--" || /^-?(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?%$/.test(display)) return display;
    return finite(item?.numericValue ?? display.replace(/[%￥¥,]/g, ""));
  }

  function metric(text, labels) {
    for (const label of labels) {
      const match = text.match(new RegExp(`${escapeRegExp(label)}\\s*[：:]?\\s*(?:¥|￥)?\\s*(-?[\\d,]+(?:\\.\\d+)?)`, "i"));
      const value = finite(match?.[1]?.replace(/,/g, ""));
      if (value != null) return value;
    }
    return null;
  }

  function planName(text, id) {
    const beforeId = text.split(new RegExp(`(?:计划)?ID\\s*[：:]?\\s*${escapeRegExp(id)}`, "i"))[0] || "";
    const value = beforeId.replace(/^(?:投放中|已暂停|暂停中|已关闭)\s*/g, "").trim();
    return cleanText(value, 80) || `计划 ${id}`;
  }

  function makeReportId(factory, now) {
    const value = typeof factory === "function" ? String(factory() || "") : "";
    if (/^[A-Za-z0-9-]{16,80}$/.test(value)) return `qcr-${value}`.slice(0, 96);
    return `qcr-${now}-${hashText(`${now}:${Math.random()}`)}`;
  }

  function identifier(value, limit) {
    const text = String(value || "").trim().slice(0, limit);
    return /^[A-Za-z0-9_.:@-]+$/.test(text) ? text : "";
  }

  function finite(value) {
    if (value === null || value === undefined || value === "") return null;
    const parsed = Number(value);
    return Number.isFinite(parsed) ? Number(parsed.toFixed(4)) : null;
  }

  function cleanText(value, limit) {
    return String(value || "").replace(/\s+/g, " ").trim().slice(0, limit);
  }

  function hashText(value) {
    let hash = 2166136261;
    for (const char of String(value)) {
      hash ^= char.charCodeAt(0);
      hash = Math.imul(hash, 16777619);
    }
    return (hash >>> 0).toString(16).padStart(8, "0");
  }

  function escapeRegExp(value) {
    return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  }

  const api = Object.freeze({ CONTRACT_VERSION, DEFAULT_SETTINGS, normalizeSettings, isDue, buildReport });
  if (typeof window !== "undefined") window.MMWQianchuanDataReport = api;
  if (typeof module !== "undefined" && module.exports) module.exports = api;
})();
