// SocialRequirements 的 P2 留存是“基准日全体活跃用户 -> D+N 仍活跃”的 canonical cohort。
// 这里仅负责把动态 metrics 行整理成留存质量页可消费的 App 合计/日行，并按分子分母安全聚合。

import { isBlank } from "./format.js";

export const ACTIVE_RETENTION_WINDOWS = [
  {
    baseKey: "active_d1_active_base_users",
    key: "active_d1_active_rate",
    label: "次日留存",
    shortLabel: "D1",
    usersKey: "active_d1_active_users"
  },
  {
    baseKey: "active_d7_active_base_users",
    key: "active_d7_active_rate",
    label: "7日留存",
    shortLabel: "D7",
    usersKey: "active_d7_active_users"
  },
  {
    baseKey: "active_d30_active_base_users",
    key: "active_d30_active_rate",
    label: "30日留存",
    shortLabel: "D30",
    usersKey: "active_d30_active_users"
  }
];

function asArray(value) {
  return Array.isArray(value) ? value : [];
}

function sectionKey(section) {
  return String(section?.key ?? section?.section ?? section?.code ?? "").trim().toLowerCase();
}

function flattenMetricRow(row, context) {
  if (!row || typeof row !== "object") {
    return null;
  }
  const metrics = row.metrics && typeof row.metrics === "object" && !Array.isArray(row.metrics) ? row.metrics : {};
  const flattened = { ...context, ...row, ...metrics };
  delete flattened.metrics;
  return flattened;
}

// requirements 可能同时返回多个 App；每个 App 的 retention section 已按顶栏区域筛选裁剪。
// 不借用 Overview 的注册 cohort 或区域行，避免“整体次留”再次混入另一套口径。
export function normalizeActiveRetentionRequirements(payload) {
  const appErrors = [];
  const appTotals = [];
  const appDaily = [];

  asArray(payload?.apps).forEach((app) => {
    if (app?.error) {
      appErrors.push(`${app.app_name || app.app_code || "未知 App"}: ${app.error}`);
    }
    const section = asArray(app?.sections).find((item) => sectionKey(item) === "retention");
    if (!section) {
      return;
    }
    const context = {
      app_code: app.app_code || app.appCode || "",
      app_name: app.app_name || app.appName || app.app_code || app.appCode || "",
      kind: app.kind || "",
      restricted: Boolean(app.restricted)
    };
    const dailyRows = asArray(section.daily_series || section.dailyRows || section.daily_rows || section.rows || section.items)
      .map((row) => flattenMetricRow(row, context))
      .filter(Boolean)
      .map((row) => ({ ...row, stat_day: row.stat_day || row.label || "" }));
    appDaily.push(...dailyRows);

    const total = flattenMetricRow(section.total || section.totals || section.summary, context);
    if (total) {
      appTotals.push(total);
    } else if (dailyRows.length) {
      appTotals.push({ ...context, ...aggregateActiveRetentionRows(dailyRows) });
    }
  });

  return { appDaily, appErrors, appTotals };
}

function numericValue(row, key) {
  const value = row?.[key];
  if (isBlank(value)) {
    return null;
  }
  const numeric = Number(value);
  return Number.isFinite(numeric) ? numeric : null;
}

// 空值表示观察窗尚未成熟或数据未接入，必须保持 null；只有明确的数值 0 才参与求和。
// 比例始终用汇总后的留存人数 / 基数重算，不能平均各 App、各日百分比。
export function aggregateActiveRetentionRows(rows) {
  const out = {};
  ACTIVE_RETENTION_WINDOWS.forEach(({ baseKey, key, usersKey }) => {
    let base = null;
    let users = null;
    rows.forEach((row) => {
      const rowBase = numericValue(row, baseKey);
      const rowUsers = numericValue(row, usersKey);
      if (rowBase !== null) {
        base = (base ?? 0) + rowBase;
      }
      if (rowUsers !== null) {
        users = (users ?? 0) + rowUsers;
      }
    });
    out[baseKey] = base;
    out[usersKey] = users;
    out[key] = users !== null && base ? users / base : null;
  });
  return out;
}
