import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
import { fetchPlatformGrantRecords, fetchPlatformGrantUsers } from "../api.js";
import { EChart } from "../charts/EChart.jsx";
import { createReportRevenueOption } from "../charts/options/createReportRevenueOption.js";
import { formatCoin, formatMoneyFull, formatPercent } from "../utils/format.js";

const textCollator = new Intl.Collator("zh-Hans", { numeric: true, sensitivity: "base" });

const reportTabs = [
  { key: "country", label: "国家经营报表" },
  { key: "revenue", label: "收入趋势" },
  { key: "gift", label: "礼物消费" },
  { key: "lucky", label: "幸运礼物" },
  { key: "game", label: "游戏流水" },
  { key: "robot", label: "机器人送礼" }
];

const platformGrantRecordSourceOptions = [
  { label: "全部来源", value: "all" },
  { label: "任务奖励", value: "WalletTaskRewardCredited" },
  { label: "房间流水奖励", value: "WalletRoomTurnoverRewardCredited" },
  { label: "邀请活动奖励", value: "WalletInviteActivityRewardCredited" },
  { label: "代理开通奖励", value: "WalletAgencyOpeningRewardCredited" },
  { label: "资源发放", value: "WalletBalanceChanged" },
  { label: "平台发放", value: "WalletPlatformGrantCoinCredited" }
];

const countryColumns = [
  { align: "left", key: "date_label", label: "日期", render: (row) => <DateCell row={row} />, sortable: false, stickyLeft: true },
  { align: "left", key: "country", label: "国家", render: (row) => <CountryCell row={row} />, sortable: false },
  { key: "registrations", label: "注册", render: (row) => formatOptionalCoin(row.registrations), sortable: false },
  { key: "active_users", label: "活跃用户", render: (row) => formatOptionalCoin(row.active_users), sortable: false },
  { key: "paid_users", label: "付费用户", render: (row) => formatOptionalCoin(row.paid_users), sortable: false },
  { key: "recharge_users", label: "充值用户", render: (row) => formatOptionalCoin(row.recharge_users), sortable: false },
  { key: "recharge_usd_minor", label: "总充值", render: (row) => formatOptionalMoney(row.recharge_usd_minor), sortable: false },
  { key: "new_user_recharge_usd_minor", label: "新用户充值", render: (row) => formatOptionalMoney(row.new_user_recharge_usd_minor), sortable: false },
  { key: "coin_seller_recharge_usd_minor", label: "币商充值", render: (row) => formatOptionalMoney(row.coin_seller_recharge_usd_minor), sortable: false },
  { key: "coin_seller_stock_coin", label: "币商充值金币", render: (row) => formatOptionalCoin(row.coin_seller_stock_coin), sortable: false },
  { key: "coin_seller_transfer_coin", label: "币商出货金币", render: (row) => formatOptionalCoin(row.coin_seller_transfer_coin), sortable: false },
  { key: "google_recharge_usd_minor", label: "谷歌充值", render: (row) => formatOptionalMoney(row.google_recharge_usd_minor), sortable: false },
  { key: "mifapay_recharge_usd_minor", label: "三方充值", render: (row) => formatOptionalMoney(row.mifapay_recharge_usd_minor), sortable: false },
  { key: "game_turnover", label: "游戏流水/利润率", render: (row) => <FlowRateCell rate={row.game_profit_rate} value={row.game_turnover} />, sortable: false },
  { key: "lucky_gift_turnover", label: "幸运礼物流水/利润率", render: (row) => <FlowRateCell rate={row.lucky_gift_profit_rate} value={row.lucky_gift_turnover} />, sortable: false },
  { key: "super_lucky_gift_turnover", label: "超级幸运礼物流水/利润率", render: (row) => <FlowRateCell rate={row.super_lucky_gift_profit_rate} value={row.super_lucky_gift_turnover} />, sortable: false },
  { key: "gift_coin_spent", label: "礼物流水", render: (row) => formatOptionalCoin(row.gift_coin_spent), sortable: false },
  { key: "coin_total", label: "用户金币数", render: (row) => formatOptionalCoin(row.coin_total), sortable: false },
  { key: "consumed_coin", label: "消耗金币", render: (row) => formatOptionalCoin(row.consumed_coin), sortable: false },
  { key: "output_coin", label: "产出金币", render: (row) => formatOptionalCoin(row.output_coin), sortable: false },
  { key: "consume_output_ratio", label: "消耗产出比", render: (row) => <ConsumeOutputCell row={row} />, sortable: false },
  { key: "platform_grant_coin", label: "平台发放金币", render: (row, context) => <PlatformGrantCoinCell context={context} row={row} />, sortable: false },
  { key: "manual_grant_coin", label: "人工发放金币", render: (row) => formatOptionalCoin(row.manual_grant_coin), sortable: false },
  { key: "salary_usd_minor", label: "工资总和(主播/代理)", render: (row) => formatOptionalMoney(row.salary_usd_minor), sortable: false },
  { key: "salary_transfer_coin", label: "工资兑换金币", render: (row) => formatOptionalCoin(row.salary_transfer_coin), sortable: false },
  { key: "avg_mic_online_ms", label: "平均麦上时间", render: (row) => formatDuration(row.avg_mic_online_ms), sortable: false },
  { key: "mic_online_ms", label: "麦上总时长", render: (row) => formatDuration(row.mic_online_ms), sortable: false },
  { key: "arpu_usd_minor", label: "ARPU", render: (row) => formatOptionalMoney(row.arpu_usd_minor), sortable: false },
  { key: "arppu_usd_minor", label: "ARPPU", render: (row) => formatOptionalMoney(row.arppu_usd_minor), sortable: false },
  { key: "payer_rate", label: "付费转化率", render: (row) => formatOptionalPercent(row.payer_rate), sortable: false },
  { key: "recharge_conversion_rate", label: "充值转化率", render: (row) => formatOptionalPercent(row.recharge_conversion_rate), sortable: false }
];

