// view-regional.jsx — 지역 분석 (Regional Deep Dive)
// Unique names: RegionalView, RgnKpiCard, RgnModelTable, RGN_CHANNELS, RT_KO, RT_EN
// Reuses from view-overview.jsx (global scope): moneyB, cssVar,
//   Placeholder, ErrBox. Layout chrome comes from app.css classes
//   (.surface-card, .view-head, .channel-pill, .kpi-mini, .chart-card, etc).

const RGN_CHANNELS = [
  { key: 'US',  label: '🇺🇸 US',  color: '#007AFF' },
  { key: 'ROW', label: '🌐 ROW', color: '#FF9500' },
  { key: 'KR',  label: '🇰🇷 KR',  color: '#34C759' },
];

const RT_KO = {
  title: '지역 분석', loading: '불러오는 중…', empty: '데이터가 없습니다.',
  totalRev: '총 매출 (KRW)', targetPct: '연간 목표 달성률', thisMonth: '이번 달 매출', topMake: 'TOP MAKE',
  monthly12: '월별 매출',
  byMake: '제조사별 TOP 8', byCat: '카테고리 그룹 TOP 6',
  topModels: 'TOP 10 모델', rank: '#', model: '모델', revenue: '매출',
  noTarget: '목표 미설정',
  yoy: 'YoY 성장률',
  yoyPeriodNote: '{thisYr} {range} vs {prevYr} {range}',
  yoyNoData: '전년 동기 데이터 없음',
  period: '기간', all: '전체', custom: '직접 설정',
  mtd: '이번 달', mtdTitle: '이번 달 1일부터 오늘까지',
  salesKrw: '매출 KRW', qtyLabel: '판매 수량', qtyUnit: '개', qty: '수량',
};
const RT_EN = {
  title: 'Regional Deep Dive', loading: 'Loading…', empty: 'No data.',
  totalRev: 'Total Revenue (KRW)', targetPct: 'Annual Target %', thisMonth: 'This Month', topMake: 'Top Make',
  monthly12: 'Monthly Revenue',
  byMake: 'Top 8 Makes', byCat: 'Top 6 Category Groups',
  topModels: 'Top 10 Models', rank: '#', model: 'Model', revenue: 'Revenue',
  noTarget: 'No target set',
  yoy: 'YoY Growth',
  yoyPeriodNote: '{thisYr} {range} vs {prevYr} {range}',
  yoyNoData: 'No prior-year data',
  period: 'Period', all: 'All', custom: 'Custom',
  mtd: 'MTD', mtdTitle: 'Month-to-date (1st → today)',
  salesKrw: 'Sales KRW', qtyLabel: 'Units Sold', qtyUnit: '', qty: 'Qty',
};

// 차트 metric별 표시 설정 — 막대·라인 공용. view-overview.jsx의 ovMetricCfg와
// 동일한 형태이지만, Babel UMD가 각 파일을 전역 스코프에서 파싱하므로 로드
// 순서에 상관없이 이 뷰가 자립하도록 별도 정의한다. barScale: 막대/라인
// dataset 값을 사람이 읽는 원단위로 되돌릴 배율(krw는 억 단위로 넣으므로 ×1e8,
// qty는 원자료라 ×1).
function rgnMetricCfg(metric, t) {
  if (metric === 'qty') {
    return {
      label: t.qtyLabel, barScale: 1,
      axisTick: v => Number(v).toLocaleString(),
      fmt: v => Number(v).toLocaleString() + (t.qtyUnit || ''),
    };
  }
  return {
    label: t.salesKrw, barScale: 1e8,
    axisTick: v => (Math.round(v * 10) / 10).toLocaleString() + '억',  // float 오차 제거 + 1자리 반올림
    fmt: v => moneyB(v),
  };
}

