import serviceConfig from "../config/service";
import request from "../utils/request";
import { getCurrentWebviewToken } from "../utils/webview-token";

const HOME_TICKER_STORAGE_KEY = "asset_home_ticker_cache";
let runtimeHomeTickerCache = null;

function createError(message, raw) {
  return {
    message: message || "接口请求失败",
    raw: raw,
  };
}

function toNumber(value) {
  const number = Number(value || 0);
  return Number.isFinite(number) ? number : 0;
}

function toFixedNumber(value, digits) {
  return toNumber(value).toFixed(digits);
}

function formatHomeNumber(value, digits) {
  const number = toNumber(value);

  if (digits > 0) {
    const fixed = number.toFixed(digits);
    const parts = fixed.split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return parts.join(".");
  }

  return Math.round(number)
    .toString()
    .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

function isSuccessPayload(payload) {
  if (!payload || typeof payload !== "object") {
    return false;
  }

  const statusCode =
    payload.code !== undefined ? Number(payload.code) : Number(payload.status);

  return statusCode === 200;
}

function unwrapPayload(payload, fallbackMessage) {
  if (isSuccessPayload(payload)) {
    return payload.data;
  }

  if (payload && typeof payload === "object") {
    throw createError(
      payload.msg || payload.message || fallbackMessage || "接口请求失败",
      payload,
    );
  }

  throw createError(fallbackMessage || "接口返回异常", payload);
}

async function fetchPayload(options, fallbackMessage) {
  try {
    const payload = await request(options);
    return unwrapPayload(payload, fallbackMessage);
  } catch (error) {
    if (error && error.message) {
      throw error;
    }

    throw createError(fallbackMessage || "接口请求失败", error);
  }
}

function createRequestOptions(baseOptions, requestOptions) {
  return Object.assign({}, baseOptions, requestOptions || {});
}

function normalizeTicker(data) {
  const close = toNumber(data && (data.close || data.cnyPrice));
  const lastDayClose = toNumber(data && data.lastDayClose);
  const rawChange = data && data.change;
  let change = typeof rawChange === "string" ? rawChange : "";

  if (!change) {
    if (close && lastDayClose) {
      const percent = ((close - lastDayClose) / lastDayClose) * 100;
      const prefix = percent >= 0 ? "+" : "";
      change = prefix + percent.toFixed(2) + "%";
    } else {
      change = "0.00%";
    }
  }
  return {
    symbol: (data && data.symbol) || "BMT/CNY",
    close: close,
    cnyPrice: (data && data.cnyPrice) || (close ? close.toFixed(2) : "0.00"),
    lastDayClose: lastDayClose,
    change: change,
  };
}

function setHomeTickerCache(ticker) {
  const normalizedTicker = normalizeTicker(ticker);
  runtimeHomeTickerCache = normalizedTicker;

  try {
    if (typeof uni !== "undefined" && uni.setStorageSync) {
      uni.setStorageSync(HOME_TICKER_STORAGE_KEY, normalizedTicker);
    }
  } catch (error) {
    // Ignore storage failures and keep runtime cache fallback.
  }

  return normalizedTicker;
}

function getHomeTickerCache() {
  if (runtimeHomeTickerCache) {
    return runtimeHomeTickerCache;
  }

  try {
    if (typeof uni !== "undefined" && uni.getStorageSync) {
      const storedTicker = uni.getStorageSync(HOME_TICKER_STORAGE_KEY);
      if (storedTicker && typeof storedTicker === "object") {
        runtimeHomeTickerCache = normalizeTicker(storedTicker);
      }
    }
  } catch (error) {
    // Ignore storage failures.
  }

  return runtimeHomeTickerCache || normalizeTicker(null);
}

function appendTokenToTargetUrl(targetUrl) {
  const token = String(getCurrentWebviewToken() || "").trim();
  let nextTargetUrl = String(targetUrl || "").trim();

  if (token) {
    nextTargetUrl +=
      (nextTargetUrl.indexOf("?") > -1 ? "&" : "?") +
      "token=" +
      encodeURIComponent(token);
  }

  return {
    token: token,
    targetUrl: nextTargetUrl,
    encodedTargetUrl: encodeURIComponent(nextTargetUrl),
  };
}

function normalizeBalances(data) {
  return {
    points: toNumber(data && data.point),
    power: toNumber(data && data.c_power),
    bmt: toNumber(data && data.bmt_num),
    withdrawableBmt: toNumber(data && data.bmt_num),
    voucher: toNumber(data && data.coin),
    coupon: toNumber(data && data.diamond_balance),
    balance: toNumber(data && data.brokerage_price),
  };
}

function toRawDisplayValue(value) {
  if (value === undefined || value === null || value === "") {
    return "0";
  }

  return String(value);
}

function buildHomeOverview(balanceData, tickerData, userData) {
  const balances = normalizeBalances(balanceData);
  const ticker = normalizeTicker(tickerData);
  const rawQuickAssets = {
    balance: toRawDisplayValue(balanceData && balanceData.brokerage_price),
    points: toRawDisplayValue(balanceData && balanceData.point),
    voucher: toRawDisplayValue(balanceData && balanceData.coin),
    coupon: toRawDisplayValue(balanceData && balanceData.diamond_balance),
    power: toRawDisplayValue(balanceData && balanceData.c_power),
    bmtr: toRawDisplayValue(userData && userData.bmtr),
  };

  return {
    title: "数字资产",
    ticker: ticker,
    topStats: [
      {
        key: "wallet-bmt",
        title: "可提取BMT",
        value: toFixedNumber(balances.withdrawableBmt, 2),
        unit: "BMT",
        accent: "gold",
      },
      {
        key: "ticker",
        title: "BMT实时价格",
        value: toFixedNumber(ticker.close || ticker.cnyPrice, 3),
        unit: "BMT/CNY",
        accent: "green",
      },
    ],
    quickAssets: [
      {
        key: "points",
        title: "可用积分",
        value: rawQuickAssets.points,
        accent: "gold",
      },
      {
        key: "power",
        title: "算力",
        value: rawQuickAssets.power,
        accent: "violet",
      },
      {
        key: "coupon",
        title: "消费券",
        value: rawQuickAssets.coupon,
        accent: "teal",
      },
      {
        key: "voucher",
        title: "抵用券",
        value: rawQuickAssets.voucher,
        accent: "rose",
      },
      {
        key: "balance",
        title: "余额",
        value: rawQuickAssets.balance,
        accent: "blue",
      },
      {
        key: "bmtr",
        title: "BMTR",
        value: rawQuickAssets.bmtr,
        accent: "orange",
      },
    ],
    features: [
      {
        key: "points-convert",
        title: "积分转换",
        desc: "释放中的积分转换为可用积分",
        accent: "pink",
      },
      {
        key: "power-exchange",
        title: "算力兑换",
        desc: "抵用券与消费券兑换算力",
        accent: "amber",
      },
      {
        key: "bmt-flash",
        title: "BMT闪兑",
        desc: "BMT闪兑",
        accent: "indigo",
      },
      {
        key: "transfer",
        title: "转赠中心",
        desc: "积分或算力转赠好友",
        accent: "indigo",
      },
      {
        key: "bmt-exchange",
        title: "BMT兑换",
        desc: "积分与算力兑换 BMT",
        accent: "mint",
      },
      {
        key: "withdraw",
        title: "BMT提取",
        desc: "钱包中的 BMT 可提取到交易所进行交易",
        accent: "pink",
      },
    ],
    notice:
      "数字资产是您在平台上的虚拟资产，请谨慎管理；BMT可在交易所中进行交易。",
  };
}

function buildTransferTips(feePercent, bmtrFeePercent) {
  const percentText = toNumber(feePercent) || 10;
  const bmtrPercentText = toNumber(bmtrFeePercent) || 10;

  return {
    points: [
      "只能转赠1的整数倍",
      "凌晨00:00至02:00为系统维护时段不可赠送",
      "转赠系统会扣除" + percentText + "%的手续费",
    ],
    power: ["只能转赠1的整数倍", "转赠系统会扣除" + percentText + "%的手续费"],
    bmtr: [
      "只能转赠1的整数倍",
      "转赠系统会扣除" + bmtrPercentText + "%的手续费",
    ],
  };
}

function buildWalletList(address) {
  const normalizedAddress = String(address || "").trim();

  if (!normalizedAddress) {
    return [];
  }

  return [
    {
      id: "default-wallet",
      name: serviceConfig.WALLET_NAME,
      address: normalizedAddress,
      isDefault: true,
    },
  ];
}

function buildWalletPayload(address) {
  return {
    wallets: buildWalletList(address),
    instructions: [
      "点击交易所 App 底部“资产”进入钱包页",
      "搜索或输入大写字母 BMT",
      "点击“充币 / 充值”进入收款地址页面",
      "复制钱包地址后回填到当前页面",
    ],
  };
}

function pickFirstValue(source, keys) {
  const target = source && typeof source === "object" ? source : {};

  for (let index = 0; index < keys.length; index += 1) {
    const key = keys[index];
    const value = target[key];

    if (
      value !== undefined &&
      value !== null &&
      !(typeof value === "string" && value.trim() === "")
    ) {
      return value;
    }
  }

  return "";
}

function normalizeListData(data) {
  if (Array.isArray(data)) {
    return data;
  }

  if (data && Array.isArray(data.list)) {
    return data.list;
  }

  return [];
}

const DEFAULT_LIST_PAGE = 1;
const DEFAULT_LIST_PAGE_SIZE = 10;

function hasPaginationKey(value) {
  if (!value || typeof value !== "object") {
    return false;
  }

  return (
    value.page !== undefined ||
    value.pageSize !== undefined ||
    value.page_size !== undefined ||
    value.pagesize !== undefined ||
    value.size !== undefined ||
    value.limit !== undefined
  );
}

function normalizePaginationOptions(pagination) {
  const source = pagination && typeof pagination === "object" ? pagination : {};
  const page = Math.max(
    1,
    Math.floor(
      toNumber(
        pickFirstValue(source, ["page", "current_page", "currentPage", "p"]) ||
          DEFAULT_LIST_PAGE,
      ),
    ),
  );
  const pageSize = Math.max(
    1,
    Math.floor(
      toNumber(
        pickFirstValue(source, [
          "pageSize",
          "page_size",
          "pagesize",
          "size",
          "limit",
          "per_page",
        ]) || DEFAULT_LIST_PAGE_SIZE,
      ),
    ),
  );

  return {
    page: page,
    pageSize: pageSize,
  };
}

function resolvePagingArguments(paginationOrRequestOptions, requestOptions) {
  if (requestOptions || hasPaginationKey(paginationOrRequestOptions)) {
    return {
      pagination: normalizePaginationOptions(paginationOrRequestOptions),
      requestOptions: requestOptions || null,
    };
  }

  return {
    pagination: normalizePaginationOptions(null),
    requestOptions: paginationOrRequestOptions || null,
  };
}

function buildPagingRequestData(baseData, pagination) {
  const normalizedPagination = normalizePaginationOptions(pagination);

  return Object.assign({}, baseData || {}, {
    page: normalizedPagination.page,
    limit: normalizedPagination.pageSize,
  });
}

function parseBooleanLike(value) {
  if (typeof value === "boolean") {
    return value;
  }

  if (typeof value === "number") {
    return value > 0;
  }

  if (typeof value === "string") {
    const normalized = value.trim().toLowerCase();
    if (!normalized) {
      return null;
    }

    if (
      normalized === "1" ||
      normalized === "true" ||
      normalized === "yes" ||
      normalized === "y"
    ) {
      return true;
    }

    if (
      normalized === "0" ||
      normalized === "false" ||
      normalized === "no" ||
      normalized === "n"
    ) {
      return false;
    }
  }

  return null;
}

function buildPaginationMeta(data, requestPagination) {
  const normalizedData = data && typeof data === "object" ? data : {};
  const normalizedRequestPagination =
    normalizePaginationOptions(requestPagination);
  const list = normalizeListData(normalizedData);
  const page =
    Math.floor(
      toNumber(
        pickFirstValue(normalizedData, [
          "page",
          "current_page",
          "currentPage",
          "page_num",
        ]),
      ),
    ) || normalizedRequestPagination.page;
  const pageSize =
    Math.floor(
      toNumber(
        pickFirstValue(normalizedData, [
          "page_size",
          "pagesize",
          "size",
          "limit",
          "per_page",
        ]),
      ),
    ) || normalizedRequestPagination.pageSize;
  const total = Math.floor(
    toNumber(
      pickFirstValue(normalizedData, [
        "total",
        "count",
        "total_count",
        "totalCount",
        "record_count",
        "all_count",
      ]),
    ),
  );
  const lastPage = Math.floor(
    toNumber(
      pickFirstValue(normalizedData, [
        "last_page",
        "lastPage",
        "page_total",
        "total_page",
        "pages",
        "pageCount",
      ]),
    ),
  );

  const hasMoreRaw = pickFirstValue(normalizedData, [
    "has_more",
    "hasMore",
    "more",
    "is_more",
    "next_page",
    "nextPage",
  ]);
  const hasMoreByRawValue = parseBooleanLike(hasMoreRaw);
  let hasMore = hasMoreByRawValue;

  if (hasMore === null && lastPage > 0) {
    hasMore = page < lastPage;
  }

  if (hasMore === null && total > 0 && pageSize > 0) {
    hasMore = page * pageSize < total;
  }

  if (hasMore === null) {
    hasMore = list.length >= pageSize && list.length > 0;
  }

  if (!list.length) {
    hasMore = false;
  }

  return {
    page: page,
    pageSize: pageSize,
    total: total,
    lastPage: lastPage,
    hasMore: Boolean(hasMore),
  };
}

function formatTransferRecordNumber(value) {
  const number = toNumber(value);
  return formatHomeNumber(number, Number.isInteger(number) ? 0 : 2);
}

function formatLedgerRecordNumber(value) {
  return formatTransferRecordNumber(Math.abs(toNumber(value)));
}

function resolveRecordDirection(
  item,
  amountValue,
  positiveLabel,
  negativeLabel,
) {
  const rawDirection = pickFirstValue(item, [
    "io_type",
    "in_out",
    "direction",
    "income_type",
    "is_add",
    "flow_type",
  ]);

  if (rawDirection !== "") {
    const directionText = String(rawDirection).toLowerCase();

    if (
      directionText === "1" ||
      directionText === "in" ||
      directionText === "income" ||
      directionText === "add" ||
      directionText === "+"
    ) {
      return positiveLabel;
    }

    if (
      directionText === "0" ||
      directionText === "-1" ||
      directionText === "out" ||
      directionText === "expense" ||
      directionText === "sub" ||
      directionText === "-"
    ) {
      return negativeLabel;
    }
  }

  return toNumber(amountValue) >= 0 ? positiveLabel : negativeLabel;
}

function buildDirectionPresentation(direction) {
  return {
    income:
      direction === "收入" ||
      direction === "转入" ||
      direction === "获得" ||
      direction === "到账",
    actionSymbol:
      direction === "收入" ||
      direction === "转入" ||
      direction === "获得" ||
      direction === "到账"
        ? "+"
        : "-",
  };
}

function buildRecordId(item, fallbackPrefix) {
  return String(
    pickFirstValue(item, [
      "order_sn",
      "trade_no",
      "bill_no",
      "sn",
      "id",
      "log_id",
      "uid",
    ]) || fallbackPrefix + "-" + Math.random(),
  );
}

function normalizeAvailablePointsText(text) {
  const safeText = String(text || "");
  if (!safeText) {
    return "";
  }

  return safeText
    .replace(/可用积分/g, "__AVAILABLE_POINTS__")
    .replace(/积分/g, "可用积分")
    .replace(/__AVAILABLE_POINTS__/g, "可用积分");
}

function mapWalletFlowRecords(list, meta) {
  return normalizeListData(list).map(function (item) {
    const amountValue = pickFirstValue(item, [
      "number",
      "num",
      "amount",
      "change_num",
      "value",
      "money",
      "bmt_num",
      "power_num",
      "gold_num",
      "point_num",
    ]);
    const direction = resolveRecordDirection(item, amountValue, "收入", "支出");
    const directionPresentation = buildDirectionPresentation(direction);
    const orderSn = String(
      pickFirstValue(item, ["order_sn", "trade_no", "bill_no", "sn"]) || "",
    );
    const noteText = String(
      pickFirstValue(item, [
        "remark",
        "desc",
        "memo",
        "note",
        "type_name",
        "status_text",
      ]) || "",
    );
    const balanceValue = pickFirstValue(item, [
      "balance",
      "after_balance",
      "surplus",
      "remain",
      "wallet_balance",
      "usable_balance",
    ]);
    const title =
      pickFirstValue(item, ["title", "name", "type_name"]) ||
      meta.title ||
      meta.unit + "记录";
    const isPointsLedger =
      String(meta && meta.key ? meta.key : "") === "points";
    const displayTitle = isPointsLedger
      ? normalizeAvailablePointsText(title)
      : title;
    const displayNoteText = isPointsLedger
      ? normalizeAvailablePointsText(noteText)
      : noteText;
    const displayDirection = isPointsLedger
      ? normalizeAvailablePointsText(direction)
      : direction;
    const displaySubtitle = orderSn
      ? "单号 " + orderSn
      : displayNoteText || displayDirection;
    const displayFeeText =
      displayNoteText || (orderSn ? "单号 " + orderSn : meta.subtitle);

    return {
      id: buildRecordId(item, meta.key || "flow"),
      sourceId: String(pickFirstValue(item, ["id", "log_id", "uid"]) || ""),
      title: displayTitle,
      subtitle: displaySubtitle,
      time: pickFirstValue(item, [
        "add_time",
        "create_time",
        "created_at",
        "time",
        "update_time",
      ]),
      amount:
        directionPresentation.actionSymbol +
        formatLedgerRecordNumber(amountValue),
      balance:
        balanceValue !== ""
          ? "结余 " + formatTransferRecordNumber(balanceValue) + " " + meta.unit
          : "",
      balanceLabel:
        balanceValue !== ""
          ? "剩余" + meta.unit + "：" + formatTransferRecordNumber(balanceValue)
          : "当前" + meta.unit + "流水",
      assetLabel: meta.unit,
      feeText: displayFeeText,
      directionLabel: displayDirection,
      actionSymbol: directionPresentation.actionSymbol,
      orderSn: orderSn,
      noteText: displayNoteText,
      tag: directionPresentation.income ? "收" : "支",
      tone: directionPresentation.income ? "success" : "danger",
      cardTone: directionPresentation.income ? "success" : "danger",
    };
  });
}

function buildRedeemConsumeText(item, meta) {
  const fragments = [];

  if (meta.type === 0) {
    const voucherValue = pickFirstValue(item, [
      "voucher_num",
      "coin",
      "deduct_coin",
      "use_coin",
    ]);
    const couponValue = pickFirstValue(item, [
      "coupon_num",
      "diamond",
      "deduct_diamond",
      "use_diamond",
    ]);

    if (voucherValue !== "") {
      fragments.push("抵用券 " + formatTransferRecordNumber(voucherValue));
    }

    if (couponValue !== "") {
      fragments.push("消费券 " + formatTransferRecordNumber(couponValue));
    }
  } else {
    const pointValue = pickFirstValue(item, [
      "point",
      "points",
      "point_num",
      "use_point",
      "integral",
    ]);
    const powerValue = pickFirstValue(item, [
      "power",
      "power_num",
      "c_power",
      "use_power",
    ]);

    if (pointValue !== "") {
      const pointLabel = meta.type === 1 ? "可用积分" : "积分";
      fragments.push(pointLabel + " " + formatTransferRecordNumber(pointValue));
    }

    if (powerValue !== "") {
      fragments.push("算力 " + formatTransferRecordNumber(powerValue));
    }
  }

  if (fragments.length) {
    return "消耗" + fragments.join(" / ");
  }

  return String(
    pickFirstValue(item, ["remark", "desc", "memo", "note", "status_text"]) ||
      meta.subtitle ||
      "",
  );
}

function mapRedeemRecords(list, meta) {
  return normalizeListData(list).map(function (item) {
    const primaryValue = pickFirstValue(item, meta.amountKeys);
    const orderSn = String(
      pickFirstValue(item, ["order_sn", "trade_no", "bill_no", "sn"]) || "",
    );
    const balanceValue = pickFirstValue(item, [
      "balance",
      "after_balance",
      "surplus",
      "remain",
    ]);
    const titleText = String(
      pickFirstValue(item, ["title", "name", "type_name"]) ||
        meta.title ||
        "兑换记录",
    );
    const noteText = buildRedeemConsumeText(item, meta);

    return {
      id: buildRecordId(item, meta.key || "redeem"),
      title: titleText,
      subtitle: orderSn ? "单号 " + orderSn : noteText,
      time: pickFirstValue(item, [
        "add_time",
        "create_time",
        "created_at",
        "time",
        "update_time",
      ]),
      amount: "+" + formatLedgerRecordNumber(primaryValue),
      balance:
        balanceValue !== ""
          ? "结余 " + formatTransferRecordNumber(balanceValue) + " " + meta.unit
          : "",
      balanceLabel:
        balanceValue !== ""
          ? "剩余" + meta.unit + "：" + formatTransferRecordNumber(balanceValue)
          : "本次到账" + meta.unit,
      assetLabel: meta.unit,
      feeText: noteText,
      feeDisplayText:
        meta.key === "bmt-flash"
          ? "BMT闪兑"
          : meta.key === "bmt"
            ? "BMT兑换"
            : "",
      directionLabel: "兑换",
      actionSymbol: "+",
      orderSn: orderSn,
      tag: "兑",
      tone: "success",
      cardTone: "success",
    };
  });
}

function getTransferRecordUnit(item) {
  return Number(item && item.type) === 0 ? "算力" : "可用积分";
}

function normalizeTransferPointsText(text, item) {
  if (Number(item && item.type) === 0) {
    return String(text || "");
  }

  const safeText = String(text || "");
  return safeText
    .replace(/可用积分/g, "__POINTS_LABEL__")
    .replace(/积分/g, "可用积分")
    .replace(/__POINTS_LABEL__/g, "可用积分");
}

function getTransferRecordTone(item) {
  return Number(item && item.io_type) === 1 ? "success" : "danger";
}

function getTransferRecordTag(item) {
  return Number(item && item.io_type) === 1 ? "收" : "赠";
}

function getTransferRecordDirection(item) {
  return Number(item && item.io_type) === 1 ? "转入" : "转出";
}

function getTransferRecordTitle(item) {
  const unit = getTransferRecordUnit(item);
  return Number(item && item.io_type) === 1 ? unit + "获赠" : unit + "转赠";
}

function getTransferRecordSymbol(item) {
  return Number(item && item.io_type) === 1 ? "+" : "-";
}

function getTransferRecordAmount(item) {
  const numberText = formatTransferRecordNumber(item && item.num);
  return getTransferRecordSymbol(item) + numberText;
}

function extractTransferTitleFeeValue(item) {
  const titleText = String(
    pickFirstValue(item, ["title", "name"]) || "",
  ).trim();

  if (!titleText) {
    return "";
  }

  if (/^-?\d+(?:\.\d+)?$/.test(titleText)) {
    return titleText;
  }

  const titleFeeMatch = titleText.match(
    /手续费(?:\s*[:：]?\s*|\s*[（(]\s*)(-?\d+(?:\.\d+)?)\s*[)）]?/,
  );

  return titleFeeMatch && titleFeeMatch[1] !== undefined
    ? titleFeeMatch[1]
    : "";
}

function getTransferRecordFee(item) {
  const titleFeeValue = extractTransferTitleFeeValue(item);
  if (titleFeeValue !== "") {
    return toNumber(titleFeeValue);
  }

  if (
    item &&
    item.fee !== undefined &&
    item.fee !== null &&
    String(item.fee).trim() !== ""
  ) {
    return toNumber(item.fee);
  }

  return (
    (toNumber(item && item.num) * toNumber(item && item.fee_percent)) / 100
  );
}

function getTransferRecordFeeText(item) {
  const percent = toNumber(item && item.fee_percent);
  const unit = getTransferRecordUnit(item);
  const feeText = formatHomeNumber(getTransferRecordFee(item), 2);

  if (percent > 0) {
    return "手续费: " + feeText;
  }

  return "手续费: " + feeText + " " + unit;
}

function getTransferRecordBalance(item) {
  const unit = getTransferRecordUnit(item);
  return "结余 " + toFixedNumber(item && item.balance, 2) + " " + unit;
}

function getTransferRecordBalanceLabel(item) {
  const unit = getTransferRecordUnit(item);
  return (
    "剩余" + unit + "：" + formatTransferRecordNumber(item && item.balance)
  );
}

function mapTransferRecords(list) {
  return (Array.isArray(list) ? list : []).map(function (item) {
    const titleText = item.title || getTransferRecordTitle(item);
    return {
      id: item.order_sn || item.id || String(Math.random()),
      title: normalizeTransferPointsText(titleText, item),
      subtitle: item.order_sn
        ? "单号 " + item.order_sn
        : getTransferRecordDirection(item),
      time: item.add_time || "",
      amount: getTransferRecordAmount(item),
      balance: getTransferRecordBalance(item),
      balanceLabel: getTransferRecordBalanceLabel(item),
      assetLabel: getTransferRecordUnit(item),
      feeText: getTransferRecordFeeText(item),
      directionLabel: getTransferRecordDirection(item),
      actionSymbol: getTransferRecordSymbol(item),
      orderSn: item.order_sn || "",
      tag: getTransferRecordTag(item),
      tone: getTransferRecordTone(item),
      cardTone: getTransferRecordTone(item),
    };
  });
}

function mapBmtrTransferRecords(list) {
  return normalizeListData(list).map(function (item) {
    // 交易类型：0 支出，1 收入，2 退回
    const bmtrType = Number(item && item.bmtr_type);
    const isIncome = bmtrType === 1 || bmtrType === 2;
    const amountValue = Math.abs(toNumber(item && item.bmtr));
    const orderSn = String(pickFirstValue(item, ["order_sn", "sn"]) || "");
    const tipsText = String(
      pickFirstValue(item, ["bmtr_type_tips", "title"]) || "",
    );
    const titleText =
      tipsText ||
      (bmtrType === 2 ? "BMTR退回" : isIncome ? "BMTR获赠" : "BMTR转赠");
    const balanceValue = pickFirstValue(item, [
      "bmtr_after",
      "balance",
      "after_balance",
    ]);
    const feeValue = extractTransferTitleFeeValue({ title: tipsText });

    return {
      id: buildRecordId(item, "bmtr-transfer"),
      title: titleText,
      subtitle: orderSn ? "单号 " + orderSn : tipsText,
      time: String(
        pickFirstValue(item, ["add_time", "create_time", "created_at", "time"]) ||
          "",
      ),
      amount: (isIncome ? "+" : "-") + formatTransferRecordNumber(amountValue),
      balance:
        balanceValue !== ""
          ? "结余 " + formatTransferRecordNumber(balanceValue) + " BMTR"
          : "",
      balanceLabel:
        balanceValue !== ""
          ? "剩余BMTR：" + formatTransferRecordNumber(balanceValue)
          : "本次到账BMTR",
      assetLabel: "BMTR",
      feeText:
        feeValue !== ""
          ? "手续费: " + formatHomeNumber(toNumber(feeValue), 2)
          : "",
      directionLabel: bmtrType === 2 ? "退回" : isIncome ? "转入" : "转出",
      actionSymbol: isIncome ? "+" : "-",
      orderSn: orderSn,
      tag: isIncome ? "收" : "赠",
      tone: isIncome ? "success" : "danger",
      cardTone: isIncome ? "success" : "danger",
    };
  });
}

function mapPointsConvertRecords(list) {
  return normalizeListData(list).map(function (item) {
    const rawTransferPointValue = pickFirstValue(item, [
      "transfer_point_num",
      "transfer_coin_num",
      "point_num",
      "coin_num",
      "value",
    ]);
    const hasTransferPointValue = rawTransferPointValue !== "";
    const amountValue = pickFirstValue(item, [
      "gold_num",
      "number",
      "transfer_point_num",
      "transfer_coin_num",
      "point_num",
      "num",
      "amount",
      "value",
    ]);
    const rawStatusText = String(
      pickFirstValue(item, [
        "status_text",
        "status_name",
        "status_desc",
        "transfer_status_text",
      ]) || "",
    );
    const rawStatusCode = String(
      pickFirstValue(item, ["status", "state", "transfer_status"]) || "",
    );
    let statusText = rawStatusText;
    let disabled = false;

    if (!statusText) {
      if (rawStatusCode === "1") {
        statusText = "兑换中";
      } else if (rawStatusCode === "2") {
        statusText = "已转换";
      } else if (rawStatusCode === "3") {
        statusText = "转换失败";
      }
    }

    if (
      /中/.test(statusText) ||
      /完成/.test(statusText) ||
      /成功/.test(statusText) ||
      /失败/.test(statusText)
    ) {
      disabled = true;
    }

    if (hasTransferPointValue && toNumber(rawTransferPointValue) <= 0) {
      disabled = true;
    }

    return {
      id: String(
        pickFirstValue(item, ["id", "bill_id", "log_id", "sn"]) ||
          Math.random(),
      ),
      sourceId: String(pickFirstValue(item, ["id", "bill_id", "log_id"]) || ""),
      orderSn: String(
        pickFirstValue(item, ["order_sn", "trade_no", "bill_no", "sn"]) || "",
      ),
      title:
        pickFirstValue(item, ["title", "name", "type_name"]) || "系统赠送积分",
      subtitle:
        "可转数量 " + formatTransferRecordNumber(rawTransferPointValue || 0),
      time: pickFirstValue(item, [
        "add_time",
        "create_time",
        "created_at",
        "time",
        "update_time",
      ]),
      amount: "+" + formatLedgerRecordNumber(amountValue),
      amountValue: toNumber(amountValue),
      transferPointValue: toNumber(rawTransferPointValue),
      transfer_point_num: toNumber(rawTransferPointValue),
      statusText: statusText,
      disabled: disabled,
      balance:
        item &&
        item.userBillRelease &&
        item.userBillRelease.total !== undefined &&
        item.userBillRelease.total !== null
          ? "释放总量 " + formatTransferRecordNumber(item.userBillRelease.total)
          : "",
      tag: "积",
      tone: disabled ? "warning" : "success",
    };
  });
}

function extractMonthLabel(value) {
  const raw = String(value || "").trim();

  if (!raw) {
    const currentDate = new Date();
    const year = currentDate.getFullYear();
    const month = String(currentDate.getMonth() + 1).padStart(2, "0");
    return year + "-" + month;
  }

  const matcher = raw.match(/(\d{4})[-/.](\d{1,2})/);
  if (matcher) {
    return matcher[1] + "-" + String(matcher[2]).padStart(2, "0");
  }

  const date = new Date(raw.replace(/-/g, "/"));
  if (Number.isNaN(date.getTime())) {
    return raw.slice(0, 7);
  }

  return (
    date.getFullYear() + "-" + String(date.getMonth() + 1).padStart(2, "0")
  );
}

function buildPointsHistoryRecords(list) {
  return mapWalletFlowRecords(list, {
    key: "points-convert-history",
    unit: "积分",
    title: "积分记录",
    subtitle: "可用积分流水",
  }).map(function (item) {
    return Object.assign({}, item, {
      month: extractMonthLabel(item.time),
      detailAvailable: canOpenPointsConvertRecordDetail(item),
      amountTone: item.actionSymbol === "+" ? "increase" : "decrease",
    });
  });
}

function buildMonthOptions(list) {
  const months = (Array.isArray(list) ? list : []).reduce(function (
    result,
    item,
  ) {
    const month =
      item && item.month ? item.month : extractMonthLabel(item && item.time);
    if (month && result.indexOf(month) === -1) {
      result.push(month);
    }
    return result;
  }, []);

  months.sort(function (left, right) {
    return right.localeCompare(left);
  });

  if (!months.length) {
    months.push(extractMonthLabel(""));
  }

  return months;
}

function canOpenPointsConvertRecordDetail(item) {
  const target = item && typeof item === "object" ? item : {};
  const contentText = [
    target.title,
    target.subtitle,
    target.noteText,
    target.feeText,
    target.directionLabel,
  ]
    .join(" ")
    .toLowerCase();

  return (
    Boolean(target.orderSn || target.sourceId) &&
    /转换/.test(contentText) &&
    !/bmt/.test(contentText)
  );
}

function extractPointsConvertDetailItems(data) {
  if (Array.isArray(data)) {
    return data;
  }

  if (!data || typeof data !== "object") {
    return [];
  }

  if (Array.isArray(data.list)) {
    return data.list;
  }

  if (Array.isArray(data.items)) {
    return data.items;
  }

  if (Array.isArray(data.details)) {
    return data.details;
  }

  if (Array.isArray(data.records)) {
    return data.records;
  }

  return [];
}

function buildPointsConvertDetailFallback(record) {
  const fallback = record || {};
  const amountValue = String(fallback.amount || "").replace(/[^\d.-]/g, "");

  return {
    orderSn: fallback.orderSn || "",
    totalAmount:
      fallback.amount && String(fallback.amount).trim()
        ? String(fallback.amount)
        : "+" + formatLedgerRecordNumber(amountValue),
    time: fallback.time || "",
    details: [
      {
        id: fallback.id || fallback.orderSn || "fallback-record",
        title: fallback.title || "积分转换",
        amount:
          fallback.amount && String(fallback.amount).trim()
            ? String(fallback.amount)
            : "+" + formatLedgerRecordNumber(amountValue),
        time: fallback.time || "",
      },
    ],
  };
}

function buildPointsConvertDetailPayload(data, fallbackRecord) {
  const detailItems = extractPointsConvertDetailItems(data);
  const summarySource =
    data && typeof data === "object" && !Array.isArray(data) ? data : {};
  const fallback = fallbackRecord || {};
  const summaryTotalValue = pickFirstValue(summarySource, [
    "gold_num",
    "number",
    "num",
    "amount",
    "point_num",
    "transfer_coin_num",
    "total",
  ]);
  const detailFallbackTotal = detailItems.reduce(function (total, item) {
    const value = pickFirstValue(item, [
      "gold_num",
      "number",
      "num",
      "amount",
      "point_num",
      "transfer_coin_num",
      "value",
    ]);
    return total + toNumber(value);
  }, 0);
  const totalValue =
    summaryTotalValue !== "" ? summaryTotalValue : detailFallbackTotal;
  const totalAmountText =
    totalValue !== ""
      ? "+" + formatLedgerRecordNumber(totalValue)
      : fallback.amount || "+0";
  const detailList = detailItems.map(function (item, index) {
    const amountValue = pickFirstValue(item, [
      "gold_num",
      "number",
      "num",
      "amount",
      "point_num",
      "transfer_coin_num",
      "value",
    ]);

    return {
      id: String(
        pickFirstValue(item, ["id", "bill_id", "log_id", "sn"]) ||
          "detail-" + index,
      ),
      title:
        pickFirstValue(item, ["title", "name", "type_name"]) ||
        fallback.title ||
        "系统赠送积分",
      amount: "+" + formatLedgerRecordNumber(amountValue),
      time:
        pickFirstValue(item, [
          "add_time",
          "create_time",
          "created_at",
          "time",
          "update_time",
        ]) ||
        fallback.time ||
        "",
    };
  });

  if (!detailList.length) {
    return buildPointsConvertDetailFallback({
      id: fallback.id,
      orderSn: String(
        pickFirstValue(summarySource, [
          "order_sn",
          "trade_no",
          "bill_no",
          "sn",
        ]) ||
          fallback.orderSn ||
          "",
      ),
      title:
        pickFirstValue(summarySource, ["title", "name", "type_name"]) ||
        fallback.title,
      amount: totalAmountText,
      time:
        pickFirstValue(summarySource, [
          "add_time",
          "create_time",
          "created_at",
          "time",
          "update_time",
        ]) || fallback.time,
    });
  }

  return {
    orderSn: String(
      pickFirstValue(summarySource, [
        "order_sn",
        "trade_no",
        "bill_no",
        "sn",
      ]) ||
        fallback.orderSn ||
        "",
    ),
    totalAmount: totalAmountText,
    time:
      pickFirstValue(summarySource, [
        "add_time",
        "create_time",
        "created_at",
        "time",
        "update_time",
      ]) ||
      fallback.time ||
      "",
    details: detailList,
  };
}

function buildDefaultLedger(type, balances) {
  const map = {
    power: {
      title: "兑换记录",
      subtitle: "算力兑换记录",
    },
    bmt: {
      title: "兑换记录",
      subtitle: "BMT兑换记录",
    },
    withdraw: {
      title: "提取记录",
      subtitle: "BMT提取流水",
    },
    coupon: {
      title: "消费券",
      subtitle: "当前消费券 " + toFixedNumber(balances.coupon, 2),
    },
    voucher: {
      title: "抵用券记录",
      subtitle: "可用抵用券 " + toFixedNumber(balances.voucher, 2),
    },
  };

  return {
    type: type,
    title: map[type].title,
    subtitle: map[type].subtitle,
    records: [],
  };
}

function buildFlowRecordId(item, groupKey, index) {
  const directId = String(
    pickFirstValue(item, ["id", "flow_id", "log_id", "record_id"]) || "",
  ).trim();

  if (directId) {
    return directId;
  }

  return [
    groupKey,
    pickFirstValue(item, ["add_time", "time", "created_at"]),
    pickFirstValue(item, ["title", "mark", "amount", "number"]),
    index,
  ]
    .map((value) => String(value || ""))
    .join("-");
}

function isPositiveFlowValue(value) {
  const booleanLike = parseBooleanLike(value);

  if (booleanLike !== null) {
    return booleanLike;
  }

  return toNumber(value) > 0;
}

function resolveMonthLabel(dateText) {
  const normalized = String(dateText || "").trim();

  if (/^\d{6}$/.test(normalized)) {
    return normalized.slice(4, 6) + "月";
  }

  return normalized || "本月";
}

function mapBalanceCenterItem(item, groupKey, index) {
  const isIncome = isPositiveFlowValue(
    pickFirstValue(item, ["pm", "io_type", "direction"]),
  );
  const amount = formatTransferRecordNumber(
    pickFirstValue(item, ["number", "amount", "num"]),
  );
  const merchantName = pickFirstValue(item, ["merchant_name", "merchantName"]);
  const frozenTime = pickFirstValue(item, [
    "frozen_time_str",
    "frozen_time",
    "unlock_time",
  ]);
  const failReason = pickFirstValue(item, ["fail_msg", "reason", "remark"]);
  const refunded =
    String(pickFirstValue(item, ["status"]) || "").trim() === "-1" &&
    isIncome;
  const detailRows = [
    {
      label: "获得时间",
      value: pickFirstValue(item, ["add_time", "time", "created_at"]) || "--",
    },
  ];

  if (!isIncome && frozenTime && String(frozenTime) !== "0") {
    detailRows.push({
      label: "解冻时间",
      value: String(frozenTime),
    });
  }

  return {
    id: buildFlowRecordId(item, groupKey, index),
    title:
      pickFirstValue(item, ["title", "mark", "type_name"]) ||
      (isIncome ? "佣金获得" : "佣金支出"),
    amount: (isIncome ? "+" : "-") + amount,
    amountTone: isIncome ? "income" : "expense",
    directionLabel: isIncome ? "佣金获得" : "佣金支出",
    detailRows: detailRows,
    merchantName: merchantName ? String(merchantName) : "",
    note: failReason
      ? "原因：" + failReason
      : refunded
        ? "已退单"
        : "",
    noteTone: failReason ? "danger" : refunded ? "expense" : "muted",
  };
}

function mapBalanceCenterSections(data) {
  const list = normalizeListData(data);
  const groupOrder = [];
  const groupedMap = {};
  const sourceGroups = Array.isArray(data && data.time) ? data.time : [];

  sourceGroups.forEach((groupKey) => {
    const normalizedKey = String(groupKey || "").trim();
    if (!normalizedKey || groupedMap[normalizedKey]) {
      return;
    }

    groupedMap[normalizedKey] = {
      key: normalizedKey,
      label: normalizedKey,
      items: [],
    };
    groupOrder.push(normalizedKey);
  });

  list.forEach((item, index) => {
    const groupKey =
      String(
        pickFirstValue(item, ["time_key", "date_str", "date", "month"]) ||
          groupOrder[0] ||
          "最新记录",
      ).trim() || "最新记录";

    if (!groupedMap[groupKey]) {
      groupedMap[groupKey] = {
        key: groupKey,
        label: groupKey,
        items: [],
      };
      groupOrder.push(groupKey);
    }

    groupedMap[groupKey].items.push(mapBalanceCenterItem(item, groupKey, index));
  });

  return groupOrder
    .map((groupKey) => groupedMap[groupKey])
    .filter((section) => section && section.items.length);
}

function normalizeVoucherTab(tabKey) {
  const normalizedKey = String(tabKey || "").trim();

  if (normalizedKey === "normal" || normalizedKey === "3") {
    return "normal";
  }

  if (normalizedKey === "order" || normalizedKey === "6") {
    return "order";
  }

  return "all";
}

function resolveVoucherTabFilters(tabKey) {
  const normalizedKey = normalizeVoucherTab(tabKey);

  if (normalizedKey === "normal") {
    return {
      tabKey: normalizedKey,
      is_release: 1,
      coin_type: 3,
    };
  }

  if (normalizedKey === "order") {
    return {
      tabKey: normalizedKey,
      is_release: 1,
      coin_type: 6,
    };
  }

  return {
    tabKey: "all",
    is_release: 0,
    coin_type: "",
  };
}

function mapVoucherCenterItem(item, groupKey, index) {
  const isIncome = isPositiveFlowValue(
    pickFirstValue(item, ["io_type", "pm", "direction"]),
  );
  const coinType = pickFirstValue(item, ["coin_type", "coinType"]);
  const dcNum = pickFirstValue(item, ["dc_num", "dcNum"]);
  let title =
    pickFirstValue(item, ["title", "mark", "type_name"]) ||
    (isIncome ? "抵用券收入" : "抵用券支出");

  if (dcNum !== "" && String(coinType) === "6") {
    title += "（" + String(dcNum) + "代）";
  }

  return {
    id: buildFlowRecordId(item, groupKey, index),
    title: title,
    amount:
      (isIncome ? "+" : "-") +
      formatTransferRecordNumber(
        pickFirstValue(item, ["amount", "number", "num"]),
      ),
    amountTone: isIncome ? "income" : "expense",
    time: pickFirstValue(item, ["add_time", "time", "created_at"]) || "--",
  };
}

function mapVoucherCenterSections(data) {
  const list = normalizeListData(data);
  const statistics = Array.isArray(data && data.statistics)
    ? data.statistics.slice().reverse()
    : [];
  const groupOrder = [];
  const groupedMap = {};

  statistics.forEach((item) => {
    const groupKey = String(pickFirstValue(item, ["date_str", "month"]) || "").trim();
    if (!groupKey || groupedMap[groupKey]) {
      return;
    }

    groupedMap[groupKey] = {
      key: groupKey,
      label: resolveMonthLabel(groupKey),
      income: formatTransferRecordNumber(
        pickFirstValue(item, ["sum_io1", "income", "in_amount"]),
      ),
      expense: formatTransferRecordNumber(
        pickFirstValue(item, ["sum_io0", "expense", "out_amount"]),
      ),
      items: [],
    };
    groupOrder.push(groupKey);
  });

  list.forEach((item, index) => {
    const groupKey =
      String(pickFirstValue(item, ["date_str", "month"]) || "").trim() ||
      "latest";

    if (!groupedMap[groupKey]) {
      groupedMap[groupKey] = {
        key: groupKey,
        label: resolveMonthLabel(groupKey),
        income: "0",
        expense: "0",
        items: [],
      };
      groupOrder.push(groupKey);
    }

    groupedMap[groupKey].items.push(mapVoucherCenterItem(item, groupKey, index));
  });

  return groupOrder
    .map((groupKey) => groupedMap[groupKey])
    .filter((section) => section && section.items.length);
}

function normalizeTransferTarget(data, fallbackId) {
  if (data && typeof data === "object" && !Array.isArray(data)) {
    const id = String(data.uid || data.id || fallbackId || "").trim();
    if (!id) {
      throw createError("未查询到好友", data);
    }

    return {
      id: id,
      nickname: data.nickname || data.nick_name || data.username || "用户" + id,
      phone: data.mobile || data.phone || "ID已通过校验",
      avatar: data.avatar || data.headimg || "",
    };
  }

  if (data === true) {
    const id = String(fallbackId || "").trim();
    if (!id) {
      throw createError("未查询到好友", data);
    }

    return {
      id: id,
      nickname: "用户" + id,
      phone: "ID已通过校验",
      avatar: "",
    };
  }

  throw createError("未查询到好友", data);
}

function sumBy(list, key) {
  return (Array.isArray(list) ? list : []).reduce(function (total, item) {
    return total + toNumber(item && item[key]);
  }, 0);
}

async function fetchPriceData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.price,
      },
      requestOptions,
    ),
    "实时价格加载失败",
  );
}

