// RegionsView（地区洞察）：概要条 + 世界地图（国家粒度）+ 区域卡片网格 + 区域→国家下钻表。
// 数据契约见 SocialBiApp.jsx 的 useSocialBi()；金额为 USD 分、比例为 0-1，渲染时统一走 metrics/format 层。

import { Fragment, useMemo, useState } from "react";
import { VisualMapComponent } from "echarts/components";
import * as echarts from "echarts/core";
import { EChart } from "../../charts/EChart.jsx";
import { resolveCountryMeta } from "../../data/countryMeta.js";
import worldMap from "../../data/world.json";
import { formatCount, formatMoneyMinor, formatRatioPercent, isBlank } from "../format.js";
import { aggregateMetricMaps, appColor, formatMetric, metricChartValue, metricLabel, metricTooltip } from "../metrics.js";
import { useSocialBi } from "../SocialBiApp.jsx";
import "./regions-view.css";

// EChart.jsx 未注册 visualMap 组件，这里按需补注册（echarts.use 幂等，不影响其它图表）。
echarts.use([VisualMapComponent]);

const MAP_METRICS = [
  { key: "recharge_usd_minor", label: "充值" },
  { key: "new_users", label: "新增" },
  { key: "active_users", label: "日活" }
];

const CARD_METRICS = ["new_users", "active_users", "arppu_usd_minor"];

const TABLE_METRICS = [
  "recharge_usd_minor",
  "new_users",
  "active_users",
  "paid_users",
  "arppu_usd_minor",
  "d1_retention_rate",
  "gift_coin_spent"
];

// databi-world 的合法地名索引（小写 → 原始 feature name），用于把 ISO alpha-2 / 后端国家名归一成地图地名。
const MAP_NAME_INDEX = new Map();
(worldMap.features || []).forEach((feature) => {
  const name = feature?.properties?.name;
  if (name) {
    MAP_NAME_INDEX.set(String(name).trim().toLowerCase(), name);
  }
});

// 复用 countryMeta 的 ISO alpha-2 → 备选英文/中文名列表，再校验哪一个是 databi-world 的 feature name。
function resolveMapName(countryCode, countryName) {
  const meta = resolveCountryMeta({ code: countryCode, name: countryName });
  const candidates = [...(meta?.names || []), countryName];
  for (const candidate of candidates) {
    const hit = MAP_NAME_INDEX.get(String(candidate || "").trim().toLowerCase());
    if (hit) {
      return hit;
    }
  }
  return "";
}

function countryDisplayName(countryCode, countryName) {
  const meta = resolveCountryMeta({ code: countryCode, name: countryName });
  return meta?.label || countryName || countryCode || "未知国家";
}

function rechargeValue(row) {
  return isBlank(row?.recharge_usd_minor) ? -1 : Number(row.recharge_usd_minor);
}

function byRechargeDesc(a, b) {
  return rechargeValue(b) - rechargeValue(a);
}