// ─── Main view ────────────────────────────────────────────────────────────────
function RegionalView({ lang, perms }) {
  const [loading, setLoading]       = React.useState(true);
  const [allRows, setAllRows]       = React.useState([]);
  const [kpiTargets, setKpiTargets] = React.useState([]);
  const [err, setErr]               = React.useState(null);
  const [channel, setChannel]       = React.useState('US');

  // 차트별 매출액(krw)/수량(qty) 토글 — 세션 한정(새로고침 시 krw로 리셋).
  const [chartMetric, setChartMetric] = React.useState({
    month:'krw', make:'krw', cat:'krw', models:'krw',
  });
  const setMetric = (key, val) => setChartMetric(prev => ({ ...prev, [key]: val }));

  const rt = lang === 'en' ? RT_EN : RT_KO;
  const currentYear  = new Date().getFullYear();
  const currentMonth = new Date().getMonth() + 1;
  const thisYM = currentYear + '-' + String(currentMonth).padStart(2, '0');

  // Period filter — default to current year (mirrors Overview's UX).
  // PeriodBar/filterByPeriod come from view-overview.jsx (global scope).
  const [period, setPeriod]     = React.useState(String(currentYear));
  const [dateFrom, setDateFrom] = React.useState('');
  const [dateTo, setDateTo]     = React.useState('');

  React.useEffect(() => {
    (async () => {
      try {
        setLoading(true);
        const [rows, targets] = await Promise.all([
          SALES_DB.fetchAllSalesData(),
          SALES_DB.fetchKpiTargets(currentYear).catch(() => []),
        ]);
        setAllRows(rows);
        setKpiTargets(targets || []);
      } catch (e) {
        setErr(e?.message || String(e));
      } finally {
        setLoading(false);
      }
    })();
  }, []);

  // Per-channel totals for pills
  const channelTotals = React.useMemo(() => {
    const m = { US: 0, ROW: 0, KR: 0 };
    for (const r of allRows) {
      const ch = r.channel_group;
      if (ch === 'US' || ch === 'ROW' || ch === 'KR') m[ch] += r.sales_amount_krw || 0;
    }
    return m;
  }, [allRows]);

  // Rows for selected channel + period filter.
  // channelTotals (pills) intentionally still uses unfiltered allRows above
  // so pills always show full-context revenue regardless of period choice.
  const chRows = React.useMemo(() => {
    const filtered = allRows.filter(r => r.channel_group === channel);
    if (typeof filterByPeriod === 'function') {
      return filterByPeriod(filtered, period, dateFrom, dateTo);
    }
    return filtered;
  }, [allRows, channel, period, dateFrom, dateTo]);

  // Aggregates for selected channel.
  // Most metrics use period-filtered chRows (reflects the selected period).
  // YoY is special: it derives the comparison year from period and uses
  // unfiltered channel rows so the prior year's data is also available.
  const chStats = React.useMemo(() => {
    let totalKrw = 0, thisMonthKrw = 0, ytdKrw = 0;
    // 각 버킷은 {krw, qty} — 차트 토글이 두 메트릭을 모두 필요로 한다.
    const makeMap = {}, catMap = {}, modelMap = {};
    const bump = (m, k, krw, qty) => {
      const b = m[k] || (m[k] = { krw: 0, qty: 0 });
      b.krw += krw; b.qty += qty;
    };

    for (const r of chRows) {
      const krw = r.sales_amount_krw || 0;
      const qty = r.qty || 0;
      const d   = r.order_date || '';
      if (!d) continue;
      totalKrw += krw;
      if (d.slice(0, 7) === thisYM) thisMonthKrw += krw;
      if (d.startsWith(String(currentYear))) ytdKrw += krw;

      const make = r.make || 'Other';
      bump(makeMap, make, krw, qty);

      const cg = r.category_group || 'Other';
      bump(catMap, cg, krw, qty);

      const mdl = (r.make || '?') + ' ' + (r.model || '?');
      bump(modelMap, mdl, krw, qty);
    }

    // ── YoY block ────────────────────────────────────────────────────────
    // Derive comparison year from period:
    //   period='2025' → 2025 vs 2024 (full year, both sides)
    //   period='2026' (current) → 2026 vs 2025, both capped at last-completed month
    //   period='all' → currentYear vs currentYear-1, capped at last-completed month
    //   period='custom' → hide YoY (range comparison too ambiguous to auto-pick)
    const _now = new Date();
    const _lcm = (typeof lastCompletedMonth === 'function')
      ? lastCompletedMonth(_now)
      : { year: _now.getFullYear(), month: Math.max(1, _now.getMonth()) };

    let yoyThisYear, yoyPrevYear, yoyCutoffMonth, yoyThis = 0, yoyPrev = 0, yoyEnabled = true;

    if (period === 'custom') {
      yoyEnabled = false;
    } else if (period === 'all') {
      yoyThisYear = currentYear;
      yoyPrevYear = currentYear - 1;
      yoyCutoffMonth = _lcm.month;
    } else {
      // year token like '2024', '2025', '2026'
      yoyThisYear = parseInt(period, 10);
      yoyPrevYear = yoyThisYear - 1;
      // Only cap if comparing against current year (partial-year)
      yoyCutoffMonth = (yoyThisYear === currentYear) ? _lcm.month : 12;
    }

    if (yoyEnabled) {
      const cutoffMM = String(yoyCutoffMonth).padStart(2, '0');
      // Iterate over channel-only rows (NOT period-filtered) so both years' data is available
      for (const r of allRows) {
        if (r.channel_group !== channel) continue;
        const d = r.order_date || '';
        if (!d) continue;
        const rowYr = parseInt(d.slice(0, 4), 10);
        const mm   = d.slice(5, 7);
        if (mm > cutoffMM) continue;
        const krw = r.sales_amount_krw || 0;
        if (rowYr === yoyThisYear)      yoyThis += krw;
        else if (rowYr === yoyPrevYear) yoyPrev += krw;
      }
    }
    // ─────────────────────────────────────────────────────────────────────

    // Top-N을 메트릭별로 따로 정렬·슬라이스 — 'qty' 토글 시 수량 기준 랭킹.
    // 각 엔트리는 [key, value] 형태(value는 해당 메트릭 숫자)로 평탄화해
    // 기존 차트/테이블 렌더 코드와의 호환을 유지한다.
    const rankBy = (m, n, metric) => Object.entries(m)
      .map(([k, b]) => [k, b[metric]])
      .sort((a, b) => b[1] - a[1])
      .slice(0, n);
    const topMakes  = { krw: rankBy(makeMap, 8, 'krw'),  qty: rankBy(makeMap, 8, 'qty') };
    const topCats   = { krw: rankBy(catMap, 6, 'krw'),   qty: rankBy(catMap, 6, 'qty') };
    const topModels = { krw: rankBy(modelMap, 10, 'krw'), qty: rankBy(modelMap, 10, 'qty') };
    const topMake   = topMakes.krw[0]?.[0] || '—';

    const revTarget = (kpiTargets || []).find(t => t.metric === 'revenue' && t.year === currentYear && t.segment === channel);
    const targetVal = revTarget?.target_value || 0;
    const targetPct = targetVal > 0 ? ytdKrw / targetVal * 100 : null;

    const yoyPct   = (!yoyEnabled || yoyPrev <= 0) ? null : (yoyThis - yoyPrev) / yoyPrev * 100;
    const yoyDelta = yoyThis - yoyPrev;

    return {
      totalKrw, thisMonthKrw, ytdKrw, topMake, topMakes, topCats, topModels,
      targetPct, targetVal,
      yoyPct, yoyDelta, yoyThis, yoyPrev, yoyCutoffMonth,
      yoyThisYear, yoyPrevYear, yoyEnabled,
    };
  }, [chRows, allRows, kpiTargets, channel, thisYM, currentYear, period]);

  // Monthly chart (line). Respects period filter:
  //   period='all'  → cap at last 12 months (otherwise too many points)
  //   period=year   → all months in that year (1-12)
  //   period=custom → all months within the custom range
  const monthlyData = React.useMemo(() => {
    // 월별 krw/qty 모두 집계 — 차트 토글이 둘 다 필요.
    const byYM = {};
    for (const r of chRows) {
      const ym = (r.order_date || '').slice(0, 7);
      if (!ym) continue;
      const b = byYM[ym] || (byYM[ym] = { krw: 0, qty: 0 });
      b.krw += r.sales_amount_krw || 0;
      b.qty += r.qty || 0;
    }
    let months = Object.keys(byYM).sort();
    if (period === 'all') months = months.slice(-12);
    return {
      months,
      // krw는 억 단위, qty는 원자료. 렌더 단에서 chartMetric.month로 선택.
      krw: months.map(m => Math.round((byYM[m]?.krw || 0) / 1e7) / 10),
      qty: months.map(m => byYM[m]?.qty || 0),
    };
  }, [chRows, period]);

  // Chart refs
  const rgnMakeRef  = React.useRef(null);
  const rgnCatRef   = React.useRef(null);
  const rgnMonthRef = React.useRef(null);
  const rgnCharts   = React.useRef({});

  // 차트는 각각 독립 effect — 한 차트의 metric 토글이 다른 차트를 다시 그리지
  // 않도록 분리(라인 + 막대 + 막대 = 3개 effect). 각 effect의 deps에는 자기
  // metric 키만 포함한다.

  // 1. Monthly line — better for trend reading than bars
  React.useEffect(() => {
    if (loading || !chStats || !rgnMonthRef.current) return;
    const fgMuted = cssVar('--fg-muted');
    const gridC   = 'rgba(128,128,128,0.12)';
    const chColor = RGN_CHANNELS.find(c => c.key === channel)?.color || '#007AFF';
    const m       = chartMetric.month;
    const cfg     = rgnMetricCfg(m, rt);
    const prev    = rgnCharts.current['rgn-month'];
    if (prev) { try { prev.destroy(); } catch (_) {} }
    const chart = new Chart(rgnMonthRef.current, {
      type: 'line',
      data: {
        labels: monthlyData.months,
        datasets: [{
          label: cfg.label,
          data: monthlyData[m],
          borderColor: chColor,
          backgroundColor: chColor + '22',
          borderWidth: 2,
          tension: 0.3,
          fill: true,
          pointRadius: 3,
          pointHoverRadius: 5,
          pointBackgroundColor: chColor,
          pointBorderColor: '#fff',
          pointBorderWidth: 1.5,
        }],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: { display: false },
          tooltip: { callbacks: { label: ctx => ' ' + cfg.fmt(ctx.raw * cfg.barScale) } },
        },
        scales: {
          x: { grid: { color: gridC }, ticks: { color: fgMuted, font: { size: 10 }, maxTicksLimit: 12 } },
          y: { grid: { color: gridC }, ticks: { color: fgMuted, font: { size: 10 }, callback: cfg.axisTick } },
        },
      },
    });
    rgnCharts.current['rgn-month'] = chart;
    return () => { try { chart.destroy(); } catch (_) {} };
  }, [monthlyData, channel, loading, lang, chartMetric.month]);

  // 2. Make bar
  React.useEffect(() => {
    if (loading || !chStats || !rgnMakeRef.current) return;
    const fg      = cssVar('--fg');
    const fgMuted = cssVar('--fg-muted');
    const gridC   = 'rgba(128,128,128,0.12)';
    const chColor = RGN_CHANNELS.find(c => c.key === channel)?.color || '#007AFF';
    const m       = chartMetric.make;
    const cfg     = rgnMetricCfg(m, rt);
    const data    = chStats.topMakes[m];
    const prev    = rgnCharts.current['rgn-make'];
    if (prev) { try { prev.destroy(); } catch (_) {} }
    const chart = new Chart(rgnMakeRef.current, {
      type: 'bar',
      data: {
        labels: data.map(([k]) => k),
        datasets: [{
          label: cfg.label,
          data: data.map(([, v]) => m === 'krw' ? Math.round(v / 1e7) / 10 : v),
          backgroundColor: chColor + 'cc', borderRadius: 4,
        }],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        indexAxis: 'y',
        plugins: {
          legend: { display: false },
          tooltip: { callbacks: { label: ctx => ' ' + cfg.fmt(ctx.raw * cfg.barScale) } },
        },
        scales: {
          x: { grid: { color: gridC }, ticks: { color: fgMuted, font: { size: 10 }, callback: cfg.axisTick } },
          y: { grid: { display: false }, ticks: { color: fg, font: { size: 10 } } },
        },
      },
    });
    rgnCharts.current['rgn-make'] = chart;
    return () => { try { chart.destroy(); } catch (_) {} };
  }, [chStats, channel, loading, lang, chartMetric.make]);

  // 3. Category bar
  React.useEffect(() => {
    if (loading || !chStats || !rgnCatRef.current) return;
    const fg      = cssVar('--fg');
    const fgMuted = cssVar('--fg-muted');
    const gridC   = 'rgba(128,128,128,0.12)';
    const chColor = RGN_CHANNELS.find(c => c.key === channel)?.color || '#007AFF';
    const m       = chartMetric.cat;
    const cfg     = rgnMetricCfg(m, rt);
    const data    = chStats.topCats[m];
    const prev    = rgnCharts.current['rgn-cat'];
    if (prev) { try { prev.destroy(); } catch (_) {} }
    const chart = new Chart(rgnCatRef.current, {
      type: 'bar',
      data: {
        labels: data.map(([k]) => k),
        datasets: [{
          label: cfg.label,
          data: data.map(([, v]) => m === 'krw' ? Math.round(v / 1e7) / 10 : v),
          backgroundColor: chColor + '99', borderRadius: 4,
        }],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        indexAxis: 'y',
        plugins: {
          legend: { display: false },
          tooltip: { callbacks: { label: ctx => ' ' + cfg.fmt(ctx.raw * cfg.barScale) } },
        },
        scales: {
          x: { grid: { color: gridC }, ticks: { color: fgMuted, font: { size: 10 }, callback: cfg.axisTick } },
          y: { grid: { display: false }, ticks: { color: fg, font: { size: 10 } } },
        },
      },
    });
    rgnCharts.current['rgn-cat'] = chart;
    return () => { try { chart.destroy(); } catch (_) {} };
  }, [chStats, channel, loading, lang, chartMetric.cat]);

  if (loading) return <Placeholder msg={rt.loading}/>;
  if (err)     return <ErrBox err={err} lang={lang}/>;

  const chInfo    = RGN_CHANNELS.find(c => c.key === channel);
  const tgtColor  = chStats.targetPct == null ? 'var(--fg-muted)'
    : chStats.targetPct >= 100 ? '#34C759'
    : chStats.targetPct >= 80  ? '#FF9500' : '#FF453A';

  return (
    <div>
      <h2 className="view-head">{rt.title}</h2>

      {/* Period selector — same component used in Overview tab */}
      <PeriodBar
        period={period} setPeriod={setPeriod}
        dateFrom={dateFrom} setDateFrom={setDateFrom}
        dateTo={dateTo} setDateTo={setDateTo}
        t={rt}
      />

      {/* Channel pills */}
      <div style={{ display:'flex', gap:10, marginBottom:20, flexWrap:'wrap' }}>
        {RGN_CHANNELS.map(ch => {
          const active = channel === ch.key;
          return (
            <button
              key={ch.key}
              onClick={() => setChannel(ch.key)}
              className="channel-pill"
              style={active ? {
                background: ch.color,
                color: '#fff',
                borderColor: ch.color,
              } : undefined}
            >
              {ch.label}
              {' '}
              <span className="channel-pill__amount">
                {moneyB(channelTotals[ch.key] || 0)}
              </span>
            </button>
          );
        })}
      </div>

      {/* 5 KPI cards (Fix 2 — YoY card added) */}
      <div className="kpi-summary-grid" style={{ gridTemplateColumns:'repeat(5, 1fr)', marginBottom:16 }}>
        <RgnKpiCard label={rt.totalRev}   value={moneyB(chStats.totalKrw)}/>
        <RgnKpiCard label={rt.targetPct}
          value={chStats.targetPct != null ? chStats.targetPct.toFixed(1) + '%' : rt.noTarget}
          valueColor={tgtColor}/>
        <RgnKpiCard label={rt.thisMonth}  value={moneyB(chStats.thisMonthKrw)}/>
        <RgnKpiCard label={rt.topMake}    value={chStats.topMake}/>
        <RgnKpiCard label={rt.yoy}
          value={chStats.yoyPct == null ? '—'
            : (chStats.yoyPct >= 0 ? '+' : '') + chStats.yoyPct.toFixed(1) + '%'}
          valueColor={
            chStats.yoyPct == null ? 'var(--fg-muted)'
              : chStats.yoyPct >= 0 ? '#34C759' : '#FF453A'
          }
          subText={
            !chStats.yoyEnabled
              ? (lang === 'en' ? 'YoY not shown for custom range' : '직접설정 기간 YoY 미산정')
              : chStats.yoyPct == null
                ? rt.yoyNoData
                : (rt.yoyPeriodNote || '')
                    .replace('{thisYr}', String(chStats.yoyThisYear))
                    .replace('{prevYr}', String(chStats.yoyPrevYear))
                    .replace('{range}', formatRgnRange(chStats.yoyCutoffMonth, lang))
          }/>
      </div>

      {/* Monthly + make charts.
          Equal columns (1fr 1fr) so both charts get matching mass — the
          monthly bar chart with 12 columns and the horizontal top-8 makes
          chart are visually comparable when sized the same. RG_CHART_HEIGHT
          ensures consistency with the row below. */}
      <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14, marginBottom:14 }}>
        <RgChartCard title={rt.monthly12}
          right={<MetricToggle value={chartMetric.month} onChange={v => setMetric('month', v)} lang={lang}/>}>
          <canvas ref={rgnMonthRef} id="rgn-month-cv" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}/>
        </RgChartCard>
        <RgChartCard title={rt.byMake}
          right={<MetricToggle value={chartMetric.make} onChange={v => setMetric('make', v)} lang={lang}/>}>
          <canvas ref={rgnMakeRef} id="rgn-make-cv" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}/>
        </RgChartCard>
      </div>

      {/* Category + top models — keep 1fr 2fr because the right side is a
          tabular list of 10 models (not a chart) and benefits from extra
          width. Both panels use RG_CHART_HEIGHT_TALL since the category
          chart has 6 horizontal bars and the table has 10 rows. */}
      <div style={{ display:'grid', gridTemplateColumns:'1fr 2fr', gap:14 }}>
        <RgChartCard title={rt.byCat} height={RG_CHART_HEIGHT_TALL}
          right={<MetricToggle value={chartMetric.cat} onChange={v => setMetric('cat', v)} lang={lang}/>}>
          <canvas ref={rgnCatRef} id="rgn-cat-cv" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}/>
        </RgChartCard>

        <RgChartCard title={rt.topModels} height={RG_CHART_HEIGHT_TALL} bodyAlign="start"
          right={<MetricToggle value={chartMetric.models} onChange={v => setMetric('models', v)} lang={lang}/>}>
          <RgnModelTable models={chStats.topModels[chartMetric.models]} rt={rt} metric={chartMetric.models}/>
        </RgChartCard>
      </div>
    </div>
  );
}