async function fetchHomeBalanceData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.homeBalance,
      },
      requestOptions,
    ),
    "首页资产加载失败",
  );
}

async function fetchExtractBankData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.extractBank,
      },
      requestOptions,
    ),
    "余额信息加载失败",
  );
}

async function fetchBmtPowerRateData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.bmtRedeemPowerRate,
      },
      requestOptions,
    ),
    "兑换比例加载失败",
  );
}

async function fetchPowerExchangeMuitData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.powerExchangeMuit,
      },
      requestOptions,
    ),
    "兑换倍率加载失败",
  );
}

function resolveRedeemPowerRate(data) {
  const sourceValue =
    data && typeof data === "object"
      ? pickFirstValue(data, [
          "r",
          "rate",
          "power_rate",
          "powerRate",
          "redeem_power_rate",
          "redeemRate",
          "value",
          "num",
          "number",
        ])
      : data;

  const normalizedRate = toNumber(sourceValue);
  return normalizedRate > 0 ? normalizedRate : 0;
}

async function fetchUserData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.getUser,
      },
      requestOptions,
    ),
    "用户信息加载失败",
  );
}

async function fetchTransferFeeData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.transferFee,
      },
      requestOptions,
    ),
    "手续费比例加载失败",
  );
}

async function fetchTransferBmtrFeeData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.transferBmtrFee,
      },
      requestOptions,
    ),
    "BMTR手续费比例加载失败",
  );
}