export function RegionsView() {
  const { appCodes, derived, isLoading } = useSocialBi();
  const { appTotals, countryTotals, regionTotals } = derived;
  const [mapMetric, setMapMetric] = useState("recharge_usd_minor");
  const [expandedRegions, setExpandedRegions] = useState(() => new Set());

  const regionRows = useMemo(() => [...regionTotals].sort(byRechargeDesc), [regionTotals]);

  const regionSummary = useMemo(() => aggregateMetricMaps(regionTotals), [regionTotals]);

  const regionCount = useMemo(
    () => new Set(regionTotals.map((row) => `${row.app_code}:${row.region_id}`)).size,
    [regionTotals]
  );

  const appCount = useMemo(() => new Set(regionTotals.map((row) => row.app_code)).size, [regionTotals]);

  const countryCount = useMemo(() => {
    const codes = new Set();
    countryTotals.forEach((row) => {
      const key = String(row.country_code || row.country_name || "").trim();
      if (key) {
        codes.add(key);
      }
    });
    return codes.size;
  }, [countryTotals]);

  // 每个 App 的总充值（占比条分母）：优先 appTotals 的整 App 口径，缺失时退化为可见区域行求和。
  const appRechargeTotals = useMemo(() => {
    const totals = new Map();
    appTotals.forEach((row) => {
      if (!isBlank(row.recharge_usd_minor)) {
        totals.set(row.app_code, Number(row.recharge_usd_minor));
      }
    });
    const fallback = new Map();
    regionTotals.forEach((row) => {
      if (!isBlank(row.recharge_usd_minor)) {
        fallback.set(row.app_code, (fallback.get(row.app_code) || 0) + Number(row.recharge_usd_minor));
      }
    });
    fallback.forEach((value, code) => {
      if (!totals.has(code)) {
        totals.set(code, value);
      }
    });
    return totals;
  }, [appTotals, regionTotals]);

  // 下钻子行：countryTotals 按 app_code + region_id 分组（region_id 缺失已在数据层归一成 0，对应"未划分区域"）。
  const countriesByRegion = useMemo(() => {
    const groups = new Map();
    countryTotals.forEach((row) => {
      const key = `${row.app_code}:${Number(row.region_id ?? 0)}`;
      const bucket = groups.get(key) || [];
      bucket.push(row);
      groups.set(key, bucket);
    });
    groups.forEach((rows) => rows.sort(byRechargeDesc));
    return groups;
  }, [countryTotals]);

  // 地图数据：跨 App 同国家先按地图地名合桶，再用 aggregateMetricMaps 合并（比例按分子分母重算）。
  const mapIndex = useMemo(() => {
    const buckets = new Map();
    const unmatched = new Set();
    countryTotals.forEach((row) => {
      const mapName = resolveMapName(row.country_code, row.country_name);
      if (!mapName) {
        unmatched.add(String(row.country_code || row.country_name || "?"));
        return;
      }
      const bucket = buckets.get(mapName) || { label: countryDisplayName(row.country_code, row.country_name), rows: [] };
      bucket.rows.push(row);
      buckets.set(mapName, bucket);
    });
    const entries = new Map();
    buckets.forEach((bucket, mapName) => {
      entries.set(mapName, { label: bucket.label, metrics: aggregateMetricMaps(bucket.rows) });
    });
    return { entries, unmatchedCount: unmatched.size };
  }, [countryTotals]);

  const mapOption = useMemo(() => {
    const data = [];
    mapIndex.entries.forEach((entry, mapName) => {
      const value = metricChartValue(mapMetric, entry.metrics[mapMetric]);
      if (value !== null) {
        data.push({ name: mapName, value });
      }
    });
    const max = data.reduce((acc, item) => Math.max(acc, item.value), 0) || 1;
    return {
      series: [
        {
          data,
          emphasis: { itemStyle: { areaColor: "#93b6f2" }, label: { show: false } },
          itemStyle: { areaColor: "#e9eef5", borderColor: "#d5dfeb", borderWidth: 0.6 },
          label: { show: false },
          map: "databi-world",
          name: metricLabel(mapMetric),
          roam: false,
          select: { disabled: true },
          type: "map"
        }
      ],
      tooltip: {
        backgroundColor: "#ffffff",
        borderColor: "#e3eaf3",
        extraCssText: "box-shadow: 0 4px 16px rgba(16, 34, 56, 0.12);",
        formatter: (params) => {
          const entry = mapIndex.entries.get(params.name);
          if (!entry) {
            return `${params.name}<br/>暂无数据`;
          }
          return `${entry.label}<br/>${metricLabel(mapMetric)}：${formatMetric(mapMetric, entry.metrics[mapMetric])}`;
        },
        textStyle: { color: "#14263c", fontSize: 12 }
      },
      visualMap: {
        bottom: 10,
        calculable: false,
        inRange: { color: ["#dbeafe", "#2557d6"] },
        itemHeight: 110,
        itemWidth: 10,
        left: 12,
        max,
        min: 0,
        orient: "horizontal",
        text: ["高", "低"],
        textStyle: { color: "#5b7089", fontSize: 11 }
      }
    };
  }, [mapIndex, mapMetric]);

  const toggleRegion = (key) => {
    setExpandedRegions((current) => {
      const next = new Set(current);
      if (next.has(key)) {
        next.delete(key);
      } else {
        next.add(key);
      }
      return next;
    });
  };

  if (isLoading && !regionTotals.length && !countryTotals.length) {
    return <RegionsSkeleton />;
  }

  if (!regionTotals.length) {
    return (
      <section className="sbi-card">
        <div className="sbi-empty">
          <strong>暂无区域数据</strong>
          <span>检查顶栏区域筛选，或该 App 尚未配置区域目录（legacy App 在其 Mongo sys_region_config，hyapp 在区域管理）</span>
        </div>
      </section>
    );
  }

  return (
    <>
      <div className="sbi-rg-summary">
        <section className="sbi-card sbi-rg-summary-card">
          <span className="sbi-rg-summary-label">覆盖区域数</span>
          <span className="sbi-rg-summary-value">{formatCount(regionCount)}</span>
          <span className="sbi-rg-summary-sub">按 App × 区域去重 · 覆盖 {formatCount(appCount)} 个 App</span>
        </section>
        <section className="sbi-card sbi-rg-summary-card">
          <span className="sbi-rg-summary-label">覆盖国家数</span>
          <span className="sbi-rg-summary-value">{formatCount(countryCount)}</span>
          <span className="sbi-rg-summary-sub">countryTotals 按国家去重（跨 App 合并）</span>
        </section>
        <section className="sbi-card sbi-rg-summary-card">
          <span className="sbi-rg-summary-label" title={metricTooltip("recharge_usd_minor")}>
            区域充值合计
          </span>
          <span className="sbi-rg-summary-value">{formatMoneyMinor(regionSummary.recharge_usd_minor)}</span>
          <span className="sbi-rg-summary-sub">当前区间 · 可见区域行合计</span>
        </section>
      </div>

      <section className="sbi-card sbi-rg-map-card">
        <div className="sbi-card-header">
          <strong>全球分布</strong>
          <small>
            {countryCount ? `${formatCount(countryCount)} 个国家 · 跨 App 合并` : "国家粒度"}
            {mapIndex.unmatchedCount ? ` · ${mapIndex.unmatchedCount} 个国家未匹配到地图` : ""}
          </small>
          <div className="sbi-card-toolbar">
            <div className="sbi-seg" role="radiogroup" aria-label="地图指标">
              {MAP_METRICS.map((item) => (
                <button
                  aria-checked={mapMetric === item.key}
                  className={mapMetric === item.key ? "is-active" : ""}
                  key={item.key}
                  onClick={() => setMapMetric(item.key)}
                  role="radio"
                  title={metricTooltip(item.key)}
                  type="button"
                >
                  {item.label}
                </button>
              ))}
            </div>
          </div>
        </div>
        <div className="sbi-rg-map-body">
          {mapIndex.entries.size ? (
            <EChart className="sbi-rg-map-chart" option={mapOption} />
          ) : (
            <div className="sbi-empty">
              <strong>暂无国家数据</strong>
              <span>当前区间没有国家粒度数据，或国家编码未能匹配到世界地图</span>
            </div>
          )}
        </div>
      </section>

      <div className="sbi-rg-grid">
        {regionRows.map((row) => {
          const key = `${row.app_code}:${row.region_id}`;
          const appTotal = appRechargeTotals.get(row.app_code);
          const share = appTotal && !isBlank(row.recharge_usd_minor) ? Number(row.recharge_usd_minor) / appTotal : null;
          return (
            <section className="sbi-card sbi-rg-region-card" key={key}>
              <div className="sbi-rg-region-head">
                <span className="sbi-rg-region-name" title={row.region_name}>
                  {row.region_name}
                </span>
                {row.restricted ? (
                  <span className="sbi-badge" title="数据按你的负责范围裁剪">
                    范围裁剪
                  </span>
                ) : null}
                <span className="sbi-rg-app-tag">
                  <span className="sbi-rg-app-dot" style={{ background: appColor(row.app_code, appCodes) }} />
                  {row.app_name}
                </span>
              </div>
              <div className="sbi-rg-region-money">
                <small className="sbi-metric-hint" title={metricTooltip("recharge_usd_minor")}>
                  {metricLabel("recharge_usd_minor")}
                </small>
                <strong>{formatMoneyMinor(row.recharge_usd_minor)}</strong>
              </div>
              <div className="sbi-rg-region-metrics">
                {CARD_METRICS.map((metric) => (
                  <div className="sbi-rg-region-metric" key={metric}>
                    <small className="sbi-metric-hint" title={metricTooltip(metric)}>
                      {metricLabel(metric)}
                    </small>
                    <span>{formatMetric(metric, row[metric])}</span>
                  </div>
                ))}
              </div>
              <div className="sbi-rg-share">
                <span className="sbi-rg-share-head">
                  <span>占 {row.app_name} 总充值</span>
                  <span>{share === null ? "--" : formatRatioPercent(share)}</span>
                </span>
                <span className="sbi-rg-share-track">
                  <span
                    className="sbi-rg-share-fill"
                    style={{ width: share === null ? 0 : `${Math.min(100, Math.max(0, share * 100))}%` }}
                  />
                </span>
              </div>
            </section>
          );
        })}
      </div>

      <section className="sbi-card sbi-rg-table-card">
        <div className="sbi-card-header">
          <strong>区域下钻</strong>
          <small>点击区域行展开国家明细 · 按充值降序</small>
        </div>
        <div className="sbi-table-scroll">
          <table className="sbi-table">
            <thead>
              <tr>
                <th className="is-left">地区 / 国家</th>
                <th className="is-left">App</th>
                {TABLE_METRICS.map((metric) => (
                  <th key={metric}>
                    <span className="sbi-metric-hint" title={metricTooltip(metric)}>
                      {metricLabel(metric)}
                    </span>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              <tr className="is-total">
                <td className="is-left">全部区域</td>
                <td className="is-left">{formatCount(appCount)} 个 App</td>
                {TABLE_METRICS.map((metric) => (
                  <td key={metric}>{formatMetric(metric, regionSummary[metric])}</td>
                ))}
              </tr>
              {regionRows.map((row) => {
                const key = `${row.app_code}:${row.region_id}`;
                const isOpen = expandedRegions.has(key);
                const children = isOpen ? countriesByRegion.get(key) || [] : [];
                return (
                  <Fragment key={key}>
                    <tr aria-expanded={isOpen} className="sbi-rg-row" onClick={() => toggleRegion(key)}>
                      <td className="is-left">
                        <span className="sbi-rg-region-cell">
                          <span aria-hidden="true" className={isOpen ? "sbi-rg-caret is-open" : "sbi-rg-caret"}>
                            ▸
                          </span>
                          {row.region_name}
                          {row.restricted ? (
                            <span className="sbi-badge" title="数据按你的负责范围裁剪">
                              范围裁剪
                            </span>
                          ) : null}
                        </span>
                      </td>
                      <td className="is-left">
                        <span className="sbi-rg-app-tag">
                          <span className="sbi-rg-app-dot" style={{ background: appColor(row.app_code, appCodes) }} />
                          {row.app_name}
                        </span>
                      </td>
                      {TABLE_METRICS.map((metric) => (
                        <td key={metric}>{formatMetric(metric, row[metric])}</td>
                      ))}
                    </tr>
                    {isOpen && !children.length ? (
                      <tr className="sbi-rg-child">
                        <td className="is-left" colSpan={2 + TABLE_METRICS.length}>
                          <span className="sbi-rg-child-name">该区域暂无国家明细</span>
                        </td>
                      </tr>
                    ) : null}
                    {children.map((child) => (
                      <tr className="sbi-rg-child" key={`${key}:${child.country_code || child.country_name}`}>
                        <td className="is-left">
                          <span className="sbi-rg-child-name">{countryDisplayName(child.country_code, child.country_name)}</span>
                        </td>
                        <td className="is-left sbi-rg-child-app">{child.app_name}</td>
                        {TABLE_METRICS.map((metric) => (
                          <td key={metric}>{formatMetric(metric, child[metric])}</td>
                        ))}
                      </tr>
                    ))}
                  </Fragment>
                );
              })}
            </tbody>
          </table>
        </div>
      </section>
    </>
  );
}

function RegionsSkeleton() {
  return (
    <>
      <div className="sbi-rg-summary" aria-busy="true">
        {[0, 1, 2].map((index) => (
          <section className="sbi-card sbi-rg-summary-card" key={index}>
            <span className="sbi-skeleton" style={{ height: 12, width: 90 }} />
            <span className="sbi-skeleton" style={{ height: 26, width: 140 }} />
            <span className="sbi-skeleton" style={{ height: 11, width: 170 }} />
          </section>
        ))}
      </div>
      <section className="sbi-card sbi-rg-map-card" aria-busy="true">
        <div className="sbi-card-header">
          <span className="sbi-skeleton" style={{ height: 14, width: 120 }} />
        </div>
        <div className="sbi-rg-map-body">
          <span className="sbi-skeleton" style={{ display: "block", height: "100%", width: "100%" }} />
        </div>
      </section>
      <div className="sbi-rg-grid" aria-busy="true">
        {[0, 1, 2].map((index) => (
          <section className="sbi-card sbi-rg-region-card" key={index}>
            <span className="sbi-skeleton" style={{ height: 14, width: 150 }} />
            <span className="sbi-skeleton" style={{ height: 24, width: 130 }} />
            <span className="sbi-skeleton" style={{ height: 34, width: "100%" }} />
          </section>
        ))}
      </div>
    </>
  );
}