// Unified chart-card sizing for the Regional Deep Dive tab.
// Mirrors the OvChartCard pattern from view-overview.jsx.
const RG_CHART_HEIGHT      = 280;
const RG_CHART_HEIGHT_TALL = 320;

// Body uses `position:relative; flex:1; minHeight:0` so an absolute-positioned
// canvas can fill the remaining space below the title row. Non-chart bodies
// (the TOP 10 model table) can pass bodyAlign="start" to scroll-overflow
// instead of stretching.
function RgChartCard({ title, children, right, height = RG_CHART_HEIGHT, bodyAlign = 'stretch' }) {
  const bodyClass = 'chart-card__body' + (bodyAlign === 'start' ? ' chart-card__body--list' : '');
  return (
    <div className="chart-card" style={{ height }}>
      <div className="chart-card__head">
        <div className="chart-card__title chart-card__title--sm">{title}</div>
        {right || null}
      </div>
      <div className={bodyClass}>
        {children}
      </div>
    </div>
  );
}

// ─── KPI mini-card ────────────────────────────────────────────────────────────
function RgnKpiCard({ label, value, valueColor, subText }) {
  return (
    <div className="kpi-mini">
      <div className="kpi-mini__label">{label}</div>
      <div className="kpi-mini__value kpi-mini__value--sm" style={valueColor ? { color: valueColor } : undefined}>{value}</div>
      {subText && (
        <div className="kpi-mini__subtext" style={{ fontVariantNumeric:'normal' }}>{subText}</div>
      )}
    </div>
  );
}