async function fetchTransferBmtrBalanceData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.transferBmtrBalance,
      },
      requestOptions,
    ),
    "BMTR余额加载失败",
  );
}

async function fetchWithdrawRateData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.withdrawRate,
      },
      requestOptions,
    ),
    "提现费率加载失败",
  );
}

function resolvePercentRate(data) {
  let sourceValue =
    data && typeof data === "object"
      ? pickFirstValue(data, [
          "r",
          "rate",
          "fee_rate",
          "feeRate",
          "withdraw_rate",
          "withdrawRate",
          "prop",
          "value",
          "num",
          "number",
        ])
      : data;

  if (typeof sourceValue === "string") {
    sourceValue = sourceValue.replace(/%/g, "").trim();
  }

  const rate = toNumber(sourceValue);

  if (rate > 0 && rate < 1) {
    return rate * 100;
  }

  return rate;
}

async function fetchWalletAddressData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.walletDetail,
      },
      requestOptions,
    ),
    "钱包加载失败",
  );
}

async function fetchCoinIndexData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.coinIndex,
      },
      requestOptions,
    ),
    "抵用券信息加载失败",
  );
}

async function fetchCoinIndexSummaryData(query, requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.coinIndex,
        data: query || {},
      },
      requestOptions,
    ),
    "抵用券信息加载失败",
  );
}