const countryDetailColumns = countryColumns.filter((column) => column.key !== "date_label");

const revenueColumns = [
  { align: "left", key: "label", label: "日期", render: (row) => row.label, sortValue: (row) => row.label, type: "text" },
  { key: "google", label: "Google", render: (row) => formatMoneyFull(row.google) },
  { key: "mifapay", label: "MifaPay", render: (row) => formatMoneyFull(row.mifapay) },
  { key: "coin_seller", label: "币商", render: (row) => formatMoneyFull(row.coin_seller) },
  { key: "total", label: "渠道合计", render: (row) => formatMoneyFull(row.total) },
  { key: "lineTotal", label: "总计", render: (row) => formatMoneyFull(row.lineTotal ?? row.total) }
];

const giftColumns = [
  { align: "left", key: "name", label: "礼物", render: (row) => row.name, sortValue: (row) => row.name, type: "text" },
  { key: "value", label: "金币消费", render: (row) => formatCoin(row.value) },
  { key: "share", label: "占比", render: (row) => formatPercent(row.share) },
  { key: "trend_rate", label: "近 7 日", render: (row) => <TrendValue value={row.trend_rate} /> }
];

const luckyColumns = [
  { align: "left", key: "pool_id", label: "奖池", render: (row) => row.pool_id, sortValue: (row) => row.pool_id, type: "text" },
  { key: "turnover", label: "流水", render: (row) => formatCoin(row.turnover) },
  { key: "payout", label: "返奖", render: (row) => formatCoin(row.payout) },
  { key: "profit", label: "利润", render: (row) => formatCoin(row.profit) },
  { key: "payout_rate", label: "返奖率", render: (row) => formatPercent(row.payout_rate) },
  { key: "profit_rate", label: "利润率", render: (row) => formatPercent(row.profit_rate) }
];

const gameColumns = [
  { align: "left", key: "game_id", label: "游戏", render: (row) => row.game_label || row.game_id, sortValue: (row) => row.game_label || row.game_id, type: "text" },
  { key: "turnover_coin", label: "流水 (金币)", render: (row) => formatCoin(row.turnover_coin) },
  { key: "profit_rate", label: "利润率", render: (row) => formatPercent(row.profit_rate) },
  { key: "share", label: "占比", render: (row) => formatPercent(row.share) }
];

const metricColumns = [
  { align: "left", key: "label", label: "指标", render: (row) => row.label, sortValue: (row) => row.label, type: "text" },
  { key: "value", label: "数值", render: (row) => row.value, sortable: false },
  { key: "unit", label: "单位", render: (row) => row.unit || "--", sortable: false },
  { key: "caption", label: "对比口径", render: (row) => row.caption || "--", sortable: false },
  { key: "delta", label: "变化", render: (row) => <DeltaText value={row.delta} />, sortable: false }
];

export function ReportOverview({ grantDrilldownQuery, loading = false, model, onMetricTrend, onOpenLuckyGiftPools }) {
  const [activeTab, setActiveTab] = useState("country");
  const summaryCards = useMemo(() => createSummaryCards(model), [model]);

  return (
    <section className="databi-report" aria-label="数据报表">
      <section className="report-metric-grid" aria-label="核心经营指标">
        {summaryCards.map((card) => (
          <ReportMetricCard card={card} key={card.title} loading={loading} onOpenTrend={onMetricTrend} />
        ))}
      </section>

      <section className="report-workbench">
        <div className="report-tabs" role="tablist" aria-label="报表切换">
          {reportTabs.map((tab) => (
            <button
              aria-selected={activeTab === tab.key}
              className={activeTab === tab.key ? "is-active" : ""}
              key={tab.key}
              role="tab"
              type="button"
              onClick={() => setActiveTab(tab.key)}
            >
              {tab.label}
            </button>
          ))}
        </div>
        <div className="report-tab-panel" role="tabpanel">
          {activeTab === "country" ? <CountryReport grantDrilldownQuery={grantDrilldownQuery} loading={loading} rows={model.reportCountryRows} /> : null}
          {activeTab === "revenue" ? <RevenueReport loading={loading} rows={model.revenueSeries} /> : null}
          {activeTab === "gift" ? <GiftReport loading={loading} metrics={model.businessKpis} rows={model.giftRanking} /> : null}
          {activeTab === "lucky" ? <LuckyReport loading={loading} metrics={model.businessKpis} onOpenLuckyGiftPools={onOpenLuckyGiftPools} rows={model.luckyGiftPools} /> : null}
          {activeTab === "game" ? <GameReport loading={loading} metrics={model.businessKpis} rows={model.gameRanking} /> : null}
          {activeTab === "robot" ? <RobotReport loading={loading} rows={model.robotGiftKpis} /> : null}
        </div>
      </section>
    </section>
  );
}