// Range formatter shared with the YoY sub-text. Mirrors view-overview.jsx's
// formatYoyRangeNote shape. Lives here (not imported) because Babel UMD
// parses each file in global scope and we want this view self-contained
// even if view-overview.jsx loads in a different order.
function formatRgnRange(cutoffMonth, lang) {
  const m = Math.max(1, Math.min(12, cutoffMonth || 1));
  if (lang === 'en') {
    const MS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
    return m === 1 ? 'Jan' : 'Jan-' + MS[m - 1];
  }
  return m === 1 ? '1월' : ('1-' + m + '월');
}

// ─── TOP 10 models table ──────────────────────────────────────────────────────
// metric: 'krw' | 'qty' — 값 컬럼의 헤더·포맷을 메트릭에 맞춰 전환한다.
function RgnModelTable({ models, rt, metric = 'krw' }) {
  if (!models || models.length === 0) {
    return <div style={{ padding:'18px 4px', fontSize:12, color:'var(--fg-muted)' }}>—</div>;
  }
  const tdBase = { padding:'6px 8px', fontSize:12, borderBottom:'1px solid var(--divider)' };
  const valHeader = metric === 'qty' ? rt.qty : rt.revenue;
  const fmtVal = metric === 'qty'
    ? v => Number(v).toLocaleString() + (rt.qtyUnit || '')
    : v => moneyB(v);
  return (
    <table style={{ width:'100%', borderCollapse:'collapse' }}>
      <thead>
        <tr style={{ borderBottom:'1px solid var(--border)' }}>
          <th style={{ ...tdBase, color:'var(--fg-muted)', fontWeight:600, textAlign:'left', width:28 }}>{rt.rank}</th>
          <th style={{ ...tdBase, color:'var(--fg-muted)', fontWeight:600, textAlign:'left' }}>{rt.model}</th>
          <th style={{ ...tdBase, color:'var(--fg-muted)', fontWeight:600, textAlign:'right' }}>{valHeader}</th>
        </tr>
      </thead>
      <tbody>
        {models.map(([mdl, val], i) => (
          <tr key={mdl} style={{ transition:'background .12s' }}>
            <td style={{ ...tdBase, color:'var(--fg-subtle)', fontVariantNumeric:'tabular-nums' }}>{i + 1}</td>
            <td style={{ ...tdBase, color:'var(--fg-2)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap', maxWidth:200 }} title={mdl}>{mdl}</td>
            <td style={{ ...tdBase, textAlign:'right', color:'var(--fg)', fontWeight:600, fontVariantNumeric:'tabular-nums' }}>{fmtVal(val)}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

window.RegionalView = RegionalView;