async function fetchUserProfileData(requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.userProfile,
      },
      requestOptions,
    ),
    "用户信息加载失败",
  );
}

function normalizePointsConvertInterval(value) {
  const rawInterval = String(
    value === undefined || value === null ? "" : value,
  ).trim();

  if (!rawInterval) {
    return serviceConfig.POINTS_CONVERT_INTERVAL;
  }

  const matcher = rawInterval.match(
    /^(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/,
  );
  if (!matcher) {
    return serviceConfig.POINTS_CONVERT_INTERVAL;
  }

  const start = toNumber(matcher[1]);
  const end = toNumber(matcher[2]);

  if (!Number.isFinite(start) || !Number.isFinite(end)) {
    return serviceConfig.POINTS_CONVERT_INTERVAL;
  }

  return String(start) + "," + String(end);
}

async function fetchPointsConvertList(pagination, requestOptions, interval) {
  const normalizedInterval = normalizePointsConvertInterval(interval);
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.pointsConvertAvailableList,
        data: buildPagingRequestData(
          {
            interval: normalizedInterval,
          },
          pagination,
        ),
      },
      requestOptions,
    ),
    "积分转换列表加载失败",
  );
}

async function fetchPointsConvertHistoryListData(
  month,
  pagination,
  requestOptions,
) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.pointsConvertHistoryList,
        data: buildPagingRequestData(
          {
            month: month,
          },
          pagination,
        ),
      },
      requestOptions,
    ),
    "积分兑换列表加载失败",
  );
}