function ReportMetricCard({ card, loading, onOpenTrend }) {
  const clickable = Boolean(card.trendMetric?.trend?.length && onOpenTrend);
  if (loading) {
    return (
      <article className="report-metric-card is-loading" aria-busy="true">
        <span className="skeleton-block report-skeleton-title" />
        <span className="skeleton-block report-skeleton-value" />
        <span className="skeleton-block report-skeleton-line" />
        <span className="skeleton-block report-skeleton-line report-skeleton-line--short" />
      </article>
    );
  }

  return (
    <article
      className={["report-metric-card", clickable ? "report-metric-card--clickable" : ""].filter(Boolean).join(" ")}
      role={clickable ? "button" : undefined}
      tabIndex={clickable ? 0 : undefined}
      onClick={clickable ? () => onOpenTrend(card.trendMetric) : undefined}
      onKeyDown={clickable ? (event) => {
        if (event.key === "Enter" || event.key === " ") {
          event.preventDefault();
          onOpenTrend(card.trendMetric);
        }
      } : undefined}
    >
      <div className="report-metric-head">
        <span>{card.title}</span>
        {card.delta ? <DeltaText value={card.delta} /> : null}
      </div>
      <strong>{card.value}</strong>
      <div className="report-metric-detail-grid">
        {card.details.filter((detail) => detail.label !== card.title).map((detail) => (
          <span className="report-metric-detail" key={detail.label}>
            <small>{detail.label}</small>
            <b>{detail.value}</b>
          </span>
        ))}
      </div>
    </article>
  );
}

function CountryReport({ grantDrilldownQuery, loading, rows }) {
  const [expandedRowIds, setExpandedRowIds] = useState(() => new Set());
  const [grantCountryModal, setGrantCountryModal] = useState(null);
  const [grantUsersModal, setGrantUsersModal] = useState(null);
  const [grantRecordsModal, setGrantRecordsModal] = useState(null);
  const toggleRow = useCallback((rowId) => {
    setExpandedRowIds((current) => {
      const next = new Set(current);
      if (next.has(rowId)) {
        next.delete(rowId);
      } else {
        next.add(rowId);
      }
      return next;
    });
  }, []);
  const tableRows = useMemo(() => rows.map((row) => {
    const children = Array.isArray(row.children) ? row.children : [];
    if (row.row_type !== "date_total" || !children.length) {
      return row;
    }
    return {
      ...row,
      expanded: expandedRowIds.has(row.row_id),
      onToggle: () => toggleRow(row.row_id)
    };
  }), [expandedRowIds, rows, toggleRow]);
  const openGrantUsers = useCallback((row) => {
    setGrantCountryModal(null);
    setGrantRecordsModal(null);
    setGrantUsersModal({
      countryLabel: row.country || "国家",
      query: buildPlatformGrantQuery(grantDrilldownQuery, row)
    });
  }, [grantDrilldownQuery]);
  const openGrantCountries = useCallback((row) => {
    const countryRows = platformGrantCountryRows(row, rows);
    if (!countryRows.length) {
      return;
    }
    setGrantRecordsModal(null);
    setGrantUsersModal(null);
    setGrantCountryModal({
      rows: countryRows,
      title: row.row_type === "date_total" ? `${row.date_label} 平台发放金币` : "平台发放金币"
    });
  }, [rows]);
  const grantContext = useMemo(() => ({
    onOpenPlatformGrantCountries: openGrantCountries,
    onOpenPlatformGrantUsers: openGrantUsers
  }), [openGrantCountries, openGrantUsers]);

  return (
    <ReportPanel>
      <ReportTable
        columns={countryColumns}
        context={grantContext}
        loading={loading}
        preserveOrder
        renderExpandedRow={(row) => <CountryDetailTable context={grantContext} dateLabel={row.date_label} rows={row.children || []} />}
        rows={tableRows}
        wide
      />
      {grantCountryModal ? (
        <PlatformGrantCountryModal
          modal={grantCountryModal}
          onClose={() => setGrantCountryModal(null)}
          onOpenUsers={openGrantUsers}
        />
      ) : null}
      {grantUsersModal ? (
        <PlatformGrantUsersModal
          modal={grantUsersModal}
          onClose={() => setGrantUsersModal(null)}
          onOpenRecords={(userRow) => setGrantRecordsModal({
            countryLabel: grantUsersModal.countryLabel,
            query: { ...grantUsersModal.query, userId: userRow.user_id },
            user: userRow
          })}
        />
      ) : null}
      {grantRecordsModal ? (
        <PlatformGrantRecordsModal
          modal={grantRecordsModal}
          onClose={() => setGrantRecordsModal(null)}
        />
      ) : null}
    </ReportPanel>
  );
}

function RevenueReport({ loading, rows }) {
  return (
    <ReportPanel>
      {loading ? (
        <div className="report-chart-skeleton" aria-busy="true">
          <span className="skeleton-block report-skeleton-line" />
          <span className="skeleton-block report-skeleton-chart" />
        </div>
      ) : rows.length ? (
        <EChart className="report-revenue-chart" option={createReportRevenueOption(rows)} />
      ) : (
        <div className="report-empty">当前无数据</div>
      )}
      <ReportTable columns={revenueColumns} defaultSort={{ direction: "asc", key: "label", type: "text" }} loading={loading} rows={rows} />
    </ReportPanel>
  );
}

