(function feeWidgetBootstrap() {
  const HOME_HOST = "mms.pinduoduo.com";
  const HOME_PATH = "/home";
  const ROOT_ID = "pdd-fee-widget-root";
  const PAGE_HOOK_ID = "pdd-fee-page-hook";
  const PAGE_HOOK_SOURCE = "pdd-fee-network-hook";
  const STORAGE_KEYS = {
    legacyHistory: "pddFeeHistory",
    storeCache: "pddFeeStoreCache",
    lastStore: "pddFeeLastStoreName"
  };
  const TRADE_API_PATH = "/sydney/api/mallTrade/queryMallTradeList";
  const SPEND_API_PATH = "/mms-gateway/apollo/api/report/queryHourlyRangeReport";
  const REFUND_REFRESH_INTERVAL = 5 * 60 * 1000;
  const SPEND_REFRESH_INTERVAL = 10 * 60 * 1000;
  const TODAY_CURVE_COLOR = "#407cff";
  const YESTERDAY_CURVE_COLOR = "#ffc340";

  const runtime = {
    initialized: false,
    root: null,
    mountTarget: null,
    observer: null,
    domObserver: null,
    observedNode: null,
    syncTimer: null,
    routeTimer: null,
    renderQueued: false,
    syncQueued: false,
    refundData: null,
    isFetchingRefund: false,
    lastRefundFetchAt: 0,
    isFetchingSpendHistory: false,
    lastStateHash: "",
    storedHistory: {},
    storeCache: {},
    lastKnownStoreName: "",
    lastSpendRefreshAt: {},
    lastSavedHistoryHash: "",
    storageListenerBound: false,
    pageMessageBound: false
  };

  function boot() {
    if (runtime.initialized) return;
    runtime.initialized = true;
    loadState().then(() => {
      bindStorageListener();
      bindPageMessages();
      installPageBridge();
      startRouteLoop();
      ensureDomObserver();
      syncWidget();
    });
  }

  function startRouteLoop() {
    if (!runtime.routeTimer) runtime.routeTimer = window.setInterval(syncWidget, 1200);
    window.addEventListener("popstate", syncWidget);
    window.addEventListener("hashchange", syncWidget);
  }

  function ensureDomObserver() {
    if (runtime.domObserver) return;
    runtime.domObserver = new MutationObserver((mutations) => {
      if (runtime.root) {
        const isOwn = mutations.every(m => runtime.root.contains(m.target));
        if (isOwn) return;
      }
      if (runtime.syncQueued) return;
      runtime.syncQueued = true;
      window.requestAnimationFrame(() => {
        runtime.syncQueued = false;
        syncWidget();
      });
    });
    runtime.domObserver.observe(document.documentElement, { childList: true, subtree: true });
  }

  function isHomePage() {
    return window.location.hostname === HOME_HOST && /^\/home\/?$/.test(window.location.pathname);
  }

  function getTodayString() {
    const d = new Date();
    const year = d.getFullYear();
    const month = String(d.getMonth() + 1).padStart(2, '0');
    const day = String(d.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  }

  // 新增：提取当前店铺名称
  function getStoreName() {
    const nameNode = document.querySelector(".user-name-text");
    return nameNode ? nameNode.textContent.trim() : "";
  }

  function resolveStoreName(preferredName) {
    const explicitName = (preferredName || "").trim();
    const pageName = getStoreName();
    const fallbackName = getFallbackStoreName();
    const storeName = explicitName || pageName || runtime.lastKnownStoreName || fallbackName;
    if (storeName) rememberStoreName(storeName);
    return storeName;
  }

  function getFallbackStoreName() {
    const names = new Set([
      ...Object.keys(runtime.storeCache || {}),
      ...Object.keys(runtime.storedHistory || {})
    ].filter(Boolean));
    if (names.size === 1) return Array.from(names)[0];
    return "";
  }

  function rememberStoreName(storeName) {
    if (!storeName || runtime.lastKnownStoreName === storeName) return;
    runtime.lastKnownStoreName = storeName;
    if (typeof chrome !== "undefined" && chrome.storage && chrome.storage.local) {
      chrome.storage.local.set({ [STORAGE_KEYS.lastStore]: storeName });
    }
  }

  function getStoreCache(storeName) {
    if (!storeName) return null;
    if (!runtime.storeCache[storeName]) {
      runtime.storeCache[storeName] = {
        tradeHistory: [],
        spendHistory: [],
        spendRequest: null,
        tradeUpdatedAt: "",
        spendUpdatedAt: ""
      };
    }
    return runtime.storeCache[storeName];
  }

  function persistStoreCache() {
    if (typeof chrome === "undefined" || !chrome.storage || !chrome.storage.local) return;
    chrome.storage.local.set({ [STORAGE_KEYS.storeCache]: runtime.storeCache });
  }

  function normalizeDateKey(value) {
    const text = String(value || "");
    const match = text.match(/(\d{4}-\d{2}-\d{2})/);
    return match ? match[1] : "";
  }

  function toFiniteNumber(value) {
    const numeric = typeof value === "number" ? value : Number(String(value || "").replace(/,/g, ""));
    return Number.isFinite(numeric) ? numeric : NaN;
  }

  function sortByDate(list) {
    return list.slice().sort((left, right) => left.date.localeCompare(right.date));
  }

  function buildTradeHistory(dayList) {
    const map = new Map();
    (Array.isArray(dayList) ? dayList : []).forEach((day) => {
      const date = normalizeDateKey(day?.stateDate);
      const amount = toFiniteNumber(day?.payOrdrAmt);
      if (!date || !Number.isFinite(amount)) return;
      map.set(date, { date, amount });
    });
    return sortByDate(Array.from(map.values()));
  }

  function buildSpendHistory(dailyReportList) {
    const map = new Map();
    (Array.isArray(dailyReportList) ? dailyReportList : []).forEach((item) => {
      const date = normalizeDateKey(item?.date || item?.statDate || item?.day || item?.ds);
      const rawSpend = toFiniteNumber(item?.spend);
      const spend = rawSpend / 1000;
      if (!date || !Number.isFinite(spend)) return;
      map.set(date, { date, spend });
    });
    return sortByDate(Array.from(map.values()));
  }

  function sanitizeReplayHeaders(headers, body) {
    const source = headers && typeof headers === "object" ? headers : {};
    const blocked = new Set([
      "accept-encoding",
      "connection",
      "content-length",
      "cookie",
      "host",
      "origin",
      "referer"
    ]);
    const result = {};
    Object.entries(source).forEach(([key, value]) => {
      const lowerKey = String(key || "").toLowerCase();
      if (!lowerKey || blocked.has(lowerKey) || lowerKey.startsWith("sec-") || lowerKey.startsWith("proxy-")) return;
      result[key] = value;
    });
    if (!Object.keys(result).some((key) => key.toLowerCase() === "content-type") && typeof body === "string" && /^[\[{]/.test(body.trim())) {
      result["Content-Type"] = "application/json";
    }
    return result;
  }

  function saveTradeHistory(storeName, dayList) {
    const history = buildTradeHistory(dayList);
    if (!storeName || !history.length) return;
    const storeData = getStoreCache(storeName);
    storeData.tradeHistory = history;
    storeData.tradeUpdatedAt = new Date().toISOString();
    persistStoreCache();
    queueRender();
  }

  function saveSpendHistory(storeName, dailyReportList, requestMeta) {
    const history = buildSpendHistory(dailyReportList);
    if (!storeName || !history.length) return;
    const storeData = getStoreCache(storeName);
    storeData.spendHistory = history;
    storeData.spendUpdatedAt = new Date().toISOString();
    if (requestMeta?.url) {
      storeData.spendRequest = {
        url: requestMeta.url,
        method: requestMeta.method || "POST",
        body: typeof requestMeta.body === "string" ? requestMeta.body : "",
        headers: sanitizeReplayHeaders(requestMeta.headers, requestMeta.body),
        capturedAt: new Date().toISOString()
      };
    }
    persistStoreCache();
    queueRender();
  }

  async function refreshHistoricalSpend(storeName) {
    const targetStore = resolveStoreName(storeName);
    const storeData = getStoreCache(targetStore);
    if (!targetStore || !storeData?.spendRequest || runtime.isFetchingSpendHistory) return;

    const lastRefreshAt = runtime.lastSpendRefreshAt[targetStore] || 0;
    if (Date.now() - lastRefreshAt < SPEND_REFRESH_INTERVAL) return;

    runtime.isFetchingSpendHistory = true;
    runtime.lastSpendRefreshAt[targetStore] = Date.now();
    try {
      const response = await fetch(storeData.spendRequest.url, {
        method: storeData.spendRequest.method || "POST",
        credentials: "include",
        headers: sanitizeReplayHeaders(storeData.spendRequest.headers, storeData.spendRequest.body),
        body: storeData.spendRequest.body || undefined
      });
      const json = await response.json();
      const dailyReportList = json?.result?.dailyReportList || [];
      saveSpendHistory(targetStore, dailyReportList, storeData.spendRequest);
    } catch (error) {
      console.error("刷新直通车历史花费失败:", error);
      runtime.lastSpendRefreshAt[targetStore] = 0;
    } finally {
      runtime.isFetchingSpendHistory = false;
    }
  }

  async function fetchMonthlyRefundData() {
    if (runtime.isFetchingRefund) return;
    if (runtime.refundData && Date.now() - runtime.lastRefundFetchAt < REFUND_REFRESH_INTERVAL) return;
    runtime.isFetchingRefund = true;

    try {
      const queryDate = getTodayString();
      const response = await fetch(`https://${HOME_HOST}${TRADE_API_PATH}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ queryType: 2, queryDate: queryDate }) 
      });
      
      const json = await response.json();
      const dailyList = json?.result?.dayList || [];
      const storeName = resolveStoreName();
      saveTradeHistory(storeName, dailyList);

      let totalAmount = 0;
      let totalRefund = 0;

      dailyList.forEach(day => {
        totalAmount += (day.payOrdrAmt || 0);
        totalRefund += (day.sucRfOrdrAmt1d || 0);
      });

      runtime.refundData = {
        amount: totalAmount,
        refund: totalRefund,
        rate: totalAmount > 0 ? totalRefund / totalAmount : 0
      };
      runtime.lastRefundFetchAt = Date.now();
      queueRender(); 
    } catch (error) {
      console.error("获取 30 日退款数据失败:", error);
    } finally {
      runtime.isFetchingRefund = false;
    }
  }

  function syncWidget() {
    if (!isHomePage()) {
      disconnectObserver();
      removeWidget();
      return;
    }
    const mountTarget = findMountTarget();
    if (!mountTarget) return;

    fetchMonthlyRefundData();
    refreshHistoricalSpend(resolveStoreName());
    ensureWidget(mountTarget);
    observeDashboard();
    render();

    if (!runtime.syncTimer) {
      runtime.syncTimer = window.setInterval(render, 3000);
    }
  }

  function findMountTarget() {
    return (
      document.querySelector(".manage-data-chart") ||
      document.querySelector('[class*="manage-data-chart"]') ||
      document.querySelector('[class*="ManageData"]')
    );
  }

  function ensureWidget(mountTarget) {
    runtime.mountTarget = mountTarget;

    if (!runtime.root) {
      runtime.root = document.createElement("div");
      runtime.root.id = ROOT_ID;
      runtime.root.className = "pdd-fee-widget";
      runtime.root.innerHTML = `
        <section class="pdd-fee-widget__card" role="dialog" aria-label="费比看板">
          <header class="pdd-fee-widget__header">
            <div class="pdd-fee-widget__header-main">
              <div class="pdd-fee-widget__brand" aria-hidden="true">
                <svg viewBox="0 0 64 64" class="pdd-fee-widget__brand-icon">
                  <defs>
                    <linearGradient id="pdd-fee-brand-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
                      <stop offset="0%" stop-color="#ff7a59"></stop>
                      <stop offset="100%" stop-color="#14b8a6"></stop>
                    </linearGradient>
                  </defs>
                  <rect x="6" y="6" width="52" height="52" rx="14" fill="url(#pdd-fee-brand-gradient)"></rect>
                  <path d="M18 42h8l4-12 7 5 9-16" fill="none" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path>
                  <circle cx="18" cy="42" r="3" fill="#fff"></circle>
                  <circle cx="30" cy="30" r="3" fill="#fff" opacity="0.9"></circle>
                  <circle cx="37" cy="35" r="3" fill="#fff" opacity="0.9"></circle>
                  <circle cx="46" cy="19" r="3" fill="#fff"></circle>
                </svg>
              </div>
              <div class="pdd-fee-widget__heading">
                <div class="pdd-fee-widget__title">费比看板</div>
                <div class="pdd-fee-widget__subtitle" data-role="subtitle">等待首页数据</div>
              </div>
            </div>
            <div class="pdd-fee-widget__header-chip">实时</div>
          </header>
          <div class="pdd-fee-widget__body" data-role="body"></div>
        </section>
      `;
    }
    if (runtime.root.parentElement !== mountTarget.parentElement || runtime.root.previousElementSibling !== mountTarget) {
      mountTarget.insertAdjacentElement("afterend", runtime.root);
    }
  }

  function observeDashboard() {
    const panel = document.querySelector(".manage-data-chart");
    if (!panel || runtime.observedNode === panel) return;
    disconnectObserver();
    runtime.observedNode = panel;
    runtime.observer = new MutationObserver((mutations) => {
      if (runtime.root) {
        const isOwn = mutations.every(m => runtime.root.contains(m.target));
        if (isOwn) return;
      }
      queueRender();
    });
    runtime.observer.observe(panel, { childList: true, subtree: true, characterData: true });
  }

  function disconnectObserver() {
    if (runtime.observer) {
      runtime.observer.disconnect();
      runtime.observer = null;
      runtime.observedNode = null;
    }
  }

  function queueRender() {
    if (runtime.renderQueued) return;
    runtime.renderQueued = true;
    window.requestAnimationFrame(() => {
      runtime.renderQueued = false;
      render();
    });
  }

  function removeWidget() {
    if (runtime.root) {
      runtime.root.remove();
      runtime.root = null;
    }
    runtime.mountTarget = null;
    if (runtime.syncTimer) {
      window.clearInterval(runtime.syncTimer);
      runtime.syncTimer = null;
    }
  }

  function render() {
    if (!runtime.root) return;

    const metrics = readDashboardMetrics();
    const forecast = metrics.ready ? estimateTodayOrderForecast(metrics) : null;
    const chartSeries = buildChartSeries(metrics);

    const stateObject = {
      ready: metrics.ready,
      updatedAt: metrics.updatedAt,
      todayAmount: metrics.todayAmount,
      yesterdayAmount: metrics.yesterdayAmount,
      todayOrders: metrics.todayOrders,
      yesterdayOrders: metrics.yesterdayOrders,
      todaySpend: metrics.todaySpend,
      yesterdaySpend: metrics.yesterdaySpend,
      refundRate: runtime.refundData?.rate,
      forecastOrders: forecast?.predictedOrders,
      forecastAmount: forecast?.predictedAmount,
      chartSignature: chartSeries.map((item) => `${item.date}:${item.amount}:${item.spend}`).join("|")
    };

    const stateHash = JSON.stringify(stateObject);
    if (runtime.lastStateHash === stateHash) {
      return;
    }
    runtime.lastStateHash = stateHash;

    const body = runtime.root.querySelector('[data-role="body"]');
    const subtitle = runtime.root.querySelector('[data-role="subtitle"]');

    subtitle.textContent = metrics.updatedAt ? `更新 ${metrics.updatedAt}` : "等待首页数据";

    if (!metrics.ready) {
      body.innerHTML = `
        <div class="pdd-fee-widget__empty">
          <div class="pdd-fee-widget__empty-title">首页实时数据还没准备好</div>
          <div class="pdd-fee-widget__empty-text">页面加载完成后会自动补齐费比、单笔成交花费和历史曲线。</div>
          <div class="pdd-fee-widget__chart-shell">${renderChart(chartSeries)}</div>
        </div>
      `;
      bindChartInteractions(body, chartSeries);
      return;
    }

    const todayFeeRatio = safeDivide(metrics.todaySpend, metrics.todayAmount);
    const yesterdayFeeRatio = safeDivide(metrics.yesterdaySpend, metrics.yesterdayAmount);
    const todayCostPerOrder = safeDivide(metrics.todaySpend, metrics.todayOrders);
    const yesterdayCostPerOrder = safeDivide(metrics.yesterdaySpend, metrics.yesterdayOrders);

    const feeTrend = getTrend(todayFeeRatio, yesterdayFeeRatio, "ratio");
    const orderTrend = getTrend(todayCostPerOrder, yesterdayCostPerOrder, "currency");
    const forecastTrend = getTrend(forecast.predictedOrders, metrics.yesterdayOrders, "count");

    const refundRateDisplay = runtime.refundData ? formatPercent(runtime.refundData.rate) : "获取中...";

    body.innerHTML = `
      <div class="pdd-fee-widget__metrics">
        ${renderMetricCard({
          title: "实时费比",
          value: formatPercent(todayFeeRatio),
          secondary: `昨日 ${formatPercent(yesterdayFeeRatio)}`,
          trend: feeTrend
        })}
        ${renderMetricCard({
          title: "每笔成交花费",
          value: formatCurrency(todayCostPerOrder),
          secondary: `昨日 ${formatCurrency(yesterdayCostPerOrder)}`,
          trend: orderTrend
        })}
        ${renderMetricCard({
          title: "预测今日总单量",
          value: formatCount(forecast.predictedOrders),
          secondary: `昨日总单量 ${formatCount(metrics.yesterdayOrders)}`,
          trend: forecastTrend,
          caption: forecast.referenceText
        })}
        ${renderMetricCard({
          title: "近30日月退款率",
          value: refundRateDisplay
        })}
      </div>
      <section class="pdd-fee-widget__panel pdd-fee-widget__panel--chart">
        <div class="pdd-fee-widget__panel-head">
          <div>
            <div class="pdd-fee-widget__panel-title">每日费比</div>
            <div class="pdd-fee-widget__panel-subtitle">近期的费比走势</div>
          </div>
        </div>
        <div class="pdd-fee-widget__chart-shell">${renderChart(chartSeries)}</div>
      </section>
    `;

    bindChartInteractions(body, chartSeries);
  }

  function renderMetricCard(model) {
    const trendClass = !model.trend ? "" : model.trend.direction === "up" ? "is-up" : model.trend.direction === "down" ? "is-down" : "is-flat";
    const trendText = !model.trend ? "" : model.trend.direction === "flat" ? "持平" : `${model.trend.direction === "up" ? "上涨" : "下跌"} ${model.trend.label}`;
    return `
      <article class="pdd-fee-widget__metric-card${model.wide ? " is-wide" : ""}">
        <div class="pdd-fee-widget__metric-label">${model.title}</div>
        <div class="pdd-fee-widget__metric-value">${model.value}</div>
        ${model.secondary ? `<div class="pdd-fee-widget__metric-secondary">${model.secondary}</div>` : ""}
        ${model.trend ? `
        <div class="pdd-fee-widget__metric-trend ${trendClass}">
          <span class="pdd-fee-widget__metric-trend-dot"></span>
          <span>${trendText}</span>
        </div>` : ""}
        ${model.caption ? `<div class="pdd-fee-widget__metric-caption">${model.caption}</div>` : ""}
      </article>
    `;
  }

  function renderChart(series) {
    const geometry = getChartGeometry(series);
    if (!geometry) return `<div class="pdd-fee-widget__chart-empty"><span>暂无历史费比</span></div>`;
    const { width, height, padding, points, linePath, areaPath, ticks, xLabels } = geometry;
    return `
      <div class="pdd-fee-widget__chart-wrap">
        <svg viewBox="0 0 ${width} ${height}" class="pdd-fee-widget__chart" role="img" aria-label="每日费比曲线">
          <defs>
            <linearGradient id="pdd-fee-area-gradient" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stop-color="#ff845f" stop-opacity="0.08"></stop>
              <stop offset="55%" stop-color="#75b4ff" stop-opacity="0.03"></stop>
              <stop offset="100%" stop-color="#10b7a4" stop-opacity="0"></stop>
            </linearGradient>
            <linearGradient id="pdd-fee-line-gradient" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0%" stop-color="#ff835f"></stop>
              <stop offset="55%" stop-color="#ff7359"></stop>
              <stop offset="100%" stop-color="#ff6968"></stop>
            </linearGradient>
            <filter id="pdd-fee-line-glow" x="-20%" y="-20%" width="140%" height="140%">
              <feGaussianBlur stdDeviation="1.1" result="blur"></feGaussianBlur>
              <feColorMatrix in="blur" type="matrix" values="1 0 0 0 0  0 1 0 0 0.46  0 0 1 0 0.33  0 0 0 0.1 0"></feColorMatrix>
            </filter>
          </defs>
          ${ticks.map(tick => {
            const y = padding.top + ((geometry.ceiling - tick) / (geometry.ceiling - geometry.floor)) * geometry.innerHeight;
            return `
              <line x1="${padding.left}" y1="${y}" x2="${width - padding.right}" y2="${y}" class="pdd-fee-widget__grid-line"></line>
              <text x="${padding.left - 10}" y="${y + 4}" class="pdd-fee-widget__axis-label pdd-fee-widget__axis-label--left">${tick.toFixed(1)}%</text>
            `;
          }).join("")}
          <path d="${linePath}" class="pdd-fee-widget__line-glow"></path>
          <path d="${areaPath}" class="pdd-fee-widget__area"></path>
          <path d="${linePath}" class="pdd-fee-widget__line"></path>
          ${points.map((point, index) => {
            const active = index === points.length - 1;
            return active
              ? `
                <circle cx="${point.x}" cy="${point.y}" r="6.2" class="pdd-fee-widget__dot-halo"></circle>
                <circle cx="${point.x}" cy="${point.y}" r="3.2" class="pdd-fee-widget__dot is-active"></circle>
              `
              : "";
          }).join("")}
          ${xLabels.map(({ item, index }) => {
            const point = points[index];
            const edgeClass = index === 0 ? " is-first" : index === points.length - 1 ? " is-last" : "";
            return `<text x="${point.x}" y="${height - 10}" class="pdd-fee-widget__axis-label pdd-fee-widget__axis-label--bottom${edgeClass}">${formatMonthDay(item.date)}</text>`;
          }).join("")}
        </svg>
        <div class="pdd-fee-widget__chart-hoverline" hidden></div>
        <div class="pdd-fee-widget__chart-hoverdot" hidden></div>
        <div class="pdd-fee-widget__chart-tooltip" hidden></div>
      </div>
    `;
  }

  function getChartGeometry(series) {
    if (!series.length) return null;
    const width = 1200;
    const height = 118;
    const padding = { top: 10, right: 18, bottom: 22, left: 54 };
    const values = series.map(item => item.ratio * 100);
    let min = Math.min(...values); let max = Math.max(...values);
    if (!Number.isFinite(min) || !Number.isFinite(max)) { min = 0; max = 1; }
    if (min === max) { min -= 1; max += 1; }
    const spread = max - min;
    const floor = Math.max(0, min - Math.max(0.8, spread * 0.18));
    const ceiling = max + Math.max(0.8, spread * 0.18);
    const innerWidth = width - padding.left - padding.right;
    const innerHeight = height - padding.top - padding.bottom;
    const points = series.map((item, index) => {
      const x = padding.left + (series.length === 1 ? innerWidth / 2 : (innerWidth * index) / (series.length - 1));
      const y = padding.top + ((ceiling - item.ratio * 100) / (ceiling - floor)) * innerHeight;
      return { x, y, date: item.date, ratio: item.ratio };
    });
    const linePath = createSmoothPath(points);
    const areaPath = `${linePath} L ${points[points.length - 1].x} ${height - padding.bottom} L ${points[0].x} ${height - padding.bottom} Z`;
    const ticks = buildTicks(floor, ceiling, 4);
    const xLabels = buildXAxisLabels(series, points, innerWidth);
    return { width, height, padding, points, values, floor, ceiling, innerHeight, linePath, areaPath, ticks, xLabels };
  }

  function buildXAxisLabels(series, points, innerWidth) {
    if (!series.length) return [];
    const labelStep = Math.max(1, Math.floor(series.length / 4));
    const candidates = series
      .map((item, index) => ({ item, index, x: points[index]?.x || 0 }))
      .filter(({ index }) => index === 0 || index === series.length - 1 || index % labelStep === 0);
    const minSpacing = Math.max(34, innerWidth / 5.6);
    const selected = [];

    candidates.forEach((candidate) => {
      const last = selected[selected.length - 1];
      if (!last) {
        selected.push(candidate);
        return;
      }
      if (candidate.index === series.length - 1) {
        if (candidate.x - last.x < minSpacing) {
          selected[selected.length - 1] = candidate;
        } else {
          selected.push(candidate);
        }
        return;
      }
      if (candidate.x - last.x >= minSpacing) {
        selected.push(candidate);
      }
    });

    if (selected[0]?.index !== 0) {
      selected.unshift({ item: series[0], index: 0, x: points[0]?.x || 0 });
    }
    if (selected[selected.length - 1]?.index !== series.length - 1) {
      selected.push({
        item: series[series.length - 1],
        index: series.length - 1,
        x: points[series.length - 1]?.x || 0
      });
    }

    return selected;
  }

  function bindChartInteractions(container, series) {
    const wrappers = Array.from(container.querySelectorAll(".pdd-fee-widget__chart-wrap"));
    const geometry = getChartGeometry(series);
    if (!wrappers.length || !geometry) return;

    wrappers.forEach(wrapper => {
      const hoverLine = wrapper.querySelector(".pdd-fee-widget__chart-hoverline");
      const hoverDot = wrapper.querySelector(".pdd-fee-widget__chart-hoverdot");
      const tooltip = wrapper.querySelector(".pdd-fee-widget__chart-tooltip");
      const move = (event) => {
        const rect = wrapper.getBoundingClientRect();
        if (rect.width === 0) return;
        const scaleX = rect.width / geometry.width;
        const scaleY = rect.height / geometry.height;
        const localX = event.clientX - rect.left;
        let nearest = geometry.points[0]; let nearestDistance = Number.POSITIVE_INFINITY;
        geometry.points.forEach(point => {
          const distance = Math.abs(localX - point.x * scaleX);
          if (distance < nearestDistance) { nearest = point; nearestDistance = distance; }
        });
        const pointX = nearest.x * scaleX;
        const pointY = nearest.y * scaleY;
        hoverLine.hidden = false; hoverDot.hidden = false; tooltip.hidden = false;
        hoverLine.style.left = `${pointX}px`;
        hoverLine.style.top = `${geometry.padding.top * scaleY}px`;
        hoverLine.style.height = `${(geometry.height - geometry.padding.top - geometry.padding.bottom) * scaleY}px`;
        hoverDot.style.left = `${pointX}px`;
        hoverDot.style.top = `${pointY}px`;
        tooltip.textContent = `${formatMonthDay(nearest.date)} 费比 ${formatPercent(nearest.ratio)}`;
        const tooltipWidth = tooltip.offsetWidth || 96;
        const tooltipHeight = tooltip.offsetHeight || 32;
        const tooltipLeft = clamp(pointX - tooltipWidth / 2, 8, rect.width - tooltipWidth - 8);
        const tooltipTop = pointY - tooltipHeight - 12 < 8 ? pointY + 12 : pointY - tooltipHeight - 12;
        tooltip.style.left = `${tooltipLeft}px`;
        tooltip.style.top = `${tooltipTop}px`;
      };
      const leave = () => { hoverLine.hidden = true; hoverDot.hidden = true; tooltip.hidden = true; };
      wrapper.addEventListener("pointermove", move);
      wrapper.addEventListener("pointerleave", leave);
    });
  }

  function buildTicks(min, max, count) {
    if (count <= 1) return [min];
    const step = (max - min) / (count - 1);
    return Array.from({ length: count }, (_, index) => min + step * index);
  }

  function createSmoothPath(points) {
    if (!points.length) return "";
    if (points.length === 1) return `M ${points[0].x} ${points[0].y}`;
    const smoothing = 0.18;
    function line(pointA, pointB) {
      const lengthX = pointB.x - pointA.x; const lengthY = pointB.y - pointA.y;
      return { length: Math.sqrt(lengthX * lengthX + lengthY * lengthY), angle: Math.atan2(lengthY, lengthX) };
    }
    function controlPoint(current, previous, next, reverse) {
      const previousPoint = previous || current; const nextPoint = next || current;
      const lineModel = line(previousPoint, nextPoint);
      const angle = lineModel.angle + (reverse ? Math.PI : 0);
      const length = lineModel.length * smoothing;
      return { x: current.x + Math.cos(angle) * length, y: current.y + Math.sin(angle) * length };
    }
    return points.reduce((path, point, index, list) => {
      if (index === 0) return `M ${point.x} ${point.y}`;
      const cps = controlPoint(list[index - 1], list[index - 2], point, false);
      const cpe = controlPoint(point, list[index - 1], list[index + 1], true);
      return `${path} C ${cps.x} ${cps.y} ${cpe.x} ${cpe.y} ${point.x} ${point.y}`;
    }, "");
  }

  function getTrend(current, previous, mode) {
    if (!Number.isFinite(current) || !Number.isFinite(previous)) return { direction: "flat", label: "0.00" };
    const delta = current - previous;
    if (Math.abs(delta) < 0.0001) return { direction: "flat", label: mode === "ratio" ? "0.00 个点" : mode === "count" ? "0 单" : "0.00 元" };
    return {
      direction: delta > 0 ? "up" : "down",
      label: mode === "ratio" ? `${Math.abs(delta * 100).toFixed(2)} 个点` : mode === "count" ? `${Math.round(Math.abs(delta)).toLocaleString("zh-CN")} 单` : `${Math.abs(delta).toFixed(2)} 元`
    };
  }

  function estimateTodayOrderForecast(metrics) {
    const chartContext = readTrendChartContext(metrics);
    const timeShare = estimateTimeShare(metrics.updatedAt);
    
    let progressShare;
    let predictedAmount = 0;
    let referenceText = "";

    if (chartContext && Number.isFinite(chartContext.svgPredictedAmount)) {
      const svgAmount = chartContext.svgPredictedAmount;
      const timeAmount = safeDivide(metrics.todayAmount, clamp(timeShare, 0.08, 0.97));
      const diffRatio = Math.abs(svgAmount - timeAmount) / timeAmount;
      
      if (diffRatio > 0.25) {
        predictedAmount = svgAmount * 0.40 + timeAmount * 0.60;
        referenceText = `图表延迟偏离,按动态防抖估算`;
      } else {
        predictedAmount = svgAmount * 0.78 + timeAmount * 0.22;
        referenceText = chartContext.referenceText || `按当前与昨日同节点真实曲线比例估算`;
      }
      progressShare = clamp(safeDivide(metrics.todayAmount, predictedAmount), 0.08, 0.97);
    } else {
      progressShare = clamp(timeShare, 0.08, 0.97);
      predictedAmount = safeDivide(metrics.todayAmount, progressShare);
      referenceText = `按 ${extractTimeLabel(metrics.updatedAt) || "当前"} 时段进度估算`;
    }

    const todayAov = safeDivide(metrics.todayAmount, metrics.todayOrders);
    const yesterdayAov = safeDivide(metrics.yesterdayAmount, metrics.yesterdayOrders);
    
    const aovWeight = clamp(0.35 + progressShare * 0.55, 0.35, 0.9);
    const estimatedAov = blendNumbers(todayAov, yesterdayAov, aovWeight);
    
    let predictedOrders = safeDivide(predictedAmount, estimatedAov);
    
    if (!Number.isFinite(predictedOrders)) {
      predictedOrders = safeDivide(predictedAmount, yesterdayAov);
    }
    if (Number.isFinite(predictedOrders)) {
      predictedOrders = Math.max(predictedOrders, metrics.todayOrders);
    }

    return { predictedOrders, predictedAmount, referenceText };
  }

  function readTrendChartContext(metrics) {
    const selectedMetric = document.querySelector('.manage-data-chart__main__header input[data-testid="beast-core-select-htmlInput"]')?.value?.trim() || "";
    const activeRange = Array.from(document.querySelectorAll(".manage-data_rangeRadio__21m6d [data-testid='beast-core-radio']")).find(node => node.getAttribute("data-checked") === "true")?.textContent?.trim();
    const activeGraph = Array.from(document.querySelectorAll(".manage-data_graphTypeRadio__y641o [data-testid='beast-core-radio']")).find(node => node.getAttribute("data-checked") === "true")?.textContent?.trim();
    if ((selectedMetric && !selectedMetric.includes("成交金额")) || (activeRange && !activeRange.includes("实时")) || (activeGraph && !activeGraph.includes("累计趋势图"))) return null;
    
    const svg = document.querySelector(".manage-data-chart_container svg");
    if (!svg) return null;
    
    const todayPath = getTrendCurvePath(svg, TODAY_CURVE_COLOR);
    const yesterdayPath = getTrendCurvePath(svg, YESTERDAY_CURVE_COLOR);
    const axis = readTrendAxis(svg);
    if (!todayPath || !yesterdayPath || !axis) return null;
    
    const totalLength = todayPath.getTotalLength();
    if (!Number.isFinite(totalLength) || totalLength <= 0) return null;
    
    const todayEnd = todayPath.getPointAtLength(totalLength);
    const yesterdayPoint = samplePathPointAtX(yesterdayPath, todayEnd.x);
    if (!yesterdayPoint) return null;
    
    const sameTimeTodayAmount = axis.yToValue(todayEnd.y);
    const sameTimeYesterdayAmount = axis.yToValue(yesterdayPoint.y);
    
    if (!Number.isFinite(sameTimeTodayAmount) || !Number.isFinite(sameTimeYesterdayAmount) || sameTimeYesterdayAmount <= 0) return null;
    
    const ratio = sameTimeTodayAmount / sameTimeYesterdayAmount;
    const svgPredictedAmount = metrics.yesterdayAmount * ratio;
    
    return { svgPredictedAmount, referenceText: `按图表同节点真实比例估算` };
  }

  function getTrendCurvePath(svg, targetColor) {
    const paths = Array.from(svg.querySelectorAll("path[stroke]")).filter(path => {
      const strokeWidth = parseFloat(path.getAttribute("stroke-width") || "0");
      return path.getAttribute("fill") === "none" && strokeWidth >= 2;
    });
    return paths.find(path => normalizeColor(path.getAttribute("stroke")) === targetColor) || null;
  }

  function readTrendAxis(svg) {
    const texts = Array.from(svg.querySelectorAll("text"));
    const startX = parseFloat(texts.find(node => node.textContent?.trim() === "00:00")?.getAttribute("x") || "");
    const endX = parseFloat(texts.find(node => node.textContent?.trim() === "24:00")?.getAttribute("x") || "");
    if (!Number.isFinite(startX) || !Number.isFinite(endX) || endX <= startX) return null;
    const yLabels = texts.map(node => {
      const valueText = node.textContent?.trim() || "";
      const x = parseFloat(node.getAttribute("x") || "");
      const y = parseFloat(node.getAttribute("y") || "");
      if (!/^\d+(?:\.\d+)?$/.test(valueText) || !Number.isFinite(x) || !Number.isFinite(y) || x >= startX) return null;
      return { value: Number(valueText), y };
    }).filter(Boolean).sort((left, right) => left.y - right.y);
    if (yLabels.length < 2) return null;
    const top = yLabels[0]; const bottom = yLabels[yLabels.length - 1];
    const slope = (bottom.value - top.value) / (bottom.y - top.y);
    if (!Number.isFinite(slope)) return null;
    return { startX, endX, yToValue(y) { return top.value + (y - top.y) * slope; } };
  }

  function samplePathPointAtX(path, targetX) {
    const total = path.getTotalLength();
    if (!Number.isFinite(total) || total <= 0) return null;
    const samples = 360; let previous = path.getPointAtLength(0);
    let nearest = previous; let nearestDistance = Math.abs(previous.x - targetX);
    for (let index = 1; index <= samples; index += 1) {
      const point = path.getPointAtLength((total * index) / samples);
      const distance = Math.abs(point.x - targetX);
      if (distance < nearestDistance) { nearest = point; nearestDistance = distance; }
      const between = (previous.x <= targetX && targetX <= point.x) || (previous.x >= targetX && targetX >= point.x);
      if (between) {
        const span = point.x - previous.x;
        const ratio = span === 0 ? 0 : (targetX - previous.x) / span;
        return { x: targetX, y: previous.y + (point.y - previous.y) * ratio };
      }
      previous = point;
    }
    return nearest;
  }

  function normalizeColor(color) {
    const compact = (color || "").replace(/\s+/g, "").toLowerCase();
    if (compact === "#407cff" || compact === "rgb(64,124,255)") return TODAY_CURVE_COLOR;
    if (compact === "#ffc340" || compact === "rgb(255,195,64)") return YESTERDAY_CURVE_COLOR;
    return compact;
  }

  function estimateTimeShare(updatedAt) {
    const timeText = extractTimeLabel(updatedAt);
    if (!timeText) return 0.5;
    const [hours, minutes] = timeText.split(":").map(Number);
    if (!Number.isFinite(hours) || !Number.isFinite(minutes)) return 0.5;
    return clamp((hours * 60 + minutes) / 1440, 0.05, 0.97);
  }

  function extractTimeLabel(text) {
    const match = (text || "").match(/(\d{2}:\d{2})/);
    return match ? match[1] : "";
  }

  function blendNumbers(primary, secondary, primaryWeight) {
    if (Number.isFinite(primary) && Number.isFinite(secondary)) return primary * primaryWeight + secondary * (1 - primaryWeight);
    if (Number.isFinite(primary)) return primary;
    if (Number.isFinite(secondary)) return secondary;
    return NaN;
  }

  function clamp(value, min, max) { return Math.min(Math.max(value, min), max); }

  function readDashboardMetrics() {
    const cards = Array.from(document.querySelectorAll(".manage-data-chart__panel__card"));
    const lookup = cards.reduce((result, card) => {
      const label = card.querySelector(".manage-data-chart__panel__card_has-tips")?.textContent?.trim();
      if (label) result[label] = card;
      return result;
    }, {});
    const amount = extractCardValues(lookup["成交金额"]);
    const orders = extractCardValues(lookup["成交订单数"]);
    const spend = extractCardValues(lookup["推广花费"]);
    const updatedAt = document.querySelector(".ManageHeader_time__1faa7")?.textContent?.replace("更新时间:", "").trim() || "";
    return {
      ready: [amount.current, amount.previous, orders.current, orders.previous, spend.current, spend.previous].every(value => Number.isFinite(value) && value >= 0),
      updatedAt,
      todayAmount: amount.current,
      yesterdayAmount: amount.previous,
      todayOrders: orders.current,
      yesterdayOrders: orders.previous,
      todaySpend: spend.current,
      yesterdaySpend: spend.previous
    };
  }

  function extractCardValues(card) {
    if (!card) return { current: NaN, previous: NaN };
    const currentText = [
      card.querySelector(".manage-data-chart__panel__card__content_val")?.textContent || "",
      card.querySelector(".manage-data-chart__panel__card__content_unit")?.textContent || ""
    ].join("").trim();
    const previousText = card.querySelector(".manage-data-chart__panel__card__yesterday-value")?.textContent || "";
    return { current: parseNumberWithUnit(currentText), previous: parseNumberWithUnit(previousText) };
  }

  function parseNumberWithUnit(text) {
    if (!text) return NaN;
    const compact = text.replace(/\s+/g, "").replace(/,/g, "");
    const match = compact.match(/(-?\d+(?:\.\d+)?)(万|亿)?/);
    if (!match) return NaN;
    const value = Number(match[1]);
    if (!Number.isFinite(value)) return NaN;
    const unit = match[2];
    if (unit === "亿") return value * 100000000;
    if (unit === "万") return value * 10000;
    return value;
  }

  // --- 核心改动：合并历史数据并区分店铺 ---
  function buildChartSeries(metrics) {
    const storeName = resolveStoreName();
    const map = new Map();
    const storeData = storeName ? getStoreCache(storeName) : null;

    // 1. 优先合并接口缓存的交易额与直通车花费
    if (storeData?.tradeHistory?.length && storeData?.spendHistory?.length) {
      const tradeMap = new Map(storeData.tradeHistory.map((item) => [item.date, item.amount]));
      storeData.spendHistory.forEach((item) => {
        const amount = tradeMap.get(item.date);
        const ratio = safeDivide(item.spend, amount);
        if (Number.isFinite(ratio)) {
          map.set(item.date, { date: item.date, ratio, amount, spend: item.spend });
        }
      });
    }

    // 2. 回退到旧版本地累计数据，避免已存历史丢失
    if (storeName && runtime.storedHistory[storeName]) {
      runtime.storedHistory[storeName].forEach(entry => {
        if (map.has(entry.date)) return;
        const ratio = safeDivide(entry.spend, entry.amount);
        if (Number.isFinite(ratio)) {
          map.set(entry.date, { date: entry.date, ratio, amount: entry.amount, spend: entry.spend });
        }
      });
    }

    // 3. 读取当前页面的昨日和今日最新数据
    const baseDate = parseDashboardDate(metrics.updatedAt) || new Date();
    const todayDate = toDateKey(baseDate);
    const yesterday = new Date(baseDate.getTime());
    yesterday.setDate(yesterday.getDate() - 1);
    const yesterdayDate = toDateKey(yesterday);

    const yesterdayRatio = safeDivide(metrics.yesterdaySpend, metrics.yesterdayAmount);
    if (Number.isFinite(yesterdayRatio)) {
      map.set(yesterdayDate, { date: yesterdayDate, ratio: yesterdayRatio, amount: metrics.yesterdayAmount, spend: metrics.yesterdaySpend });
    }

    const todayRatio = safeDivide(metrics.todaySpend, metrics.todayAmount);
    if (Number.isFinite(todayRatio)) {
      map.set(todayDate, { date: todayDate, ratio: todayRatio, amount: metrics.todayAmount, spend: metrics.todaySpend });
    }

    // 4. 将合并后的全量数据保存回旧版数组缓存，兼容已有数据结构
    if (storeName && metrics.ready) {
      saveHistoryToStorage(storeName, map);
    }

    return Array.from(map.values()).sort((left, right) => left.date.localeCompare(right.date));
  }

  // --- 新增：持久化存储到 Chrome 本地 ---
  function saveHistoryToStorage(storeName, map) {
    if (!storeName || typeof chrome === "undefined" || !chrome.storage || !chrome.storage.local) return;

    // 提取成极简数组，避免存入无用数据
    const historyArray = Array.from(map.values()).map(item => ({
      date: item.date,
      amount: item.amount,
      spend: item.spend
    }));

    const newHash = JSON.stringify(historyArray);
    if (runtime.lastSavedHistoryHash === newHash) return; // 性能优化：无变动不频繁写入硬盘
    runtime.lastSavedHistoryHash = newHash;

    runtime.storedHistory[storeName] = historyArray;
    chrome.storage.local.set({ [STORAGE_KEYS.legacyHistory]: runtime.storedHistory });
  }

  function parseDashboardDate(text) {
    const match = text.match(/(\d{4})-(\d{2})-(\d{2})/);
    return match ? new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3])) : null;
  }

  function toDateKey(date) {
    const year = date.getFullYear();
    const month = `${date.getMonth() + 1}`.padStart(2, "0");
    const day = `${date.getDate()}`.padStart(2, "0");
    return `${year}-${month}-${day}`;
  }

  function formatMonthDay(dateKey) {
    const match = dateKey.match(/\d{4}-(\d{2})-(\d{2})/);
    return match ? `${Number(match[1])}-${Number(match[2])}` : "--";
  }

  function safeDivide(dividend, divisor) {
    return (!Number.isFinite(dividend) || !Number.isFinite(divisor) || divisor === 0) ? NaN : dividend / divisor;
  }

  function formatPercent(value) { return Number.isFinite(value) ? `${(value * 100).toFixed(2)}%` : "--"; }
  function formatCurrency(value) { return Number.isFinite(value) ? `¥${value.toFixed(2)}` : "--"; }
  function formatCount(value) { return Number.isFinite(value) ? `${Math.round(value).toLocaleString("zh-CN")} 单` : "--"; }
  function formatAmount(value) { return Number.isFinite(value) ? value.toLocaleString("zh-CN", { maximumFractionDigits: 2 }) : "--"; }
  function formatInteger(value) { return Number.isFinite(value) ? Math.round(value).toLocaleString("zh-CN") : "--"; }

  // --- 改动：在初始化时预先从 Chrome 本地加载历史数据 ---
  async function loadState() {
    return new Promise((resolve) => {
      if (typeof chrome !== "undefined" && chrome.storage && chrome.storage.local) {
        chrome.storage.local.get([STORAGE_KEYS.legacyHistory, STORAGE_KEYS.storeCache, STORAGE_KEYS.lastStore], (result) => {
          runtime.storedHistory = result[STORAGE_KEYS.legacyHistory] || {};
          runtime.storeCache = result[STORAGE_KEYS.storeCache] || {};
          runtime.lastKnownStoreName = result[STORAGE_KEYS.lastStore] || "";
          resolve();
        });
      } else {
        runtime.storedHistory = {};
        runtime.storeCache = {};
        runtime.lastKnownStoreName = "";
        resolve();
      }
    });
  }

  function installPageBridge() {
    if (!document.documentElement || document.getElementById(PAGE_HOOK_ID) || typeof chrome === "undefined" || !chrome.runtime?.getURL) return;
    const script = document.createElement("script");
    script.id = PAGE_HOOK_ID;
    script.src = chrome.runtime.getURL("modules/fee-dashboard/page-hook.js");
    script.async = false;
    script.onload = () => script.remove();
    (document.head || document.documentElement).appendChild(script);
  }

  function bindPageMessages() {
    if (runtime.pageMessageBound) return;
    runtime.pageMessageBound = true;

    window.addEventListener("message", (event) => {
      if (event.source !== window) return;
      const payload = event.data;
      if (!payload || payload.source !== PAGE_HOOK_SOURCE || payload.type !== "network") return;

      const requestUrl = String(payload.url || "");
      const storeName = resolveStoreName(payload.storeName);

      if (requestUrl.includes(TRADE_API_PATH)) {
        const dayList = payload.response?.result?.dayList || [];
        saveTradeHistory(storeName, dayList);
        return;
      }

      if (requestUrl.includes(SPEND_API_PATH)) {
        const dailyReportList = payload.response?.result?.dailyReportList || [];
        saveSpendHistory(storeName, dailyReportList, {
          url: requestUrl,
          method: payload.method || "POST",
          body: payload.requestBody || "",
          headers: payload.headers || {}
        });
      }
    });
  }

  function bindStorageListener() {
    if (runtime.storageListenerBound) return;
    if (typeof chrome === "undefined" || !chrome.storage || !chrome.storage.onChanged) return;
    runtime.storageListenerBound = true;

    chrome.storage.onChanged.addListener((changes, areaName) => {
      if (areaName !== "local") return;
      if (changes[STORAGE_KEYS.legacyHistory]) {
        runtime.storedHistory = changes[STORAGE_KEYS.legacyHistory].newValue || {};
        runtime.lastSavedHistoryHash = "";
        queueRender();
      }
      if (changes[STORAGE_KEYS.storeCache]) {
        runtime.storeCache = changes[STORAGE_KEYS.storeCache].newValue || {};
        queueRender();
      }
      if (changes[STORAGE_KEYS.lastStore]) {
        runtime.lastKnownStoreName = changes[STORAGE_KEYS.lastStore].newValue || "";
      }
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", boot, { once: true });
  } else {
    boot();
  }
})();