async function fetchTransferLedgerData(pagination, requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.transferLedger,
        data: buildPagingRequestData({}, pagination),
      },
      requestOptions,
    ),
    "转赠记录加载失败",
  );
}

async function fetchBmtrTransferLedgerData(pagination, requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.transferBmtrList,
        data: buildPagingRequestData({}, pagination),
      },
      requestOptions,
    ),
    "BMTR转赠记录加载失败",
  );
}

async function fetchSpreadCommissionListData(
  recordType,
  pagination,
  requestOptions,
  filters,
) {
  const filterSource = filters && typeof filters === "object" ? filters : {};

  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.spreadCommission + "/" + recordType,
        data: buildPagingRequestData(
          {
            pm:
              pickFirstValue(filterSource, ["pm", "direction", "flow"]) || "",
            start_time:
              pickFirstValue(filterSource, [
                "start_time",
                "startTime",
                "start",
              ]) || "",
            end_time:
              pickFirstValue(filterSource, ["end_time", "endTime", "end"]) ||
              "",
          },
          pagination,
        ),
      },
      requestOptions,
    ),
    "余额记录加载失败",
  );
}

async function fetchWalletFlowListData(flowType, pagination, requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.walletFlowList,
        data: buildPagingRequestData(
          {
            type: flowType,
          },
          pagination,
        ),
      },
      requestOptions,
    ),
    "资产流水加载失败",
  );
}