function GiftReport({ loading, metrics, rows }) {
  const total = rows.reduce((sum, row) => sum + Number(row.value || 0), 0) || 1;
  const giftRows = rows.map((row) => ({ ...row, share: Number(row.value || 0) / total }));
  return (
    <ReportPanel>
      <ReportMetricTable loading={loading} rows={metrics.filter((item) => item.label.includes("礼物") || item.label.includes("币商"))} />
      <ReportTable columns={giftColumns} defaultSort={{ direction: "desc", key: "value", type: "number" }} loading={loading} rows={giftRows} />
    </ReportPanel>
  );
}

function LuckyReport({ loading, metrics, onOpenLuckyGiftPools, rows }) {
  return (
    <ReportPanel
      action={(
        <button className="report-panel-action" disabled={!rows.length} type="button" onClick={onOpenLuckyGiftPools}>
          查看奖池明细
        </button>
      )}
    >
      <ReportMetricTable loading={loading} rows={metrics.filter((item) => item.label.includes("幸运礼物"))} />
      <ReportTable columns={luckyColumns} defaultSort={{ direction: "desc", key: "turnover", type: "number" }} loading={loading} rows={rows} />
    </ReportPanel>
  );
}

function GameReport({ loading, metrics, rows }) {
  const total = rows.reduce((sum, row) => sum + Number(row.turnover_coin || 0), 0) || 1;
  const gameRows = rows.map((row) => ({ ...row, share: Number(row.turnover_coin || 0) / total }));
  return (
    <ReportPanel>
      <ReportMetricTable loading={loading} rows={metrics.filter((item) => item.label.includes("游戏"))} />
      <ReportTable columns={gameColumns} defaultSort={{ direction: "desc", key: "turnover_coin", type: "number" }} loading={loading} rows={gameRows} />
    </ReportPanel>
  );
}

function RobotReport({ loading, rows }) {
  return (
    <ReportPanel>
      <ReportMetricTable loading={loading} rows={rows} />
    </ReportPanel>
  );
}

function ReportPanel({ action, children }) {
  return (
    <section className="report-panel">
      {action ? <div className="report-panel-head">{action}</div> : null}
      {children}
    </section>
  );
}

function ReportMetricTable({ loading, rows }) {
  return (
    <div className="report-metric-table-block">
      <ReportTable columns={metricColumns} loading={loading} rows={rows} />
    </div>
  );
}