async function fetchCoinReleaseListData(pagination, requestOptions, filters) {
  const filterSource = filters && typeof filters === "object" ? filters : {};

  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.coinList,
        data: buildPagingRequestData(
          {
            is_release:
              pickFirstValue(filterSource, [
                "is_release",
                "isRelease",
                "release",
              ]) || 0,
            coin_type:
              pickFirstValue(filterSource, [
                "coin_type",
                "coinType",
                "type",
              ]) || "",
          },
          pagination,
        ),
      },
      requestOptions,
    ),
    "抵用券记录加载失败",
  );
}

async function fetchRedeemRecordListData(
  redeemType,
  pagination,
  requestOptions,
) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.redeemRecordList,
        data: buildPagingRequestData(
          {
            type: redeemType,
          },
          pagination,
        ),
      },
      requestOptions,
    ),
    "兑换记录加载失败",
  );
}

async function fetchPointsConvertInfoData(query, requestOptions) {
  return fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.pointsConvertRecordDetail,
        data: query || {},
      },
      requestOptions,
    ),
    "积分转换详情加载失败",
  );
}

export async function fetchAssetHome(requestOptions) {
  const result = await Promise.all([
    fetchPriceData(requestOptions),
    fetchHomeBalanceData(requestOptions),
    fetchUserData(requestOptions),
  ]);
  const overview = buildHomeOverview(result[1], result[0], result[2]);
  setHomeTickerCache(overview.ticker);
  return overview;
}

export async function fetchVoucherBrokerLinkData(requestOptions) {
  const data = await fetchCoinIndexData(requestOptions);
  const userId = pickFirstValue(data, ["user_id", "uid", "id"]);
  const balance = pickFirstValue(data, ["balance", "coin", "total"]);

  if (userId === "") {
    throw createError("未获取到用户信息", data);
  }

  const targetUrl =
    serviceConfig.EXTERNAL_H5_HOST +
    "/JXH5/pages/users/user_broker/index?user_id=" +
    encodeURIComponent(String(userId)) +
    "&total=" +
    encodeURIComponent(balance === "" ? "0" : String(balance));
  const targetInfo = appendTokenToTargetUrl(targetUrl);

  return {
    userId: String(userId),
    balance: balance === "" ? "0" : String(balance),
    token: targetInfo.token,
    targetUrl: targetInfo.targetUrl,
    encodedTargetUrl: targetInfo.encodedTargetUrl,
  };
}

export async function fetchCouponRedeemLinkData(requestOptions) {
  const userInfo = await fetchUserProfileData(requestOptions);
  const canRedeem = pickFirstValue(userInfo, [
    "is_show_merchant_button",
    "canRedeem",
    "can_redeem",
  ]);
  const targetUrl =
    serviceConfig.EXTERNAL_H5_HOST +
    "/MD/pages/redeemVoucher/index?canRedeem=" +
    encodeURIComponent(canRedeem === "" ? "0" : String(canRedeem));
  const targetInfo = appendTokenToTargetUrl(targetUrl);

  return {
    canRedeem: canRedeem === "" ? "0" : String(canRedeem),
    token: targetInfo.token,
    targetUrl: targetInfo.targetUrl,
    encodedTargetUrl: targetInfo.encodedTargetUrl,
  };
}

export function fetchBalanceSpreadLinkData() {
  return appendTokenToTargetUrl(
    serviceConfig.EXTERNAL_H5_HOST +
      "/JXH5/pages/users/user_spread_money/index?type=2",
  );
}

export async function fetchPointsConvertHome(
  month,
  paginationOrRequestOptions,
  requestOptions,
) {
  const params = resolvePagingArguments(
    paginationOrRequestOptions,
    requestOptions,
  );
  const pagination = params.pagination;
  const mergedRequestOptions = params.requestOptions;
  const result = await Promise.all([
    fetchHomeBalanceData(mergedRequestOptions),
    fetchPointsConvertHistoryListData(month, pagination, mergedRequestOptions),
  ]);
  const balances = normalizeBalances(result[0]);
  const records = buildPointsHistoryRecords(result[1]).map(function (item) {
    return Object.assign({}, item, {
      month: extractMonthLabel(item.time) || month,
      detailAvailable: canOpenPointsConvertRecordDetail(item),
    });
  });

  return {
    availablePoints: formatHomeNumber(balances.points, 0),
    records: records,
    pagination: buildPaginationMeta(result[1], pagination),
  };
}

export async function fetchPointsConvertSelection(
  paginationOrRequestOptions,
  requestOptions,
) {
  const interval =
    paginationOrRequestOptions && typeof paginationOrRequestOptions === "object"
      ? paginationOrRequestOptions.interval
      : "";
  const params = resolvePagingArguments(
    paginationOrRequestOptions,
    requestOptions,
  );
  const data = await fetchPointsConvertList(
    params.pagination,
    params.requestOptions,
    interval,
  );
  const items = mapPointsConvertRecords(data);
  const pagination = buildPaginationMeta(data, params.pagination);

  return {
    items: items,
    pagination: pagination,
  };
}

export async function fetchPointsConvertRecordDetail(record, requestOptions) {
  const fallbackRecord = record || {};
  const query = {};

  if (fallbackRecord.sourceId) {
    query.id = fallbackRecord.sourceId;
  } else if (
    fallbackRecord.id &&
    fallbackRecord.orderSn &&
    fallbackRecord.id !== fallbackRecord.orderSn
  ) {
    query.id = fallbackRecord.id;
  }

  if (fallbackRecord.orderSn) {
    query.order_sn = fallbackRecord.orderSn;
    query.sn = fallbackRecord.orderSn;
  }

  if (!Object.keys(query).length) {
    return buildPointsConvertDetailFallback(fallbackRecord);
  }

  try {
    const data = await fetchPointsConvertInfoData(query, requestOptions);
    return buildPointsConvertDetailPayload(data, fallbackRecord);
  } catch (error) {
    return buildPointsConvertDetailFallback(fallbackRecord);
  }
}

export async function submitAssetPointsConvert(payload, requestOptions) {
  const ids = Array.isArray(payload && payload.ids) ? payload.ids : [];

  if (!ids.length) {
    throw createError("暂无可转换积分");
  }

  await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.pointsConvertSubmit,
        method: "POST",
        data: {
          ids: ids.join(","),
          type: 1,
        },
      },
      requestOptions,
    ),
    "积分转换失败",
  );

  return {
    success: true,
    message: "转换成功",
  };
}

export async function fetchTransferDetail(requestOptions) {
  const result = await Promise.all([
    fetchHomeBalanceData(requestOptions),
    fetchTransferFeeData(requestOptions),
    fetchTransferBmtrBalanceData(requestOptions),
    fetchTransferBmtrFeeData(requestOptions),
  ]);
  const balances = normalizeBalances(result[0]);
  const feePercent = toNumber(result[1] && result[1].r) || 10;
  const bmtrFeePercent = toNumber(result[3] && result[3].r) || 10;
  // 转赠数量只能为整数，余额向下取整展示，避免全部赠送时超出实际可用
  const bmtrBalance = Math.floor(
    toNumber(result[2] && result[2].balance),
  );

  return {
    balances: {
      points: toFixedNumber(balances.points, 0),
      power: toFixedNumber(balances.power, 0),
      bmtr: String(bmtrBalance),
    },
    feePercent: feePercent,
    bmtrFeePercent: bmtrFeePercent,
    tips: buildTransferTips(feePercent, bmtrFeePercent),
  };
}

export async function searchTransferUser(uid, requestOptions) {
  const keyword = String(uid || "").trim();
  if (!keyword) {
    throw createError("请输入被赠人ID");
  }

  const data = await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.transferUser,
        method: "POST",
        data: {
          uid: keyword,
        },
      },
      requestOptions,
    ),
    "查询好友失败",
  );

  return normalizeTransferTarget(data, keyword);
}

export async function submitAssetTransfer(payload, requestOptions) {
  const rawType = payload && payload.type;
  const transferType =
    rawType === "power" ? "power" : rawType === "bmtr" ? "bmtr" : "points";
  const targetId = String(
    payload && payload.targetId ? payload.targetId : "",
  ).trim();
  const amount = toNumber(payload && payload.amount);

  if (!targetId) {
    throw createError("请选择被赠送人");
  }

  if (!amount) {
    throw createError("请输入转赠数量");
  }

  const submitUrl =
    transferType === "power"
      ? serviceConfig.ENDPOINTS.transferPowerSubmit
      : transferType === "bmtr"
        ? serviceConfig.ENDPOINTS.transferBmtrSubmit
        : serviceConfig.ENDPOINTS.transferPointsSubmit;

  const result = await Promise.all([
    transferType === "bmtr"
      ? fetchTransferBmtrFeeData(requestOptions)
      : fetchTransferFeeData(requestOptions),
    fetchPayload(
      createRequestOptions(
        {
          url: submitUrl,
          method: "POST",
          data: {
            uid: targetId,
            number: String(amount),
          },
        },
        requestOptions,
      ),
      "转赠失败",
    ),
  ]);
  const feePercent = toNumber(result[0] && result[0].r) || 10;
  const fee = (amount * feePercent) / 100;
  const received = amount - fee;

  return {
    success: true,
    fee: toFixedNumber(fee, 2),
    received: toFixedNumber(received, 2),
  };
}

export async function fetchPowerExchangeDetail(requestOptions) {
  const result = await Promise.all([
    fetchPriceData(requestOptions),
    fetchHomeBalanceData(requestOptions),
    fetchPowerExchangeMuitData(requestOptions),
  ]);
  const ticker = normalizeTicker(result[0]);
  const balances = normalizeBalances(result[1]);
  const exchangeMultiplier = resolveRedeemPowerRate(result[2]) || 1;
  return {
    ticker: ticker,
    exchangeMultiplier: exchangeMultiplier,
    balances: {
      coupon: toFixedNumber(balances.coupon, 2),
      voucher: toFixedNumber(balances.voucher, 2),
      power: toFixedNumber(balances.power, 2),
      brokerage_price: toFixedNumber(balances.balance, 2),
    },
    tips: [
      "算力 = 输入数量 ÷ BMT实时价格",
      "兑换算力时所需的抵用券、消费券、余额。必须大于10的倍数",
      "算力用于兑换BMT使用",
    ],
  };
}

export async function submitAssetPowerExchange(payload, requestOptions) {
  const mode =
    payload && payload.mode === "coupon"
      ? "coupon"
      : payload && payload.mode === "balance"
        ? "balance"
        : "voucher";
  const amount = toNumber(payload && payload.amount);

  if (!amount) {
    throw createError("请输入兑换数量");
  }

  await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.powerExchangeSubmit,
        method: "POST",
        data: {
          type: mode === "coupon" ? 1 : mode === "balance" ? 2 : 0,
          number: String(amount),
        },
      },
      requestOptions,
    ),
    "算力兑换失败",
  );

  return {
    success: true,
  };
}

export async function fetchBmtFlashExchangeDetail(requestOptions) {
  const result = await Promise.all([
    fetchPriceData(requestOptions),
    fetchHomeBalanceData(requestOptions),
  ]);
  const ticker = normalizeTicker(result[0]);
  const balances = normalizeBalances(result[1]);

  setHomeTickerCache(ticker);

  return {
    ticker: ticker,
    balances: {
      bmt: toFixedNumber(balances.bmt, 2),
      coupon: toFixedNumber(balances.coupon, 2),
      voucher: toFixedNumber(balances.voucher, 2),
      brokerage_price: toFixedNumber(balances.balance, 2),
    },
    tips: [
      "BMT闪兑 = 输入数量 ÷ BMT实时价格",
      "BMT闪兑时所需的抵用券、消费券、余额。必须大于10的倍数。",
      "闪兑成功后数量将直接结算到可用BMT。",
    ],
  };
}

export async function submitAssetBmtFlashExchange(payload, requestOptions) {
  const mode =
    payload && payload.mode === "coupon"
      ? "coupon"
      : payload && payload.mode === "balance"
        ? "balance"
        : "voucher";
  const amount = toNumber(payload && payload.amount);

  if (!amount) {
    throw createError("请输入闪兑数量");
  }

  await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.bmtFlashExchangeSubmit,
        method: "POST",
        data: {
          type: mode === "coupon" ? 1 : mode === "balance" ? 2 : 0,
          number: String(amount),
        },
      },
      requestOptions,
    ),
    "BMT闪兑失败",
  );

  return {
    success: true,
  };
}

// BMT兑换
export async function fetchBmtExchangeDetail(requestOptions) {
  const result = await Promise.all([
    fetchHomeBalanceData(requestOptions),
    fetchBmtPowerRateData(requestOptions),
  ]);

  const ticker = getHomeTickerCache();
  const balances = normalizeBalances(result[0]);
  const powerRate = resolveRedeemPowerRate(result[1]);

  return {
    ticker: ticker,
    powerRate: powerRate,
    balances: {
      points: balances.points,
      power: balances.power,
      bmt: balances.bmt,
      voucher: balances.voucher,
      coupon: balances.coupon,
    },
    tips: [
      "预估 BMT数= 输入可用积分数÷BMT 实时价格。",
      `兑换会同步消耗算力， 1 点可用积分，需同步消耗${powerRate}点算力。`,
      "仅支持 100 的正整数倍， 不足 100的可用积分无法发起兑换。",
      "凌晨00:00至02:00为积分维护时段，期间暂停兑换服务，请避开该时间段操作。",
    ],
  };
}

export async function submitAssetBmtExchange(payload, requestOptions) {
  const amount = toNumber(payload && payload.amount);

  if (!amount) {
    throw createError("请输入积分数量");
  }

  await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.bmtExchangeSubmit,
        method: "POST",
        data: {
          number: String(amount),
        },
      },
      requestOptions,
    ),
    "BMT兑换失败",
  );

  return {
    success: true,
  };
}

export async function fetchWithdrawDetail(requestOptions) {
  const result = await Promise.all([
    fetchPriceData(requestOptions),
    fetchHomeBalanceData(requestOptions),
    fetchWalletAddressData(requestOptions),
    fetchWithdrawRateData(requestOptions),
  ]);
  const ticker = normalizeTicker(result[0]);
  const balances = normalizeBalances(result[1]);
  const walletPayload = buildWalletPayload(result[2] && result[2].address);
  const withdrawRate = resolvePercentRate(result[3]);

  setHomeTickerCache(ticker);

  return {
    ticker: ticker,
    withdrawableBmt: toFixedNumber(balances.withdrawableBmt, 2),
    withdrawRate: withdrawRate,
    balances: {
      voucher: balances.voucher,
      coupon: balances.coupon,
      brokerage_price: toFixedNumber(balances.balance, 2),
    },
    wallets: walletPayload.wallets,
    defaultWallet: walletPayload.wallets[0] || null,
  };
}