function ReportTable({ columns, context, defaultSort, loading, preserveOrder = false, renderExpandedRow, rows, wide = false }) {
  const sortableDefault = defaultSort || firstSortableColumn(columns);
  const [sortState, setSortState] = useState(sortableDefault);
  const sortedRows = useMemo(() => preserveOrder ? rows : sortRows(rows, sortState, columns), [columns, preserveOrder, rows, sortState]);

  const handleSort = (column) => {
    if (preserveOrder || column.sortable === false) {
      return;
    }
    setSortState((current) => ({
      direction: current?.key === column.key && current.direction === "desc" ? "asc" : "desc",
      key: column.key,
      type: column.type || "number"
    }));
  };

  return (
    <div className="report-table-wrap">
      <table className={["report-table", wide ? "report-table--wide" : ""].filter(Boolean).join(" ")}>
        <thead>
          <tr>
            <th>#</th>
            {columns.map((column) => {
              const isSortable = !preserveOrder && column.sortable !== false;
              const isActive = sortState?.key === column.key;
              const headerClassName = [
                isSortable ? "is-sortable" : "",
                column.stickyLeft ? "is-sticky-left" : ""
              ].filter(Boolean).join(" ");
              return (
                <th className={headerClassName} key={column.key}>
                  {isSortable ? (
                    <button
                      className={["report-sort-button", column.align === "left" ? "report-sort-button--left" : "", isActive ? "is-active" : ""].filter(Boolean).join(" ")}
                      type="button"
                      onClick={() => handleSort(column)}
                    >
                      <span>{column.label}</span>
                      <i>{isActive ? (sortState.direction === "asc" ? "↑" : "↓") : "↕"}</i>
                    </button>
                  ) : (
                    column.label
                  )}
                </th>
              );
            })}
          </tr>
        </thead>
        <tbody>
          {loading ? <ReportSkeletonRows colSpan={columns.length + 1} /> : null}
          {!loading && !rows.length ? <ReportEmptyRow colSpan={columns.length + 1} /> : null}
          {!loading && sortedRows.map((row, index) => {
            const key = reportRowKey(row, index);
            const rowProps = reportTableRowProps(row);
            const { className: rowClassName, ...interactiveRowProps } = rowProps;
            return (
              <Fragment key={key}>
                <tr
                  {...interactiveRowProps}
                  className={[reportRowClass(row), rowClassName].filter(Boolean).join(" ")}
                >
                  <td>{reportRowIndex(row, index)}</td>
                  {columns.map((column) => (
                    <td
                      className={[
                        column.align === "left" ? "is-left" : "",
                        column.stickyLeft ? "is-sticky-left" : ""
                      ].filter(Boolean).join(" ")}
                      key={column.key}
                    >
                      {column.render ? column.render(row, context) : row[column.key]}
                    </td>
                  ))}
                </tr>
                {row.expanded && renderExpandedRow ? (
                  <tr className="report-row-expanded-detail">
                    <td colSpan={columns.length + 1}>{renderExpandedRow(row)}</td>
                  </tr>
                ) : null}
              </Fragment>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

function CountryDetailTable({ context, dateLabel, rows }) {
  if (!rows.length) {
    return <div className="report-subtable-empty">当前无数据</div>;
  }
  return (
    <div className="report-subtable-wrap">
      <table aria-label={`${dateLabel || "日期"} 国家明细`} className="report-table report-subtable">
        <thead>
          <tr>
            <th>#</th>
            {countryDetailColumns.map((column) => (
              <th key={column.key}>{column.label}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((row, index) => (
            <tr key={reportRowKey(row, index)}>
              <td>{index + 1}</td>
              {countryDetailColumns.map((column) => (
                <td className={column.align === "left" ? "is-left" : ""} key={column.key}>{column.render ? column.render(row, context) : row[column.key]}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function PlatformGrantCoinCell({ context, row }) {
  const value = Number(row.platform_grant_coin || 0);
  const clickable = value > 0 && (row.row_type === "country" ? context?.onOpenPlatformGrantUsers : context?.onOpenPlatformGrantCountries);
  if (!clickable) {
    return formatOptionalCoin(row.platform_grant_coin);
  }
  const label = row.row_type === "country"
    ? `查看 ${row.country || "国家"} 平台发放金币用户明细`
    : `查看 ${row.date_label || "全部"} 平台发放金币国家明细`;
  return (
    <button
      aria-label={label}
      className="report-link-button"
      type="button"
      onClick={(event) => {
        event.stopPropagation();
        if (row.row_type === "country") {
          context.onOpenPlatformGrantUsers(row);
          return;
        }
        context.onOpenPlatformGrantCountries(row);
      }}
    >
      {formatCoin(value)}
    </button>
  );
}

function PlatformGrantCountryModal({ modal, onClose, onOpenUsers }) {
  return (
    <ReportDialog title={modal.title} onClose={onClose}>
      <div className="report-modal-table-wrap">
        <table className="report-modal-table">
          <thead>
            <tr>
              <th>国家</th>
              <th>平台发放金币</th>
            </tr>
          </thead>
          <tbody>
            {modal.rows.length ? modal.rows.map((row) => (
              <tr key={reportRowKey(row, row.country_id || row.country)}>
                <td>
                  <button
                    aria-label={`查看 ${row.country || "国家"} 平台发放金币用户明细`}
                    className="report-link-button report-link-button--left"
                    type="button"
                    onClick={() => onOpenUsers(row)}
                  >
                    <CountryCell row={row} />
                  </button>
                </td>
                <td>{formatOptionalCoin(row.platform_grant_coin)}</td>
              </tr>
            )) : (
              <tr className="report-table-empty-row"><td colSpan={2}>当前无数据</td></tr>
            )}
          </tbody>
        </table>
      </div>
    </ReportDialog>
  );
}

function PlatformGrantUsersModal({ modal, onClose, onOpenRecords }) {
  const pageSize = 20;
  const [page, setPage] = useState(1);
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  useEffect(() => {
    let active = true;
    setLoading(true);
    setError("");
    fetchPlatformGrantUsers({ ...modal.query, page, pageSize })
      .then((nextData) => {
        if (active) {
          setData(nextData || {});
        }
      })
      .catch((err) => {
        if (active) {
          setError(err.message || "请求失败");
          setData(null);
        }
      })
      .finally(() => {
        if (active) {
          setLoading(false);
        }
      });
    return () => {
      active = false;
    };
  }, [modal.query, page]);
  const items = Array.isArray(data?.items) ? data.items : [];
  const total = Number(data?.total || 0);

  return (
    <ReportDialog title={`${modal.countryLabel} 平台发放金币用户`} onClose={onClose}>
      <div className="report-modal-table-wrap">
        <table className="report-modal-table">
          <thead>
            <tr>
              <th>用户</th>
              <th>平台发放金币</th>
              <th>记录数</th>
              <th>最近发放时间</th>
            </tr>
          </thead>
          <tbody>
            {loading ? <tr className="report-table-skeleton-row"><td colSpan={4}><span className="skeleton-block report-skeleton-line" /></td></tr> : null}
            {!loading && error ? <tr className="report-table-empty-row"><td colSpan={4}>{error}</td></tr> : null}
            {!loading && !error && !items.length ? <tr className="report-table-empty-row"><td colSpan={4}>当前无数据</td></tr> : null}
            {!loading && !error ? items.map((item) => {
              const openRecords = () => onOpenRecords(item);
              return (
                <tr
                  aria-label={`查看 ${platformGrantUserLabel(item)} 平台发放金币来源明细`}
                  className="report-clickable-row"
                  key={item.user_id}
                  role="button"
                  tabIndex={0}
                  onClick={openRecords}
                  onKeyDown={(event) => {
                    if (event.key === "Enter" || event.key === " ") {
                      event.preventDefault();
                      openRecords();
                    }
                  }}
                >
                  <td>
                    <span className="report-user-cell">
                      {item.avatar ? <img alt="" src={item.avatar} /> : null}
                      <span>
                        <b>{platformGrantUserLabel(item)}</b>
                        <small>{platformGrantUserMeta(item)}</small>
                      </span>
                    </span>
                  </td>
                  <td>{formatOptionalCoin(item.total_coin)}</td>
                  <td>{formatOptionalCoin(item.record_count)}</td>
                  <td>{formatDateTime(item.last_granted_at_ms)}</td>
                </tr>
              );
            }) : null}
          </tbody>
        </table>
      </div>
      <ReportPagination page={page} pageSize={pageSize} total={total} onPageChange={setPage} />
    </ReportDialog>
  );
}

function PlatformGrantRecordsModal({ modal, onClose }) {
  const pageSize = 20;
  const [page, setPage] = useState(1);
  const [source, setSource] = useState("all");
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  useEffect(() => {
    let active = true;
    setLoading(true);
    setError("");
    fetchPlatformGrantRecords({ ...modal.query, page, pageSize, source })
      .then((nextData) => {
        if (active) {
          setData(nextData || {});
        }
      })
      .catch((err) => {
        if (active) {
          setError(err.message || "请求失败");
          setData(null);
        }
      })
      .finally(() => {
        if (active) {
          setLoading(false);
        }
      });
    return () => {
      active = false;
    };
  }, [modal.query, page, source]);
  const items = Array.isArray(data?.items) ? data.items : [];
  const total = Number(data?.total || 0);
  const selectSource = (event) => {
    setSource(event.target.value);
    setPage(1);
  };

  return (
    <ReportDialog title={`${platformGrantUserLabel(modal.user)} 平台发放金币来源`} onClose={onClose}>
      <div className="report-modal-toolbar">
        <label className="report-source-filter">
          <span>来源</span>
          <select aria-label="来源筛选" value={source} onChange={selectSource}>
            {platformGrantRecordSourceOptions.map((option) => (
              <option key={option.value} value={option.value}>{option.label}</option>
            ))}
          </select>
        </label>
      </div>
      <div className="report-modal-table-wrap">
        <table className="report-modal-table">
          <thead>
            <tr>
              <th>来源</th>
              <th>金币</th>
              <th>发放时间</th>
              <th>事件 ID</th>
            </tr>
          </thead>
          <tbody>
            {loading ? <tr className="report-table-skeleton-row"><td colSpan={4}><span className="skeleton-block report-skeleton-line" /></td></tr> : null}
            {!loading && error ? <tr className="report-table-empty-row"><td colSpan={4}>{error}</td></tr> : null}
            {!loading && !error && !items.length ? <tr className="report-table-empty-row"><td colSpan={4}>当前无数据</td></tr> : null}
            {!loading && !error ? items.map((item) => (
              <tr key={item.event_id}>
                <td>{platformGrantSourceLabel(item.event_type)}</td>
                <td>{formatOptionalCoin(item.amount)}</td>
                <td>{formatDateTime(item.occurred_at_ms)}</td>
                <td><span className="report-event-id">{item.event_id || "--"}</span></td>
              </tr>
            )) : null}
          </tbody>
        </table>
      </div>
      <ReportPagination page={page} pageSize={pageSize} total={total} onPageChange={setPage} />
    </ReportDialog>
  );
}

function ReportDialog({ children, onClose, title }) {
  return (
    <div className="report-modal-backdrop">
      <section aria-label={title} aria-modal="true" className="report-modal" role="dialog">
        <header className="report-modal-head">
          <h2>{title}</h2>
          <button className="report-modal-close" type="button" onClick={onClose}>关闭</button>
        </header>
        <div className="report-modal-body">{children}</div>
      </section>
    </div>
  );
}

function ReportPagination({ onPageChange, page, pageSize, total }) {
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
  return (
    <div className="report-pagination">
      <span>共 {formatCoin(total)} 条</span>
      <div>
        <button disabled={page <= 1} type="button" onClick={() => onPageChange(page - 1)}>上一页</button>
        <b>{page} / {totalPages}</b>
        <button disabled={page >= totalPages} type="button" onClick={() => onPageChange(page + 1)}>下一页</button>
      </div>
    </div>
  );
}

function CountryCell({ row }) {
  return (
    <span className="report-country-cell">
      {row.flag ? <i>{row.flag}</i> : null}
      <span>{row.country}</span>
    </span>
  );
}

function DateCell({ row }) {
  const childCount = Array.isArray(row.children) ? row.children.length : 0;
  return (
    <span className={["report-date-cell", childCount ? "report-date-cell--expandable" : ""].filter(Boolean).join(" ")}>
      {childCount ? (
        <span className={["report-expand-caret", row.expanded ? "is-open" : ""].filter(Boolean).join(" ")} aria-hidden="true">
          ›
        </span>
      ) : null}
      <span>{row.date_label || "--"}</span>
      {childCount ? <small>{childCount} 国</small> : null}
    </span>
  );
}

function FlowRateCell({ rate, value }) {
  if (isMissing(value) && isMissing(rate)) {
    return <span className="report-placeholder">--</span>;
  }
  return (
    <span className="report-pair-cell">
      <b>{formatOptionalCoin(value)}</b>
      <small>{formatOptionalPercent(rate)}</small>
    </span>
  );
}

function ConsumeOutputCell({ row }) {
  if (isMissing(row.consume_output_ratio) && isMissing(row.consume_output_delta)) {
    return <span className="report-placeholder">--</span>;
  }
  return (
    <span className="report-pair-cell">
      <b>{formatOptionalPercent(row.consume_output_ratio)}</b>
      <small>差额 {formatOptionalCoin(row.consume_output_delta)}</small>
    </span>
  );
}

function TrendValue({ value }) {
  return <span className={Number(value) >= 0 ? "report-trend-up" : "report-trend-down"}>{formatSignedPercent(value)}</span>;
}

function DeltaText({ value }) {
  const text = String(value || "").trim();
  if (!text) {
    return <span className="report-delta report-delta--empty">--</span>;
  }
  return <span className={text.startsWith("-") ? "report-delta report-delta--down" : "report-delta"}>{text.startsWith("-") ? "↓" : "↑"} {text.replace(/^[-+]/, "")}</span>;
}

function ReportSkeletonRows({ colSpan }) {
  return Array.from({ length: 6 }).map((_, index) => (
    <tr className="report-table-skeleton-row" key={index}>
      <td colSpan={colSpan}><span className="skeleton-block report-skeleton-line" /></td>
    </tr>
  ));
}

function ReportEmptyRow({ colSpan }) {
  return (
    <tr className="report-table-empty-row">
      <td colSpan={colSpan}>当前无数据</td>
    </tr>
  );
}

function createSummaryCards(model) {
  const totalRecharge = model.kpis[0] || {};
  const rechargeSplit = model.kpis[1]?.subMetrics || [];
  const newUsers = model.kpis[2] || {};
  const activeUsers = model.kpis[3] || {};
  const paidSplit = model.kpis[4]?.subMetrics || [];
  const arpu = model.kpis[5] || {};
  const arppu = model.kpis[6] || {};
  const payerRate = model.sideMetrics?.find((item) => item.label === "付费转化率") || {};

  return [
    {
      delta: totalRecharge.delta,
      details: [
        { label: "用户充值", value: rechargeSplit[0]?.value || "--" },
        { label: "新用户充值", value: rechargeSplit[1]?.value || "--" }
      ],
      title: "总充值",
      trendMetric: totalRecharge,
      value: totalRecharge.value || "--",
      valueLabel: "总充值"
    },
    {
      delta: activeUsers.delta,
      details: [
        { label: "新增用户", value: newUsers.value || "--" },
        { label: "活跃用户", value: activeUsers.value || "--" }
      ],
      title: "活跃用户",
      trendMetric: activeUsers,
      value: activeUsers.value || "--",
      valueLabel: "活跃用户"
    },
    {
      delta: paidSplit[0]?.delta,
      details: [
        { label: "付费用户", value: paidSplit[0]?.value || "--" },
        { label: "新增付费", value: paidSplit[1]?.value || "--" }
      ],
      title: "付费转化率",
      trendMetric: model.kpis[4],
      value: payerRate.value || "--",
      valueLabel: "付费转化率"
    },
    {
      delta: arpu.delta,
      details: [
        { label: "ARPU", value: arpu.value || "--" },
        { label: "ARPPU", value: arppu.value || "--" }
      ],
      title: "ARPPU",
      trendMetric: arpu,
      value: arppu.value || "--",
      valueLabel: "ARPPU"
    }
  ];
}

function firstSortableColumn(columns) {
  const column = columns.find((item) => item.sortable !== false);
  return column ? { direction: column.type === "text" ? "asc" : "desc", key: column.key, type: column.type || "number" } : null;
}

function sortRows(rows, sortState, columns) {
  if (!sortState?.key) {
    return rows;
  }
  const column = columns.find((item) => item.key === sortState.key);
  if (!column) {
    return rows;
  }
  const multiplier = sortState.direction === "asc" ? 1 : -1;
  return rows
    .map((row, index) => ({ index, row }))
    .sort((left, right) => {
      const result = compareValues(readSortValue(left.row, column), readSortValue(right.row, column), sortState.type);
      return result === 0 ? left.index - right.index : result * multiplier;
    })
    .map(({ row }) => row);
}

function readSortValue(row, column) {
  return column.sortValue ? column.sortValue(row) : row[column.key];
}

function compareValues(leftValue, rightValue, type) {
  if (type === "text") {
    return textCollator.compare(String(leftValue || ""), String(rightValue || ""));
  }
  const leftNumber = Number(leftValue);
  const rightNumber = Number(rightValue);
  if (!Number.isFinite(leftNumber) && !Number.isFinite(rightNumber)) {
    return 0;
  }
  if (!Number.isFinite(leftNumber)) {
    return -1;
  }
  if (!Number.isFinite(rightNumber)) {
    return 1;
  }
  return leftNumber - rightNumber;
}

function buildPlatformGrantQuery(baseQuery = {}, row = {}) {
  const countryId = Number(row.country_id ?? row.countryId ?? baseQuery.countryId ?? 0);
  const regionId = row.region_id ?? row.regionId ?? baseQuery.regionId;
  return {
    appCode: baseQuery.appCode,
    countryId,
    endMs: baseQuery.endMs,
    regionId,
    startMs: baseQuery.startMs,
    statDay: row.stat_day || row.statDay || "",
    statTz: baseQuery.statTz
  };
}

function platformGrantCountryRows(row, rows) {
  const sourceRows = row.row_type === "date_total" && Array.isArray(row.children) && row.children.length
    ? row.children
    : collectPlatformGrantCountryRows(rows);
  return aggregatePlatformGrantCountryRows(sourceRows)
    .filter((item) => Number(item.platform_grant_coin || 0) > 0)
    .sort((left, right) => Number(right.platform_grant_coin || 0) - Number(left.platform_grant_coin || 0));
}

function collectPlatformGrantCountryRows(rows) {
  const out = [];
  rows.forEach((row) => {
    if (row.row_type === "country") {
      out.push(row);
    }
    if (Array.isArray(row.children)) {
      out.push(...collectPlatformGrantCountryRows(row.children));
    }
  });
  return out;
}

function aggregatePlatformGrantCountryRows(rows) {
  const grouped = new Map();
  rows.forEach((row) => {
    const key = [row.country_id ?? row.country, row.region_id ?? ""].join(":");
    const current = grouped.get(key);
    if (!current) {
      grouped.set(key, { ...row, platform_grant_coin: Number(row.platform_grant_coin || 0) });
      return;
    }
    const nextStatDay = current.stat_day && row.stat_day && current.stat_day === row.stat_day ? current.stat_day : "";
    grouped.set(key, {
      ...current,
      platform_grant_coin: Number(current.platform_grant_coin || 0) + Number(row.platform_grant_coin || 0),
      stat_day: nextStatDay
    });
  });
  return Array.from(grouped.values());
}

function platformGrantUserLabel(item = {}) {
  return item.user?.display_user_id || item.display_user_id || item.user?.username || item.username || item.nickname || item.user_id || "用户";
}

function platformGrantUserMeta(item = {}) {
  return [item.user?.username || item.username || item.nickname, item.user_id]
    .filter((value, index, values) => value && values.indexOf(value) === index)
    .join(" · ") || "--";
}

function platformGrantSourceLabel(value) {
  switch (String(value || "").trim()) {
    case "WalletLuckyGiftRewardCredited":
      return "幸运礼物返奖";
    case "WalletTaskRewardCredited":
      return "任务奖励";
    case "WalletWheelRewardCredited":
      return "转盘奖励";
    case "WalletRoomTurnoverRewardCredited":
      return "房间流水奖励";
    case "WalletInviteActivityRewardCredited":
      return "邀请活动奖励";
    case "WalletAgencyOpeningRewardCredited":
      return "代理开通奖励";
    case "WalletBalanceChanged":
      return "资源发放";
    case "WalletPlatformGrantCoinCredited":
      return "平台发放";
    default:
      return value || "--";
  }
}

function formatDateTime(value) {
  const ms = Number(value || 0);
  if (!ms) {
    return "--";
  }
  return new Date(ms).toLocaleString("zh-CN", {
    day: "2-digit",
    hour: "2-digit",
    hour12: false,
    minute: "2-digit",
    month: "2-digit",
    second: "2-digit",
    year: "numeric"
  });
}

function formatSignedPercent(value) {
  if (value === undefined || value === null || Number.isNaN(Number(value))) {
    return "--";
  }
  return `${Number(value) >= 0 ? "+" : ""}${formatPercent(value)}`;
}

function reportRowKey(row, index) {
  return [row.row_id, row.country, row.name, row.label, row.pool_id, row.game_id, row.platform_code, row.value, index]
    .filter((item) => item !== undefined && item !== null && item !== "")
    .join(":");
}

function reportRowClass(row) {
  if (row.row_type === "total") {
    return "report-row-total";
  }
  if (row.row_type === "date_total") {
    return "report-row-date-total";
  }
  return "";
}

function reportTableRowProps(row) {
  if (!row.onToggle) {
    return {};
  }
  const action = row.expanded ? "收起" : "展开";
  const label = `${action} ${row.date_label || "日期"} 国家明细`;
  return {
    "aria-expanded": row.expanded,
    "aria-label": label,
    className: "report-row-expandable",
    role: "button",
    tabIndex: 0,
    onClick: row.onToggle,
    onKeyDown: (event) => {
      if (event.key === "Enter" || event.key === " ") {
        event.preventDefault();
        row.onToggle();
      }
    }
  };
}

function reportRowIndex(row, index) {
  if (row.row_type === "total") {
    return "总";
  }
  if (row.row_type === "date_total") {
    return "日";
  }
  return index + 1;
}

function formatOptionalMoney(value) {
  return isMissing(value) ? <span className="report-placeholder">--</span> : formatMoneyFull(value);
}

function formatOptionalCoin(value) {
  return isMissing(value) ? <span className="report-placeholder">--</span> : formatCoin(value);
}

function formatOptionalPercent(value) {
  return isMissing(value) ? <span className="report-placeholder">--</span> : formatPercent(value);
}

function formatDuration(value) {
  if (isMissing(value)) {
    return <span className="report-placeholder">--</span>;
  }
  const totalSeconds = Math.max(0, Math.round(Number(value) / 1000));
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  if (hours > 0) {
    return `${hours}h ${minutes}m`;
  }
  return `${minutes}m`;
}

function isMissing(value) {
  return value === undefined || value === null || Number.isNaN(Number(value));
}