export async function submitAssetWithdraw(payload, requestOptions) {
  const address = String(
    payload && payload.address ? payload.address : "",
  ).trim();
  const amount = toNumber(payload && payload.amount);

  if (!address) {
    throw createError("请先添加钱包地址");
  }

  if (!amount) {
    throw createError("请输入提取数量");
  }

  await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.withdrawSubmit,
        method: "POST",
        data: {
          address: address,
          number: String(amount),
        },
      },
      requestOptions,
    ),
    "提取失败",
  );

  return {
    success: true,
  };
}

export async function fetchLedgerDetail(
  type,
  paginationOrRequestOptions,
  requestOptions,
) {
  const params = resolvePagingArguments(
    paginationOrRequestOptions,
    requestOptions,
  );
  const pagination = params.pagination;
  const mergedRequestOptions = params.requestOptions;

  if (type === "transfer") {
    const data = await fetchTransferLedgerData(
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "转赠记录",
      subtitle: "可用积分与算力转赠流水",
      records: mapTransferRecords(normalizeListData(data)),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  if (type === "bmtr-transfer") {
    const data = await fetchBmtrTransferLedgerData(
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "转赠记录",
      subtitle: "BMTR转赠流水",
      records: mapBmtrTransferRecords(data),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  if (type === "points") {
    const data = await fetchWalletFlowListData(
      0,
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "可用积分记录",
      subtitle: "可用积分收支记录",
      records: mapWalletFlowRecords(data, {
        key: "points",
        unit: "可用积分",
        title: "可用积分记录",
        subtitle: "可用积分流水",
      }),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  if (type === "power-flow") {
    const data = await fetchWalletFlowListData(
      1,
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "算力记录",
      subtitle: "算力收支记录",
      records: mapWalletFlowRecords(data, {
        key: "power-flow",
        unit: "算力",
        title: "算力记录",
        subtitle: "算力流水",
      }),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  if (type === "power") {
    const data = await fetchRedeemRecordListData(
      0,
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "兑换记录",
      subtitle: "算力兑换记录",
      records: mapRedeemRecords(data, {
        key: "power",
        type: 0,
        unit: "算力",
        title: "兑换算力",
        subtitle: "算力兑换",
        amountKeys: [
          "num",
          "number",
          "power",
          "power_num",
          "c_power",
          "redeem_power",
        ],
      }),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  if (type === "bmt") {
    const data = await fetchRedeemRecordListData(
      1,
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "兑换记录",
      subtitle: "BMT兑换记录",
      records: mapRedeemRecords(data, {
        key: "bmt",
        type: 1,
        unit: "BMT",
        title: "兑换BMT",
        subtitle: "BMT兑换",
        amountKeys: ["bmt", "bmt_num", "redeem_bmt", "num", "number"],
      }),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  if (type === "bmt-flash") {
    const data = await fetchRedeemRecordListData(
      1,
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "闪兑记录",
      subtitle: "BMT闪兑记录",
      records: mapRedeemRecords(data, {
        key: "bmt-flash",
        type: 1,
        unit: "BMT",
        title: "闪兑BMT",
        subtitle: "BMT闪兑",
        amountKeys: ["bmt", "bmt_num", "redeem_bmt", "num", "number"],
      }),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  if (type === "withdraw") {
    const data = await fetchWalletFlowListData(
      2,
      pagination,
      mergedRequestOptions,
    );
    return {
      type: type,
      title: "提取记录",
      subtitle: "BMT收支记录",
      records: mapWalletFlowRecords(data, {
        key: "withdraw",
        unit: "BMT",
        title: "BMT记录",
        subtitle: "BMT流水",
      }),
      pagination: buildPaginationMeta(data, pagination),
    };
  }

  const homeData = await fetchHomeBalanceData(mergedRequestOptions);
  const balances = normalizeBalances(homeData);
  return Object.assign({}, buildDefaultLedger(type, balances), {
    pagination: {
      page: pagination.page,
      pageSize: pagination.pageSize,
      total: 0,
      lastPage: 0,
      hasMore: false,
    },
  });
}

export async function fetchBalanceCenterPage(
  filters,
  paginationOrRequestOptions,
  requestOptions,
) {
  const params = resolvePagingArguments(
    paginationOrRequestOptions,
    requestOptions,
  );
  const pagination = params.pagination;
  const mergedRequestOptions = params.requestOptions;
  const [summaryData, listData] = await Promise.all([
    fetchExtractBankData(mergedRequestOptions),
    fetchSpreadCommissionListData(
      3,
      pagination,
      mergedRequestOptions,
      filters,
    ),
  ]);

  return {
    summary: {
      balance: formatTransferRecordNumber(
        pickFirstValue(summaryData, ["brokerage_price", "balance"]),
      ),
      totalExtract: formatTransferRecordNumber(
        pickFirstValue(summaryData, [
          "extractTotalPrice",
          "extract_total_price",
          "total_extract",
        ]),
      ),
      frozen: formatTransferRecordNumber(
        pickFirstValue(summaryData, [
          "broken_commission",
          "frozen_amount",
          "frozen",
        ]),
      ),
    },
    sections: mapBalanceCenterSections(listData),
    pagination: buildPaginationMeta(listData, pagination),
  };
}

export async function fetchVoucherCenterPage(
  tabKey,
  paginationOrRequestOptions,
  requestOptions,
) {
  const params = resolvePagingArguments(
    paginationOrRequestOptions,
    requestOptions,
  );
  const pagination = params.pagination;
  const mergedRequestOptions = params.requestOptions;
  const tabFilters = resolveVoucherTabFilters(tabKey);
  const [summaryData, listData] = await Promise.all([
    fetchCoinIndexSummaryData(
      {
        sign: 1,
        integral: 1,
        all: 1,
      },
      mergedRequestOptions,
    ),
    fetchCoinReleaseListData(pagination, mergedRequestOptions, tabFilters),
  ]);

  return {
    currentTab: tabFilters.tabKey,
    summary: {
      balance: formatTransferRecordNumber(
        pickFirstValue(summaryData, ["balance", "coin", "total"]),
      ),
      totalIn: formatTransferRecordNumber(
        pickFirstValue(summaryData, ["total_in", "totalIn"]),
      ),
      totalOut: formatTransferRecordNumber(
        pickFirstValue(summaryData, ["total_out", "totalOut"]),
      ),
    },
    sections: mapVoucherCenterSections(listData),
    pagination: buildPaginationMeta(listData, pagination),
  };
}

export async function fetchWalletDetail(requestOptions) {
  const data = await fetchWalletAddressData(requestOptions);
  return buildWalletPayload(data && data.address);
}

export async function saveAssetWallet(payload, requestOptions) {
  const address = String(
    payload && payload.address ? payload.address : "",
  ).trim();

  if (!address) {
    throw createError("请输入钱包地址");
  }

  await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.walletSave,
        method: "POST",
        data: {
          address: address,
        },
      },
      requestOptions,
    ),
    "保存失败",
  );

  return {
    success: true,
  };
}

export async function deleteAssetWallet(id, requestOptions) {
  await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.walletSave,
        method: "POST",
        data: {
          address: "",
        },
      },
      requestOptions,
    ),
    "删除失败",
  );

  return {
    success: true,
  };
}

function padTimeUnit(value) {
  return value < 10 ? "0" + value : String(value);
}

function formatTimestamp(timestamp) {
  const seconds = toNumber(timestamp);

  if (!seconds) {
    return "";
  }

  const date = new Date(seconds * 1000);

  return (
    date.getFullYear() +
    "-" +
    padTimeUnit(date.getMonth() + 1) +
    "-" +
    padTimeUnit(date.getDate()) +
    " " +
    padTimeUnit(date.getHours()) +
    ":" +
    padTimeUnit(date.getMinutes()) +
    ":" +
    padTimeUnit(date.getSeconds())
  );
}

function mapBmtrRecords(list) {
  return normalizeListData(list).map(function (item) {
    const amountValue = toNumber(item && item.bmtr);
    // 交易类型：0 支出，1 收入，2 退回
    const bmtrType = Number(item && item.bmtr_type);
    const isIncome = bmtrType === 1 || bmtrType === 2;

    return {
      id: buildRecordId(item, "bmtr"),
      title: String(pickFirstValue(item, ["bmtr_type_tips", "title"]) || "BMTR记录"),
      time: formatTimestamp(item && item.add_time),
      amount: isIncome ? Math.abs(amountValue) : -Math.abs(amountValue),
      orderSn: String(pickFirstValue(item, ["order_sn", "sn"]) || ""),
    };
  });
}

export async function fetchBmtrDetail(requestOptions) {
  const data = await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.bmtrMonthPoints,
      },
      requestOptions,
    ),
    "BMTR信息加载失败",
  );
  const bmtrValue = pickFirstValue(data, ["bmtr"]);

  return {
    available: bmtrValue === "" ? "0.0000" : String(bmtrValue),
    address: String(pickFirstValue(data, ["address"]) || ""),
  };
}

export async function fetchBmtrRecords(
  paginationOrRequestOptions,
  requestOptions,
) {
  const params = resolvePagingArguments(
    paginationOrRequestOptions,
    requestOptions,
  );
  const data = await fetchPayload(
    createRequestOptions(
      {
        url: serviceConfig.ENDPOINTS.bmtrChargeList,
        data: buildPagingRequestData({}, params.pagination),
      },
      params.requestOptions,
    ),
    "BMTR记录加载失败",
  );

  return {
    records: mapBmtrRecords(data),
    pagination: buildPaginationMeta(data, params.pagination),
  };
}
