/* ============================================================
   Dashboard — zakaz va vazifa ko'rsatkichlari (faqat summa asosida)
   ============================================================ */

/* ---------- Raqamni 0 dan jonli sanab chiqadigan komponent ---------- */
function CountUp({ value, duration = 950, format }) {
  const [n, setN] = useState(0);
  const st = useRef({ raf: 0, from: 0 });
  useEffect(() => {
    const from = st.current.from;
    const t0 = performance.now();
    const tick = (t) => {
      const p = Math.min(1, (t - t0) / duration);
      const eased = 1 - Math.pow(1 - p, 3); // easeOutCubic
      setN(from + (value - from) * eased);
      if (p < 1) st.current.raf = requestAnimationFrame(tick);
      else st.current.from = value;
    };
    cancelAnimationFrame(st.current.raf);
    st.current.raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(st.current.raf);
  }, [value, duration]);
  return <>{format ? format(n) : Math.round(n)}</>;
}
const fmtMoney = (v) => DB.fmtSum(Math.round(v));

/* ---------- Regional menejerlar reytingi (sport uslubidagi podium) ---------- */
// Motivatsiya uchun — barcha rollarga ko'rinadi. Ma'lumot /api/leaderboard dan (kompaniya bo'yicha).
function rankTheme(rank) {
  if (rank === 1) return { ring: '#E3A23B', tint: 'linear-gradient(135deg,#F6E7CF,#F0D9AE)', ink: '#8F5518', medal: '🥇', label: 'Chempion' };
  if (rank === 2) return { ring: '#A39A90', tint: 'linear-gradient(135deg,#F1ECE6,#E6DFD7)', ink: '#475569', medal: '🥈', label: '2-o\'rin' };
  if (rank === 3) return { ring: '#CD7F32', tint: 'linear-gradient(135deg,#F6E7CF,#F3D5B5)', ink: '#9A5B1E', medal: '🥉', label: '3-o\'rin' };
  return { ring: 'var(--border)', tint: 'var(--bg-2)', ink: 'var(--ink-3)', medal: '', label: '' };
}

function PodiumColumn({ item, rank, max, height }) {
  const t = rankTheme(rank);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: 1, minWidth: 0 }}>
      <div style={{ position: 'relative', marginBottom: 8 }}>
        <Avatar src={item.avatar} name={item.name} size={rank === 1 ? 60 : 50} radius={999} accent={rank === 1} />
        <span style={{ position: 'absolute', bottom: -4, right: -4, fontSize: rank === 1 ? 24 : 20, lineHeight: 1 }}>{t.medal}</span>
      </div>
      <div style={{ fontWeight: 800, fontSize: rank === 1 ? 14 : 13, textAlign: 'center', lineHeight: 1.2, maxWidth: '100%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', width: '100%' }} title={item.name}>{item.name}</div>
      <div className="tnum" style={{ fontWeight: 800, fontSize: rank === 1 ? 16 : 14, color: t.ink, marginTop: 2 }}>{fmtMoney(item._val != null ? item._val : item.total)}</div>
      <div style={{ fontSize: 10.5, color: 'var(--ink-4)', marginBottom: 8 }}>{item.orders} ta zakaz</div>
      <div style={{ width: '100%', height, background: t.tint, border: '1px solid ' + t.ring, borderBottom: 'none',
                    borderRadius: '10px 10px 0 0', display: 'grid', placeItems: 'center', boxShadow: 'var(--sh-1)' }}>
        <span style={{ fontWeight: 900, fontSize: rank === 1 ? 30 : 24, color: t.ink, opacity: .85 }}>{rank}</span>
      </div>
    </div>
  );
}

function ManagerLeaderboard({ ym }) {
  // Sahifa keshi — dashboard qayta ochilganda reyting darrov ko'rsatiladi.
  const lbCached = window.PageCache ? window.PageCache.get('lb:' + (ym || '')) : null;
  const [list, setList] = useState((lbCached && lbCached.list) || null);
  const [brands, setBrands] = useState((lbCached && lbCached.brands) || []);
  const [filter, setFilter] = useState('all'); // 'all' yoki brendId
  const [err, setErr] = useState(null);
  useEffect(() => {
    let alive = true;
    const ck = 'lb:' + (ym || '');
    const hit = window.PageCache ? window.PageCache.get(ck) : null;
    // Oy o'zgarganda: kesh bo'lsa darrov ko'rsat, bo'lmasa yuklash holati.
    if (hit) { setList(hit.list); setBrands(hit.brands); } else setList(null);
    setErr(null);
    API.leaderboard(ym || undefined)
      .then((r) => {
        if (window.PageCache) window.PageCache.set(ck, { list: r.leaderboard || [], brands: r.brands || [] });
        if (alive) { setList(r.leaderboard || []); setBrands(r.brands || []); }
      })
      .catch((e) => { if (alive && !hit) setErr(e.message || 'Reytingni yuklab bo\'lmadi'); });
    return () => { alive = false; };
  }, [ym]);

  // Tanlangan filtr bo'yicha menejer "qiymati": jami yoki bitta brend summasi.
  const valueOf = (m) => (filter === 'all' ? (m.total || 0) : ((m.byBrand && m.byBrand[filter]) || 0));

  const card = (children) => (
    <div className="dx-card dx-card--pad dash-anim" style={{ marginBottom: 16, animationDelay: '.30s' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16, flexWrap: 'wrap' }}>
        <span style={{ width: 34, height: 34, borderRadius: 9, background: 'linear-gradient(135deg,#F6E7CF,#E3A23B)', color: '#8F5518', display: 'grid', placeItems: 'center' }}><Icon name="trendUp" size={18} /></span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 700, fontSize: 14.5 }}>Regional menejerlar reytingi</div>
          <div style={{ fontSize: 12, color: 'var(--ink-4)', marginTop: 2 }}>Eng ko'p savdo qilgan menejerlar — {filter === 'all' ? 'jami summa' : DB.brandName(filter) + ' brendi'} bo'yicha</div>
        </div>
        {brands.length > 0 && (
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {[{ id: 'all', name: 'Jami' }, ...brands].map((b) => {
              const on = filter === b.id;
              return (
                <button key={b.id} onClick={() => setFilter(b.id)}
                  style={{ padding: '5px 12px', borderRadius: 999, fontSize: 12, fontWeight: 700, cursor: 'pointer',
                           border: '1px solid ' + (on ? 'var(--brand)' : 'var(--border)'),
                           background: on ? 'var(--brand)' : 'var(--surface)', color: on ? 'var(--surface-solid)' : 'var(--ink-3)' }}>
                  {b.name}
                </button>
              );
            })}
          </div>
        )}
      </div>
      {children}
    </div>
  );

  if (err) return card(<div style={{ fontSize: 12.5, color: 'var(--ink-4)' }}>{err}</div>);
  if (list == null) return card(<div style={{ fontSize: 12.5, color: 'var(--ink-4)' }}>Yuklanmoqda…</div>);
  if (list.length === 0) return card(<div style={{ fontSize: 12.5, color: 'var(--ink-4)' }}>Hozircha reyting uchun ma'lumot yo'q.</div>);

  // Filtr bo'yicha qayta saralangan ro'yxat (qiymati 0 bo'lganlar pastda qoladi).
  const ranked = [...list].map((m) => ({ ...m, _val: valueOf(m) })).sort((a, b) => b._val - a._val || b.orders - a.orders);
  const top3 = ranked.slice(0, 3);
  const rest = ranked.slice(3);
  const maxTotal = Math.max(1, ...ranked.map((m) => m._val));
  // Podium ustunlari balandligi — summага proporsional (min 46px)
  const hOf = (m) => 46 + Math.round((m._val / maxTotal) * 54);
  // Ko'rsatish tartibi: 2 - 1 - 3 (markazda chempion)
  const order = [top3[1], top3[0], top3[2]].map((m, i) => m ? { m, rank: [2, 1, 3][i] } : null).filter(Boolean);

  return card(
    <div>
      <div style={{ display: 'flex', alignItems: 'flex-end', gap: 10, marginBottom: rest.length ? 18 : 0 }}>
        {order.map(({ m, rank }) => (
          <PodiumColumn key={m.managerId} item={m} rank={rank} max={maxTotal} height={hOf(m)} />
        ))}
      </div>

      {rest.length > 0 && (
        <div style={{ display: 'grid', gap: 6 }}>
          {rest.map((m, i) => {
            const rank = i + 4;
            const pct = Math.round((m._val / maxTotal) * 100);
            return (
              <div key={m.managerId} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '8px 10px', borderRadius: 10, background: 'var(--bg-2)' }}>
                <span className="tnum" style={{ width: 22, textAlign: 'center', fontWeight: 800, fontSize: 13, color: 'var(--ink-4)', flex: 'none' }}>{rank}</span>
                <Avatar src={m.avatar} name={m.name} size={30} radius={999} />
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ fontWeight: 700, fontSize: 13, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={m.name}>{m.name}</div>
                  <div style={{ height: 5, borderRadius: 3, background: 'var(--border)', marginTop: 4, overflow: 'hidden' }}>
                    <div style={{ width: pct + '%', height: '100%', background: 'var(--brand)', borderRadius: 3 }} />
                  </div>
                </div>
                <div style={{ textAlign: 'right', flex: 'none' }}>
                  <div className="tnum" style={{ fontWeight: 800, fontSize: 13 }}>{fmtMoney(m._val)}</div>
                  <div style={{ fontSize: 10.5, color: 'var(--ink-4)' }}>{m.orders} ta zakaz</div>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}


/* ---------- Reyting qatori (mahsulot / kategoriya / hodim / distributor uchun umumiy) — premium ---------- */
function StatBarList({ rows, max, accent, empty }) {
  if (!rows || rows.length === 0) return <Empty text={empty || "Bu davr uchun ma'lumot yo'q"} />;
  const ac = accent || 'var(--brand)';
  return (
    <div style={{ display: 'grid', gap: 6 }}>
      {rows.map((r, i) => (
        <div key={r.key != null ? r.key : i} className="dx-bar" title={r.name + ': ' + DB.fmtSum(r.sum) + " so'm"}>
          <div className="dx-bar__top">
            <span className="dx-bar__rank" style={i < 3 ? { background: 'color-mix(in srgb, ' + ac + ' 15%, transparent)', color: ac } : undefined}>{i + 1}</span>
            <span className="dx-bar__name">{r.name}</span>
            <div style={{ flex: 1 }} />
            {r.meta && <span className="dx-bar__meta">{r.meta}</span>}
            <span className="dx-bar__val tnum">{DB.fmtSum(r.sum)} so'm</span>
          </div>
          <div className="dx-bar__track" style={{ marginLeft: 31 }}>
            <div className="dx-bar__fill" style={{ width: (r.sum / (max || 1) * 100) + '%', background: 'linear-gradient(90deg, ' + ac + ', color-mix(in srgb, ' + ac + ' 50%, transparent))' }} />
          </div>
        </div>
      ))}
    </div>
  );
}

/* ---------- Yumaloq diagramma (donut) — live hover bilan ----------
   rows: [{ key?, name, sum, meta?, color? }]. color berilmasa — palitradan.
   Segment ↔ legend o'zaro jonli ajralib turadi; markazda jami yoki tanlangan. */
const DONUT_PALETTE = ['#EC7A55', '#2B2927', '#3DBE9C', '#E9B949', '#5A9FD4', '#8E74FF', '#D9708F', '#7FC8B5', '#C9A27E', '#9BBF5A', '#6E8FB8', '#B9A2FF'];

function DonutChart({ rows, empty, palette, onPick }) {
  const [hi, setHi] = useState(-1);
  const data = (rows || []).filter((r) => (r.sum || 0) > 0);
  if (!data.length) return <Empty text={empty || "Bu davr uchun ma'lumot yo'q"} />;
  const total = data.reduce((s, r) => s + (r.sum || 0), 0);
  const pal = palette || DONUT_PALETTE;
  const R = 70, SW = 22, C = 2 * Math.PI * R, GAP = data.length > 1 ? 2.5 : 0;
  let acc = 0;
  const segs = data.map((r, i) => {
    const frac = r.sum / total;
    const len = frac * C;
    const s = { key: r.key != null ? r.key : i, i, name: r.name, sum: r.sum, meta: r.meta, color: r.color || pal[i % pal.length], frac, len, offset: acc };
    acc += len;
    return s;
  });
  const act = hi >= 0 && hi < segs.length ? segs[hi] : null;
  const dim = (i) => (hi === -1 || hi === i ? 1 : 0.28);
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 22, flexWrap: 'wrap' }}>
      <div style={{ position: 'relative', width: 180, height: 180, flex: 'none', margin: '0 auto' }}>
        <svg width="180" height="180" viewBox="0 0 180 180" style={{ transform: 'rotate(-90deg)' }}>
          <circle cx="90" cy="90" r={R} fill="none" stroke="var(--bg-2)" strokeWidth={SW} />
          {segs.map((s) => {
            const dash = Math.max(0.5, s.len - GAP);
            return (
              <circle key={s.key} cx="90" cy="90" r={R} fill="none" stroke={s.color}
                strokeWidth={hi === s.i ? SW + 6 : SW}
                strokeDasharray={dash + ' ' + (C - dash)} strokeDashoffset={-s.offset}
                onMouseEnter={() => setHi(s.i)} onMouseLeave={() => setHi(-1)}
                onClick={() => onPick && onPick(s)}
                style={{ cursor: onPick ? 'pointer' : 'default', opacity: dim(s.i), transition: 'opacity .2s var(--ease), stroke-width .2s var(--ease)' }} />
            );
          })}
        </svg>
        <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', textAlign: 'center', pointerEvents: 'none', padding: 30 }}>
          <div>
            <div className="tnum" style={{ fontSize: 19, fontWeight: 800, letterSpacing: '-.02em', lineHeight: 1.05, color: act ? act.color : 'var(--ink)' }}>{ioShort(act ? act.sum : total)}</div>
            <div style={{ fontSize: 10.5, color: 'var(--ink-4)', fontWeight: 700, marginTop: 2, maxWidth: 116, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{act ? act.name : 'Jami'}</div>
            {act && <div className="tnum" style={{ fontSize: 11.5, fontWeight: 800, color: act.color, marginTop: 1 }}>{(act.frac * 100).toFixed(1)}%</div>}
          </div>
        </div>
      </div>
      <div style={{ flex: 1, minWidth: 188, display: 'grid', gap: 3 }}>
        {segs.map((s) => (
          <div key={s.key} onMouseEnter={() => setHi(s.i)} onMouseLeave={() => setHi(-1)}
            onClick={() => onPick && onPick(s)} title={s.name + ': ' + DB.fmtSum(s.sum) + " so'm"}
            style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '5px 8px', borderRadius: 8, cursor: onPick ? 'pointer' : 'default',
                     background: hi === s.i ? 'var(--bg-2)' : 'transparent', opacity: dim(s.i), transition: 'all .15s var(--ease)' }}>
            <span style={{ width: 11, height: 11, borderRadius: 4, background: s.color, flex: 'none', transition: 'box-shadow .15s var(--ease)', boxShadow: hi === s.i ? '0 0 0 3px color-mix(in srgb, ' + s.color + ' 32%, transparent)' : 'none' }} />
            <span style={{ fontSize: 12.5, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', minWidth: 0 }}>{s.name}</span>
            <div style={{ flex: 1 }} />
            {s.meta && <span style={{ fontSize: 10.5, color: 'var(--ink-4)', fontWeight: 600, flex: 'none' }}>{s.meta}</span>}
            <span className="tnum" style={{ fontSize: 12, fontWeight: 700, flex: 'none' }}>{DB.fmtSum(s.sum)}</span>
            <span className="tnum" style={{ fontSize: 11, color: 'var(--ink-4)', width: 44, textAlign: 'right', flex: 'none' }}>{(s.frac * 100).toFixed(1)}%</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------- Bo'lim karta sarlavhasi — premium ---------- */
function SectionHead({ icon, title, sub, tint, ink, right }) {
  return (
    <div className="dx-head">
      <span className="dx-head__ic" style={{ background: tint || 'var(--brand-tint)', color: ink || 'var(--brand-700)' }}><Icon name={icon} size={19} /></span>
      <div className="dx-head__tx">
        <div className="dx-head__t">{title}</div>
        {sub && <div className="dx-head__s">{sub}</div>}
      </div>
      {right && <div style={{ marginLeft: 'auto' }}>{right}</div>}
    </div>
  );
}

/* ============================================================
   SELL-IN (zakaz) ↔ SELL-OUT (Google Sheet) bog'langan bo'lim.
   Sell-in = platformadagi zakaz summasi (scope ichida).
   Sell-out = /api/sheet-dashboard (reja/fakt/prognoz/AKB) — token serverda.
   Ikki manba region/brend/kun bo'yicha bir-biriga bog'lanadi.
   ============================================================ */
function ioShort(v) {
  const n = Number(v) || 0, a = Math.abs(n);
  if (a >= 1e9) return (n / 1e9).toFixed(2).replace(/\.?0+$/, '') + ' mlrd';
  if (a >= 1e6) return (n / 1e6).toFixed(1).replace(/\.0$/, '') + ' mln';
  if (a >= 1e3) return Math.round(n / 1e3) + ' ming';
  return String(Math.round(n));
}
const ioPct = (v) => (Number(v || 0) * 100).toFixed(1) + '%';
const ioNorm = (s) => String(s || '').toLowerCase().replace(/[^a-z0-9]/gi, '');

// Sotuvga aylanish (sell-through) holatiga qarab rang
function ioThroughStatus(pct) {
  if (pct == null) return { ink: 'var(--ink-4)', tint: 'var(--bg-2)' };
  if (pct >= 0.9) return { ink: '#1D8A6E', tint: 'rgba(61,190,156,.14)' };
  if (pct >= 0.6) return { ink: '#A6651E', tint: 'rgba(227,162,59,.16)' };
  return { ink: '#C2453A', tint: 'rgba(232,115,95,.14)' };
}

// Joriy oy Iyul 2026+ ekanligini aniqlash (DB sell-out tizimi)
function isDbSelloutMonth() {
  const now = new Date();
  return now.getFullYear() > 2026 || (now.getFullYear() === 2026 && now.getMonth() >= 6);
}
// Joriy oy kaliti: '2026-07', '2026-08', ...
function currentSoMonth() {
  const now = new Date();
  return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
}

// Joriy oy nomi (sheet-dashboard month parametri uchun): 'iyul', 'avgust', ...
// Sell-out (Google Sheet) joriy oy varag'ini olish uchun — aks holda server Iyun default'ini qaytaradi.
const DASH_MONTH_KEYS = ['yanvar','fevral','mart','aprel','may','iyun','iyul','avgust','sentyabr','oktyabr','noyabr','dekabr'];
function dashMonthKey() {
  return DASH_MONTH_KEYS[new Date().getMonth()] || 'iyul';
}

// Zakazlarni berilgan oy kaliti (2026) bo'yicha filtrlaydi.
// Sell-out kartalari sell-in'ni AYNAN sell-out ko'rsatayotgan oy bilan solishtirishi uchun
// (aks holda oy boshida sell-out oldingi oyga tushsa-yu, sell-in joriy oyni ko'rsatsa — aylanish "—" bo'lib qoladi).
function ordersInMonthKey(orders, monthKey) {
  const mi = DASH_MONTH_KEYS.indexOf(monthKey);
  if (mi < 0) return orders || [];
  return (orders || []).filter((o) => {
    if (!o.createdAt) return false;
    const d = new Date(o.createdAt);
    return d.getFullYear() === 2026 && d.getMonth() === mi;
  });
}

// DB sell-out javobini (soSummary) sheets formatiga moslashtirish
// → ioScopeSheet uchun bir xil format
function normalizeSoSummary(soData) {
  if (!soData) return null;
  const k = soData.kpi || {};
  return {
    kpi: {
      plan: k.planSom || 0,
      fakt: k.faktSom || 0,
      prognoz: k.prognozSom || 0,
      akb: 0,
      pct: k.foiz || 0,
      prognozPct: k.prognozFoiz || 0,
      dailyTarget: k.kunlikReja || 0,
    },
    regions: (soData.regions || []).map((r) => ({
      name: r.name,
      plan: r.planSom,
      fakt: r.faktSom,
      pct: r.foiz,
      prognoz: r.prognozSom,
      akb: 0,
      byBrand: null,
    })),
    brands: null,
    daily: [],
    _source: 'db',
    _month: soData.month,
  };
}

// Tanlangan regionlar bo'yicha sell-out ma'lumotini qisqartirish/qayta hisoblash.
// regionNames bo'sh bo'lsa — butun kompaniya (sheet.kpi/brands/daily).
function ioScopeSheet(data, regionNames) {
  if (!data) return null;
  if (!regionNames || !regionNames.length) {
    return { kpi: data.kpi || {}, regions: data.regions || [], brands: data.brands || null, daily: data.daily || [], _source: data._source };
  }
  const set = new Set(regionNames.map(ioNorm));
  const regions = (data.regions || []).filter((r) => set.has(ioNorm(r.name)));
  const sum = (key) => regions.reduce((a, r) => a + (Number(r[key]) || 0), 0);
  const plan = sum('plan'), fakt = sum('fakt'), prognoz = sum('prognoz'), akb = sum('akb');
  const kpi = { plan, fakt, prognoz, akb, pct: plan ? fakt / plan : 0, prognozPct: plan ? prognoz / plan : 0 };
  let brands = null;
  if (regions.some((r) => r.byBrand)) {
    // byBrand kalitlari — brend teglari (brend nomi KATTA harfda): eski parserda {fakt}, Iyul+ parserda {faktSom}.
    const somOf = (b) => Number(b && (b.fakt != null ? b.fakt : b.faktSom)) || 0;
    brands = { other: 0 };
    regions.forEach((r) => {
      Object.entries(r.byBrand || {}).forEach(([tag, v]) => {
        const k = String(tag).toLowerCase(); brands[k] = (brands[k] || 0) + somOf(v);
      });
    });
  }
  return { kpi, regions, brands, daily: null, _source: data._source };
}

// Kichik KPI katakchasi (sell-in/out band uchun) — premium
function IoKpi({ label, value, sub, accent }) {
  return (
    <div className="dx-kpi" style={{ '--_a': accent || 'var(--accent)' }}>
      <div className="dx-kpi__l">{label}</div>
      <div className="dx-kpi__v tnum" style={{ color: accent || 'var(--ink)' }}>{value}</div>
      {sub != null && <div className="dx-kpi__s">{sub}</div>}
    </div>
  );
}

function SellInOutSection({ orders, regionNames, range, monthKey, onNavigate }) {
  // Sahifa keshi — SheetDashboard bilan bir xil kalit (bir marta yuklangani qayta ishlatiladi).
  const sioKey = 'sd:sellout:' + (monthKey || dashMonthKey());
  const sioCached = window.PageCache ? window.PageCache.get(sioKey) : null;
  const [data, setData] = useState((sioCached && sioCached.data) || null);
  const [loading, setLoading] = useState(!sioCached);
  const [err, setErr] = useState(null);
  const [tableOpen, setTableOpen] = useState(false); // region jadvali drop-down (yopiq default)
  const [sort, setSort] = useState({ key: 'fakt', dir: 'desc' }); // jadval ustun saralash
  const toggleSort = (key, strDefault) => setSort((s) =>
    s.key === key ? { key, dir: s.dir === 'asc' ? 'desc' : 'asc' } : { key, dir: strDefault ? 'asc' : 'desc' });

  useEffect(() => {
    let alive = true;
    const mk = monthKey || dashMonthKey();
    const ck = 'sd:sellout:' + mk;
    const hit = window.PageCache ? window.PageCache.get(ck) : null;
    if (hit) { setData(hit.data); setLoading(false); } else setLoading(true);
    setErr(null);
    API.sheetDashboard(false, monthKey || '')
      .then((r) => {
        if (window.PageCache) window.PageCache.set(ck, { data: r, months: r.months || [], month: r.month || mk });
        if (alive) { setData(r); setLoading(false); }
      })
      .catch((e) => { if (alive && !hit) { setErr(e.message || "Sell-out ma'lumotini yuklab bo'lmadi"); setLoading(false); } });
    return () => { alive = false; };
  }, [monthKey]);

  // Sell-in (zakaz) — sell-out AYNAN ko'rsatayotgan oy (data.month, fallback bilan) bo'yicha.
  const soMonth = (data && data.month) || monthKey;
  const sellIn = useMemo(() => {
    let total = 0; const byBrand = {}; const byRegion = {}; const byDay = {};
    DB.BRANDS.forEach((b) => { byBrand[b.id] = 0; });
    ordersInMonthKey(orders, soMonth).forEach((o) => {
      const ot = DB.orderTotal(o); total += ot;
      const rn = DB.regionName(o.region); byRegion[ioNorm(rn)] = (byRegion[ioNorm(rn)] || 0) + ot;
      if (o.createdAt) { const iso = new Date(o.createdAt).toISOString().slice(0, 10); byDay[iso] = (byDay[iso] || 0) + ot; }
      (o.lines || []).forEach((l) => {
        const v = (l.qty || 0) * (l.price || 0);
        const b = DB.brandOfProduct(l.productId);
        if (b && byBrand[b.id] != null) byBrand[b.id] += v;
      });
    });
    return { total, byBrand, byRegion, byDay };
  }, [orders, soMonth]);

  const scoped = useMemo(() => ioScopeSheet(data, regionNames), [data, regionNames]);

  // Brendlarni sheet kalitiga (brend nomi, kichik harfda) bog'lash
  const brandPair = useMemo(() => DB.BRANDS.map((b) => ({
    id: b.id, name: b.name, color: b.color || 'var(--ink-4)',
    key: DB.brandTag(b).toLowerCase(),
  })), []);

  if (loading) {
    return (
      <div className="dx-card dx-card--pad dash-anim" style={{ marginBottom: 16, color: 'var(--ink-4)', fontSize: 12.5 }}>
        <SectionHead icon="chart" title="Sell-in ↔ Sell-out bog'lanishi" sub="Sell-out ma'lumoti yuklanmoqda…" tint="rgba(142,116,255,.12)" ink="#5B45D6" />
        <div className="px-skel" style={{ width: '62%' }} /><div className="px-skel" style={{ width: '38%' }} />
      </div>
    );
  }
  if (err && /sozlanmagan|SHEETS_/i.test(err)) {
    return (
      <div className="px-note dash-anim">
        <span className="px-note__ic"><Icon name="info" size={15} /></span>
        <div><b>Sell-out manbasi ulanmagan.</b> Google Sheets ulangach bu yerda sell-in ↔ sell-out bog'lanishi va viloyatlar prognozi chiqadi.</div>
      </div>
    );
  }
  if (err || !scoped) {
    return (
      <div className="dx-card dx-card--pad dash-anim" style={{ marginBottom: 16 }}>
        <SectionHead icon="chart" title="Sell-in ↔ Sell-out bog'lanishi" sub={err || "Sell-out ma'lumoti mavjud emas"} tint="rgba(232,115,95,.12)" ink="#C2453A" />
        <div style={{ fontSize: 12.5, color: 'var(--ink-4)' }}>Sell-out manbasi (Google Sheet) hozircha ulanmagan yoki bo'sh. Sell-in (zakaz) ko'rsatkichlari yuqorida ko'rsatilgan.</div>
      </div>
    );
  }

  const k = scoped.kpi || {};
  const sellOutFakt = Number(k.fakt) || 0;
  const sellThrough = sellIn.total ? sellOutFakt / sellIn.total : null; // sotuvga aylanish
  const ts = ioThroughStatus(sellThrough);

  // Region kesimi — sell-out (sheet) + sell-in (zakaz) bir jadvalda
  const regionRows = (scoped.regions || []).map((r) => {
    const si = sellIn.byRegion[ioNorm(r.name)] || 0;
    const through = si ? (Number(r.fakt) || 0) / si : null;
    return { name: r.name, plan: Number(r.plan) || 0, fakt: Number(r.fakt) || 0, pct: Number(r.pct) || 0, sellIn: si, through };
  }).sort((a, b) => {
    const dir = sort.dir === 'asc' ? 1 : -1;
    if (sort.key === 'name') return dir * String(a.name).localeCompare(String(b.name), 'uz');
    const av = a[sort.key] == null ? -Infinity : a[sort.key];
    const bv = b[sort.key] == null ? -Infinity : b[sort.key];
    return dir * (av - bv);
  });
  const maxRegFakt = Math.max(1, ...regionRows.map((r) => Math.max(r.fakt, r.sellIn)));

  // Kunlik: sell-out (sheet.daily) ustiga sell-in (zakaz) — faqat scope bo'lmaganda (daily mavjud)
  const dailyRows = (scoped.daily || []).map((d) => ({
    label: d.date, iso: d.iso, out: Number(d.total) || 0, in: (d.iso && sellIn.byDay[d.iso]) || 0,
  })).filter((d) => d.out > 0 || d.in > 0);
  const maxDaily = Math.max(1, ...dailyRows.map((d) => Math.max(d.out, d.in)));

  const rangeDays = range === 'day' ? '1 kun' : range === 'week' ? "so'nggi 7 kun" : range === 'year' ? "so'nggi 1 yil" : "so'nggi 30 kun";
  const rangeNote = range && range !== 'all'
    ? ("Sell-in: " + rangeDays + " · Sell-out: Google Sheets (joriy oy)")
    : "Sell-in: barcha zakazlar · Sell-out: oylik reja/fakt (Google Sheets)";

  return (
    <div className="dx-card dx-card--pad dash-anim" style={{ marginBottom: 16, animationDelay: '.32s' }}>
      <SectionHead icon="chart" title="Sell-in ↔ Sell-out bog'lanishi"
        sub={rangeNote} tint="rgba(142,116,255,.12)" ink="#5B45D6"
        right={
          <button className="btn btn--ghost" onClick={() => onNavigate && onNavigate('region')} style={{ gap: 6, fontSize: 12, padding: '6px 11px' }}><Icon name="arrowR" size={13} /> Sell-out batafsil</button>
        } />

      {/* Bog'langan KPI band */}
      <div className="dx-g3" style={{ marginBottom: 16 }}>
        <IoKpi label="Sell-in (zakaz)" value={ioShort(sellIn.total)} sub={DB.fmtSum(sellIn.total) + " so'm"} accent="var(--brand-700)" />
        <IoKpi label="Sell-out (fakt)" value={ioShort(sellOutFakt)} sub={ioPct(k.pct) + ' rejadan'} />
        <IoKpi label="Sotuvga aylanish" value={sellThrough != null ? ioPct(sellThrough) : '—'} sub="sell-out / sell-in" accent={ts.ink} />
        <IoKpi label="Reja bajarilishi" value={ioPct(k.pct)} sub={'reja: ' + ioShort(k.plan)} />
        <IoKpi label="Prognoz" value={ioShort(k.prognoz)} sub={ioPct(k.prognozPct) + ' rejadan'} />
        <IoKpi label="AKB" value={k.akb ? DB.fmtSum(k.akb) : '—'} sub="faol mijozlar" />
      </div>

      {/* Sotuvga aylanish izohi */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', borderRadius: 10, background: ts.tint, marginBottom: 16, fontSize: 12.5, color: 'var(--ink-2)', flexWrap: 'wrap' }}>
        <span style={{ fontWeight: 700, color: ts.ink }}>Sotuvga aylanish {sellThrough != null ? ioPct(sellThrough) : '—'}</span>
        <span style={{ color: 'var(--ink-4)' }}>·</span>
        <span>Zakaz qilingan <b className="tnum">{ioShort(sellIn.total)}</b> so'mdan bozorga <b className="tnum">{ioShort(sellOutFakt)}</b> so'm sotilgan
          {sellThrough != null && sellThrough < 0.6 ? ' — sklad qoldig‘i yuqori bo‘lishi mumkin.' : ''}</span>
      </div>

      {/* Region kesimi jadvali: sell-out reja/fakt + sell-in + aylanish */}
      {regionRows.length > 0 && (
        <div style={{ border: '1px solid var(--border)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>
          <button onClick={() => setTableOpen((v) => !v)}
            style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 8, padding: '12px 16px', fontSize: 13, fontWeight: 700,
                     background: tableOpen ? 'var(--bg-2)' : 'transparent', border: 'none', borderBottom: tableOpen ? '1px solid var(--border)' : 'none',
                     cursor: 'pointer', userSelect: 'none', textAlign: 'left', color: 'var(--ink-1)' }}>
            <span style={{ display: 'inline-block', transition: 'transform .18s', transform: tableOpen ? 'rotate(90deg)' : 'none', color: 'var(--ink-4)' }}>▶</span>
            <span>Region bo'yicha: Sell-in ↔ Sell-out</span>
            <span style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--ink-4)' }}>({regionRows.length})</span>
            <div style={{ flex: 1 }} />
            <span style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--ink-4)' }}>{tableOpen ? 'Yashirish' : "Ko'rsatish"}</span>
          </button>
          {tableOpen && (
          <div style={{ overflowX: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5, minWidth: 620 }}>
              <thead>
                <tr style={{ textAlign: 'right', color: 'var(--ink-4)', fontSize: 11, textTransform: 'uppercase', letterSpacing: '.03em' }}>
                  {[
                    { key: 'name', label: 'Region', str: true, align: 'left', pad: '8px 16px' },
                    { key: 'plan', label: 'Sell-out reja', pad: '8px 12px' },
                    { key: 'fakt', label: 'Sell-out fakt', pad: '8px 12px' },
                    { key: 'pct', label: 'Bajarilish', pad: '8px 12px' },
                    { key: 'sellIn', label: 'Sell-in (zakaz)', pad: '8px 12px' },
                    { key: 'through', label: 'Aylanish', pad: '8px 16px' },
                  ].map((col) => {
                    const active = sort.key === col.key;
                    return (
                      <th key={col.key} onClick={() => toggleSort(col.key, col.str)}
                        title="Saralash uchun bosing (A-Z / Z-A)"
                        style={{ textAlign: col.align || 'right', padding: col.pad, fontWeight: active ? 800 : 600,
                                 cursor: 'pointer', userSelect: 'none', whiteSpace: 'nowrap', color: active ? 'var(--brand-700)' : 'var(--ink-4)' }}>
                        {col.label}
                        <span style={{ marginLeft: 4, opacity: active ? 1 : 0.35, fontSize: 10 }}>{active ? (sort.dir === 'asc' ? '▲' : '▼') : '↕'}</span>
                      </th>
                    );
                  })}
                </tr>
              </thead>
              <tbody>
                {regionRows.map((r, i) => {
                  const rt = ioThroughStatus(r.through);
                  return (
                    <tr key={i} style={{ borderTop: '1px solid var(--border)' }}>
                      <td style={{ textAlign: 'left', padding: '9px 16px', fontWeight: 600 }}>{r.name}</td>
                      <td className="tnum" style={{ textAlign: 'right', padding: '9px 12px', color: 'var(--ink-3)' }}>{ioShort(r.plan)}</td>
                      <td style={{ textAlign: 'right', padding: '9px 12px' }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 7, justifyContent: 'flex-end' }}>
                          <div style={{ width: 50, height: 6, borderRadius: 4, background: 'var(--bg-2)', overflow: 'hidden' }}>
                            <div style={{ width: Math.min(100, r.fakt / maxRegFakt * 100) + '%', height: '100%', borderRadius: 4, background: 'var(--brand)' }} />
                          </div>
                          <b className="tnum" style={{ minWidth: 56, textAlign: 'right' }}>{ioShort(r.fakt)}</b>
                        </div>
                      </td>
                      <td style={{ textAlign: 'right', padding: '9px 12px' }}>
                        <span className="tnum" style={{ display: 'inline-block', minWidth: 50, textAlign: 'center', padding: '2px 8px', borderRadius: 999, fontWeight: 700, fontSize: 11.5, background: sdStatusTint(r.pct), color: sdStatusInk(r.pct) }}>{ioPct(r.pct)}</span>
                      </td>
                      <td style={{ textAlign: 'right', padding: '9px 12px' }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 7, justifyContent: 'flex-end' }}>
                          <div style={{ width: 50, height: 6, borderRadius: 4, background: 'var(--bg-2)', overflow: 'hidden' }}>
                            <div style={{ width: Math.min(100, r.sellIn / maxRegFakt * 100) + '%', height: '100%', borderRadius: 4, background: 'var(--brand-700)' }} />
                          </div>
                          <b className="tnum" style={{ minWidth: 56, textAlign: 'right' }}>{ioShort(r.sellIn)}</b>
                        </div>
                      </td>
                      <td style={{ textAlign: 'right', padding: '9px 16px' }}>
                        <span className="tnum" style={{ fontWeight: 700, color: rt.ink }}>{r.through != null ? ioPct(r.through) : '—'}</span>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
          )}
        </div>
      )}

    </div>
  );
}

// Sheet bajarilish foiziga qarab rang (region jadvalidagi badge uchun)
function sdStatusTint(pct) { return pct >= 1 ? 'rgba(61,190,156,.14)' : pct >= 0.7 ? 'rgba(227,162,59,.16)' : 'rgba(232,115,95,.14)'; }
function sdStatusInk(pct) { return pct >= 1 ? '#1D8A6E' : pct >= 0.7 ? '#A6651E' : '#C2453A'; }

// Prognoz holatiga qarab rang: yashil = yaxshi, sariq = xavf bor, qizil = orqada qolyapti.
// pct = prognoz / reja (oy oxiriga rejaga nisbatan kutilayotgan natija).
function fcStatus(pct) {
  if (pct == null) return { label: "Ma'lumotsiz", ink: 'var(--ink-4)', tint: 'var(--bg-2)', border: 'var(--border)', dot: 'var(--ink-4)' };
  if (pct >= 1) return { label: 'Yaxshi', ink: '#1D8A6E', tint: 'rgba(61,190,156,.10)', border: 'rgba(61,190,156,.45)', dot: '#3DBE9C' };
  if (pct >= 0.8) return { label: 'Xavf bor', ink: '#A6651E', tint: 'rgba(227,162,59,.12)', border: 'rgba(227,162,59,.5)', dot: '#E3A23B' };
  return { label: 'Orqada', ink: '#C2453A', tint: 'rgba(232,115,95,.10)', border: 'rgba(232,115,95,.45)', dot: '#E8735F' };
}

// Sheet region nomi -> DB region (nomlarni normalizatsiya + qisman moslik bilan).
function fcRegion(regionName) {
  const norm = ioNorm(regionName);
  return (DB.REGIONS || []).find((r) => ioNorm(r.name) === norm)
    || (DB.REGIONS || []).find((r) => { const rn = ioNorm(r.name); return rn && (rn.includes(norm) || norm.includes(rn)); })
    || null;
}

// Brend tegi (brend nomi KATTA harfda) -> DB brend id.
function fcBrandId(tag) {
  const b = DB.brandByTag(tag);
  return b ? b.id : null;
}

// DB brend id -> qisqa yorliq (brend nomi KATTA harfda).
function fcBrandLabel(brandId) {
  const b = (DB.BRANDS || []).find((x) => x.id === brandId);
  return b ? DB.brandTag(b) : '';
}

// Viloyat + brend filtri bo'yicha javobgar menejer(lar): [{ name, brandLabel }].
// 'all'   — viloyatdagi barcha brend uyalari egalari (bitta odam ikkalasini boshqarsa — bitta qator).
// <BREND TEGI> — aniq shu brend uyasining egasi.
function fcManagers(regionName, brandFilter) {
  const reg = fcRegion(regionName);
  if (!reg) return [];
  // Brend bo'yicha aniq filtr
  if (brandFilter && brandFilter !== 'all') {
    const bid = fcBrandId(brandFilter);
    const u = bid ? DB.regionBrandManager(reg.id, bid) : null;
    if (u) return [{ name: u.name, brandLabel: '' }];
    // Aniq brend uyasi yo'q — viloyat bo'yicha umumiy egasi (brandId yo'q) bo'lsa
    const generic = DB.regionManagers(reg.id).find((m) => m.brandId == null);
    return generic ? [{ name: generic.user.name, brandLabel: '' }] : [];
  }
  // 'all' — barcha egalar
  const list = DB.regionManagers(reg.id);
  const byUser = new Map(); // userId -> { name, brands:Set }
  for (const m of list) {
    if (!m.user) continue;
    const e = byUser.get(m.user.id) || { name: m.user.name, brands: new Set() };
    if (m.brandId != null) e.brands.add(m.brandId);
    byUser.set(m.user.id, e);
  }
  const users = [...byUser.values()];
  // Bitta odam butun viloyatni boshqaradi — brend yorlig'isiz bitta qator.
  if (users.length <= 1) return users.map((u) => ({ name: u.name, brandLabel: '' }));
  // Bir nechta egasi — har birini boshqaradigan brend(lar) yorlig'i bilan.
  return users.map((u) => ({
    name: u.name,
    brandLabel: [...u.brands].map(fcBrandLabel).filter(Boolean).join(' · '),
  }));
}

/* ============================================================
   Ixcham oylik viloyat kartochkalari — har bir viloyat bo'yicha
   sell-in (zakaz) ↔ sell-out (sheet) + javobgar menejer.
   Prognoz holatiga qarab rang: yashil / sariq / qizil.
   ============================================================ */
function RegionForecastCards({ orders, regionNames, monthKey, onNavigate }) {
  // Sahifa keshi — SheetDashboard/SellInOutSection bilan bir xil kalit.
  const rfcCached = window.PageCache ? window.PageCache.get('sd:sellout:' + (monthKey || dashMonthKey())) : null;
  const [data, setData] = useState((rfcCached && rfcCached.data) || null);
  const [loading, setLoading] = useState(!rfcCached);
  const [err, setErr] = useState(null);
  const [brandFilter, setBrandFilter] = useState('all'); // 'all' | <BREND TEGI>

  useEffect(() => {
    let alive = true;
    const mk = monthKey || dashMonthKey();
    const ck = 'sd:sellout:' + mk;
    const hit = window.PageCache ? window.PageCache.get(ck) : null;
    if (hit) { setData(hit.data); setLoading(false); } else setLoading(true);
    setErr(null);
    API.sheetDashboard(false, monthKey || '')
      .then((r) => {
        if (window.PageCache) window.PageCache.set(ck, { data: r, months: r.months || [], month: r.month || mk });
        if (alive) { setData(r); setLoading(false); }
      })
      .catch((e) => { if (alive && !hit) { setErr(e.message || "Ma'lumotni yuklab bo'lmadi"); setLoading(false); } });
    return () => { alive = false; };
  }, [monthKey]);

  // Sell-in (zakaz) — viloyat bo'yicha, brend kesimi bilan { total, [BREND TEGI]: summa }
  // Sell-out AYNAN ko'rsatayotgan oy (data.month, fallback bilan) bo'yicha filtrlanadi.
  const soMonth = (data && data.month) || monthKey;
  const sellInByRegion = useMemo(() => {
    const m = {};
    ordersInMonthKey(orders, soMonth).forEach((o) => {
      const rk = ioNorm(DB.regionName(o.region));
      const slot = m[rk] || (m[rk] = { total: 0 });
      slot.total += DB.orderTotal(o);
      (o.lines || []).forEach((l) => {
        const v = (l.qty || 0) * (l.price || 0);
        const b = DB.brandOfProduct(l.productId);
        const tag = b ? DB.brandTag(b) : null;
        if (tag) slot[tag] = (slot[tag] || 0) + v;
      });
    });
    return m;
  }, [orders, soMonth]);

  const rows = useMemo(() => {
    if (!data) return [];
    const set = regionNames && regionNames.length ? new Set(regionNames.map(ioNorm)) : null;
    const bf = brandFilter;
    return (data.regions || [])
      .filter((r) => !set || set.has(ioNorm(r.name)))
      .map((r) => {
        const bb = (r.byBrand && r.byBrand[bf]) || null;
        // Iyul+ parser byBrand'da planSom/faktSom/prognozSom (so'm); eski parserda plan/fakt/prognoz — ikkalasi qo'llab-quvvatlanadi.
        const plan = bf === 'all' ? (Number(r.plan) || 0) : (Number(bb && (bb.plan != null ? bb.plan : bb.planSom)) || 0);
        const fakt = bf === 'all' ? (Number(r.fakt) || 0) : (Number(bb && (bb.fakt != null ? bb.fakt : bb.faktSom)) || 0);
        const prognoz = bf === 'all' ? (Number(r.prognoz) || 0) : (Number(bb && (bb.prognoz != null ? bb.prognoz : bb.prognozSom)) || 0);
        const siSlot = sellInByRegion[ioNorm(r.name)] || {};
        const sellIn = bf === 'all' ? (siSlot.total || 0) : (siSlot[bf] || 0);
        return {
          name: r.name, plan, fakt, prognoz,
          pct: plan ? fakt / plan : 0,
          prognozPct: plan ? prognoz / plan : null,
          sellIn,
          managers: fcManagers(r.name, bf),
        };
      })
      // Brend filtrida shu brend rejasi yo'q viloyatlarni ko'rsatmaymiz (chalkashmaslik uchun)
      .filter((r) => bf === 'all' || r.plan > 0 || r.fakt > 0 || r.sellIn > 0)
      .sort((a, b) => (b.prognozPct || 0) - (a.prognozPct || 0));
  }, [data, regionNames, sellInByRegion, brandFilter]);

  if (loading) {
    return (
      <div className="dash-anim" style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-lg)', padding: '18px 20px', boxShadow: 'var(--sh-1)', marginBottom: 18, animationDelay: '.18s' }}>
        <SectionHead icon="pin" title="Viloyatlar bo'yicha oylik prognoz" sub="Yuklanmoqda…" tint="rgba(142,116,255,.12)" ink="#5B45D6" />
        <div className="px-skel" style={{ width: '55%' }} /><div className="px-skel" style={{ width: '30%' }} />
      </div>
    );
  }
  if (err && /sozlanmagan|SHEETS_/i.test(err)) return null; // yuqoridagi ixcham xabar yetarli
  if (err || !rows.length) {
    return (
      <div className="dash-anim" style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-lg)', padding: '18px 20px', boxShadow: 'var(--sh-1)', marginBottom: 18, animationDelay: '.18s' }}>
        <SectionHead icon="pin" title="Viloyatlar bo'yicha oylik prognoz" sub={err || "Sell-out ma'lumoti hozircha mavjud emas"} tint="rgba(232,115,95,.12)" ink="#C2453A" />
      </div>
    );
  }

  // Holat bo'yicha umumiy sanoq (yashil / sariq / qizil)
  const tally = { ok: 0, risk: 0, bad: 0 };
  rows.forEach((r) => {
    const p = r.prognozPct;
    if (p == null) return;
    if (p >= 1) tally.ok++; else if (p >= 0.8) tally.risk++; else tally.bad++;
  });

  return (
    <div className="dash-anim" style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-lg)', padding: '18px 20px', boxShadow: 'var(--sh-1)', marginBottom: 18, animationDelay: '.18s' }}>
      <SectionHead icon="pin" title="Viloyatlar bo'yicha oylik prognoz"
        sub="Sell-in (zakaz) ↔ Sell-out (oylik reja/fakt) · javobgar menejer"
        tint="rgba(142,116,255,.12)" ink="#5B45D6"
        right={
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
            <div style={{ display: 'inline-flex', gap: 2, padding: 3, borderRadius: 999, background: 'var(--bg-2)', border: '1px solid var(--border)' }}>
              {[['all', 'Hammasi'], ...(DB.BRANDS || []).map((b) => [DB.brandTag(b), b.name])].map(([k, lbl]) => {
                const on = brandFilter === k;
                return (
                  <button key={k} onClick={() => setBrandFilter(k)}
                    style={{ border: 'none', cursor: 'pointer', fontSize: 11.5, fontWeight: on ? 800 : 600, padding: '5px 12px', borderRadius: 999,
                             background: on ? 'var(--accent, var(--brand))' : 'transparent', color: on ? 'var(--accent-ink, #fff)' : 'var(--ink-3)', transition: 'all .15s' }}>
                    {lbl}
                  </button>
                );
              })}
            </div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', fontSize: 11, fontWeight: 700 }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, color: '#1D8A6E' }}><span className="dot" style={{ width: 8, height: 8, background: '#3DBE9C' }} /> {tally.ok} yaxshi</span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, color: '#A6651E' }}><span className="dot" style={{ width: 8, height: 8, background: '#E3A23B' }} /> {tally.risk} xavf</span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, color: '#C2453A' }}><span className="dot" style={{ width: 8, height: 8, background: '#E8735F' }} /> {tally.bad} orqada</span>
            </div>
          </div>
        } />

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(218px, 1fr))', gap: 12 }}>
        {rows.map((r, i) => {
          const st = fcStatus(r.prognozPct);
          return (
            <div key={i} style={{ border: '1px solid ' + st.border, background: st.tint, borderRadius: 'var(--r-lg)', padding: '13px 14px', display: 'flex', flexDirection: 'column', gap: 9 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span className="dot" style={{ width: 9, height: 9, background: st.dot, flex: 'none' }} />
                <span style={{ fontWeight: 800, fontSize: 13.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', minWidth: 0 }} title={r.name}>{r.name}</span>
                <div style={{ flex: 1 }} />
                <span style={{ fontSize: 10, fontWeight: 800, color: st.ink, background: 'var(--surface)', borderRadius: 999, padding: '2px 8px', flex: 'none' }}>{st.label}</span>
              </div>

              <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                {r.managers.length === 0 && (
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11.5, color: 'var(--ink-4)' }}>
                    <Icon name="user" size={13} stroke={2} />
                    <span style={{ fontWeight: 600 }}>Menejer biriktirilmagan</span>
                  </div>
                )}
                {r.managers.map((m, mi) => (
                  <div key={mi} style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11.5, color: 'var(--ink-3)' }}>
                    <Icon name="user" size={13} stroke={2} />
                    {m.brandLabel && <span style={{ fontSize: 9, fontWeight: 800, color: 'var(--ink-4)', background: 'var(--bg-2)', borderRadius: 999, padding: '1px 6px', flex: 'none' }}>{m.brandLabel}</span>}
                    <span style={{ fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', minWidth: 0 }} title={m.name}>{m.name}</span>
                  </div>
                ))}
              </div>

              <div style={{ display: 'flex', alignItems: 'baseline', gap: 7 }}>
                <span className="tnum" style={{ fontSize: 23, fontWeight: 800, color: st.ink, lineHeight: 1, letterSpacing: '-.02em' }}>{r.prognozPct != null ? ioPct(r.prognozPct) : '—'}</span>
                <span style={{ fontSize: 10.5, color: 'var(--ink-4)', fontWeight: 600 }}>prognoz / reja</span>
              </div>

              <div>
                <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10.5, color: 'var(--ink-4)', marginBottom: 3 }}>
                  <span>Bajarilish (fakt/reja)</span>
                  <span className="tnum" style={{ fontWeight: 700, color: 'var(--ink-2)' }}>{ioPct(r.pct)}</span>
                </div>
                <div style={{ height: 6, borderRadius: 4, background: 'var(--bg-2)', overflow: 'hidden' }}>
                  <div style={{ width: Math.min(100, r.pct * 100) + '%', height: '100%', borderRadius: 4, background: st.dot }} />
                </div>
              </div>

              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 6, borderTop: '1px solid var(--border)', paddingTop: 8 }}>
                <div><div style={{ fontSize: 9.5, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '.03em' }}>Reja</div><div className="tnum" style={{ fontWeight: 700, fontSize: 12 }}>{ioShort(r.plan)}</div></div>
                <div><div style={{ fontSize: 9.5, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '.03em' }}>Fakt</div><div className="tnum" style={{ fontWeight: 700, fontSize: 12 }}>{ioShort(r.fakt)}</div></div>
                <div><div style={{ fontSize: 9.5, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '.03em' }}>Sell-in</div><div className="tnum" style={{ fontWeight: 700, fontSize: 12, color: 'var(--brand-700)' }}>{ioShort(r.sellIn)}</div></div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ============================================================
   Brend ulushi — brendlar bo'yicha ko'p segmentli donut diagramma.
   `by` — brendId bo'yicha summa; `total` — umumiy summa.
   ============================================================ */
function BrandShareCard({ by, total, title = 'Brend ulushi' }) {
  const items = (DB.BRANDS || [])
    .map((b) => ({ id: b.id, name: b.name, color: b.color || 'var(--ink-4)', value: (by && by[b.id]) || 0 }))
    .filter((x) => x.value > 0)
    .sort((a, b) => b.value - a.value);
  const sum = total || items.reduce((s, x) => s + x.value, 0);
  const R = 54, SW = 20, C = 2 * Math.PI * R;
  let acc = 0;
  const lead = items[0];
  const leadPct = sum && lead ? Math.round(lead.value / sum * 100) : 0;

  return (
    <div className="dx-card dx-card--pad dash-anim" style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 26, flexWrap: 'wrap', animationDelay: '.04s' }}>
      <div style={{ position: 'relative', width: 148, height: 148, flex: 'none' }}>
        <svg width="148" height="148" viewBox="0 0 148 148" style={{ transform: 'rotate(-90deg)' }}>
          <circle cx="74" cy="74" r={R} fill="none" stroke="var(--bg-2)" strokeWidth={SW} />
          {sum > 0 && items.map((it) => {
            const len = (it.value / sum) * C;
            const seg = (
              <circle key={it.id} cx="74" cy="74" r={R} fill="none" stroke={it.color} strokeWidth={SW}
                strokeDasharray={len + ' ' + (C - len)} strokeDashoffset={-acc}
                style={{ transition: 'stroke-dasharray .6s var(--ease), stroke-dashoffset .6s var(--ease)' }} />
            );
            acc += len;
            return seg;
          })}
        </svg>
        <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', textAlign: 'center' }}>
          <div>
            <div className="tnum" style={{ fontSize: 22, fontWeight: 800, letterSpacing: '-.02em', lineHeight: 1, color: lead ? lead.color : 'var(--ink)' }}>{leadPct}%</div>
            <div style={{ fontSize: 10.5, color: 'var(--ink-4)', fontWeight: 700, marginTop: 2 }}>{lead ? lead.name : '—'}</div>
          </div>
        </div>
      </div>
      <div style={{ flex: 1, minWidth: 200 }}>
        <div style={{ fontSize: 14.5, fontWeight: 700, marginBottom: 14, display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ width: 30, height: 30, borderRadius: 8, background: 'var(--brand-tint)', color: 'var(--brand-700)', display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name="chart" size={16} /></span>
          {title}
          <div style={{ flex: 1 }} />
          <span className="tnum" style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink-3)' }}>Jami: {ioShort(sum)} so'm</span>
        </div>
        <div style={{ display: 'grid', gap: 11 }}>
          {items.length === 0 && <div style={{ fontSize: 12.5, color: 'var(--ink-4)' }}>Bu davr uchun ma'lumot yo'q</div>}
          {items.map((it) => {
            const pct = sum ? it.value / sum * 100 : 0;
            return (
              <div key={it.id}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 5 }}>
                  <span className="dot" style={{ width: 11, height: 11, background: it.color, flex: 'none' }} />
                  <span style={{ fontWeight: 700, fontSize: 13 }}>{it.name}</span>
                  <div style={{ flex: 1 }} />
                  <span className="tnum" style={{ fontWeight: 800, fontSize: 13.5 }}>{pct.toFixed(1)}%</span>
                  <span className="tnum" style={{ fontSize: 11.5, color: 'var(--ink-4)', minWidth: 78, textAlign: 'right' }}>{ioShort(it.value)} so'm</span>
                </div>
                <div style={{ height: 8, borderRadius: 100, background: 'var(--bg-2)', overflow: 'hidden' }}>
                  <div style={{ width: pct + '%', height: '100%', borderRadius: 100, background: it.color, transition: 'width .6s var(--ease)' }} />
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function Dashboard({ orders, tasks = [], taskLists = [], onNavigate, perms = {}, scopeLabel = null, scopeRegionIds = null, isSuper = false }) {
  const [range, setRange] = useState('all'); // all | week | month
  const [overdueOpen, setOverdueOpen] = useState(false);
  const [mgrFilter, setMgrFilter] = useState('all'); // 'all' yoki regional menejer userId
  const RANGES = [['all', 'Hammasi'], ['day', 'Kunlik'], ['week', 'Haftalik'], ['month', 'Oylik'], ['year', 'Yillik']];
  const go = (v) => { if (onNavigate) onNavigate(v); };

  // ====== Oy tanlash (kalendar oy bo'yicha) ======
  // 'all' = davr (range) filtri ishlaydi; aks holda tanlangan 2026 oyi bo'yicha HAMMA ko'rsatkich.
  // Default (va har yangilanganda) — JORIY oy; "Barcha oylar"ни foydalanuvchi o'zi tanlaydi.
  const [month, setMonth] = useState(dashMonthKey());
  const MONTH_YEAR = 2026;
  const MONTH_LABELS = ['Yanvar', 'Fevral', 'Mart', 'Aprel', 'May', 'Iyun', 'Iyul', 'Avgust', 'Sentyabr', 'Oktyabr', 'Noyabr', 'Dekabr'];
  const monthOptions = useMemo(() => {
    const now = new Date();
    const upto = now.getFullYear() > MONTH_YEAR ? 11 : now.getMonth();
    const arr = [{ key: 'all', label: 'Barcha oylar' }];
    for (let i = 0; i <= upto; i++) arr.push({ key: DASH_MONTH_KEYS[i], label: MONTH_LABELS[i] + ' ' + MONTH_YEAR });
    return arr;
  }, []);
  // Sell-out (Google Sheet) uchun oy kaliti: 'all' bo'lsa joriy oy.
  const soMonthKey = month === 'all' ? dashMonthKey() : month;
  // Reyting uchun oy satri (YYYY-MM): 'all' bo'lsa null (barcha vaqt).
  const lbYm = month === 'all' ? null : `${MONTH_YEAR}-${String(DASH_MONTH_KEYS.indexOf(month) + 1).padStart(2, '0')}`;

  // Viloyatga biriktirilgan regional menejerlar ro'yxati (filtr uchun) — hammaga ko'rinadi
  const managerOptions = useMemo(() => {
    const seen = new Map();
    (DB.REGIONS || []).forEach(r => {
      if (r.managerId && !seen.has(r.managerId)) {
        const u = (DB.USERS || []).find(x => x.id === r.managerId);
        if (u) seen.set(r.managerId, u);
      }
    });
    return [...seen.values()].sort((a, b) => (a.name || '').localeCompare(b.name || ''));
  }, []);

  // Tanlangan menejer bo'yicha zakazlarni kesish (faqat o'sha menejer viloyatlari)
  const mgrRegionIds = useMemo(
    () => (mgrFilter === 'all' ? null : DB.userRegionIds(mgrFilter)),
    [mgrFilter]
  );
  const baseOrders = useMemo(
    () => (mgrRegionIds ? orders.filter(o => mgrRegionIds.includes(o.region)) : orders),
    [orders, mgrRegionIds]
  );
  const mgrLabel = mgrFilter === 'all' ? null
    : (mgrRegionIds || []).map(id => DB.regionName(id)).join(', ');

  // Sheet (sell-out) bo'limlari uchun viloyat doirasi:
  //  - superadmin menejer filtrini tanlasa — o'sha menejer viloyatlari;
  //  - regional menejer o'z profilidan kirsa — faqat o'ziga biriktirilgan viloyatlar;
  //  - aks holda (superadmin, filtrsiz) — barcha viloyatlar.
  const effRegionNames = useMemo(() => {
    if (mgrLabel) return (mgrRegionIds || []).map(id => DB.regionName(id));
    if (scopeRegionIds && scopeRegionIds.length) return scopeRegionIds.map(id => DB.regionName(id));
    return null;
  }, [mgrLabel, mgrRegionIds, scopeRegionIds]);

  // Zakazlarni filtrlash: oy tanlangan bo'lsa — o'sha kalendar oy (createdAt);
  // aks holda — tanlangan davr (range) bo'yicha (real time oyna).
  const fOrders = useMemo(() => {
    if (month !== 'all') {
      const mi = DASH_MONTH_KEYS.indexOf(month);
      return baseOrders.filter(o => {
        if (!o.createdAt) return false;
        const d = new Date(o.createdAt);
        return d.getFullYear() === MONTH_YEAR && d.getMonth() === mi;
      });
    }
    if (range === 'all') return baseOrders;
    const days = range === 'day' ? 1 : range === 'week' ? 7 : range === 'year' ? 365 : 30;
    const cutoff = Date.now() - days * 86400000;
    return baseOrders.filter(o => o.createdAt && new Date(o.createdAt).getTime() >= cutoff);
  }, [baseOrders, range, month]);

  // Zakazlar ro'yxatini brend bo'yicha summalarga ajratadi
  function splitByBrand(list) {
    const by = {}; DB.BRANDS.forEach(b => { by[b.id] = 0; });
    let total = 0;
    list.forEach(o => (o.lines || []).forEach(l => {
      const v = (l.qty || 0) * (l.price || 0);
      total += v;
      const b = DB.brandOfProduct(l.productId);
      if (b && by[b.id] != null) by[b.id] += v;
    }));
    return { total, by };
  }

  const all = splitByBrand(fOrders);
  const delivered = splitByBrand(fOrders.filter(o => o.status === 'delivered'));
  const planned = splitByBrand(fOrders.filter(o => o.status === 'planned'));
  const unplanned = splitByBrand(fOrders.filter(o => o.status === 'unplanned'));

  const count = fOrders.length;
  const avgTotal = count ? Math.round(all.total / count) : 0;
  const avgBy = {}; DB.BRANDS.forEach(b => { avgBy[b.id] = count ? Math.round(all.by[b.id] / count) : 0; });

  // Faqat summa ko'rsatkichlari — har biri brendlar bo'yicha ko'rinadi
  const cards = [
    { label: 'Jami zakazlar summasi', value: all.total, by: all.by, icon: 'coin' },
    { label: 'Yetkazilgan summasi', value: delivered.total, by: delivered.by, icon: 'truck' },
    { label: "O'rtacha chek summasi", value: avgTotal, by: avgBy, icon: 'trendUp', sub: count + ' ta zakaz' },
    { label: 'Rejalangan summasi', value: planned.total, by: planned.by, icon: 'cal' },
    { label: 'Rejalanmagan summasi', value: unplanned.total, by: unplanned.by, icon: 'box' },
  ];

  // Muddati o'tib ketgan (kechikkan) zakazlar — deadline o'tgan va yetkazilmagan
  const overdueOrders = useMemo(() => {
    const now = Date.now();
    return fOrders
      .filter(o => o.deadline && new Date(o.deadline).getTime() < now && o.status !== 'delivered')
      .sort((a, b) => new Date(a.deadline) - new Date(b.deadline));
  }, [fOrders]);
  const overdueSum = overdueOrders.reduce((s, o) => s + DB.orderTotal(o), 0);

  // ====== DISTRIBUTSIYA PULSI — mahsulot / kategoriya / hodim / distributor kesimi ======
  const pulse = useMemo(() => {
    const prodMap = {};   // productId -> { qty, sum }
    const catMap = {};    // catId     -> { qty, sum }
    const empMap = {};    // hodim nomi-> { orders, sum, qty }
    const distMap = {};   // distId    -> { orders, sum, qty }
    let totalQty = 0, deliveredCount = 0;

    fOrders.forEach(o => {
      const ot = DB.orderTotal(o);
      if (o.status === 'delivered') deliveredCount++;

      // Distributor kesimi
      const dk = o.distributorId || '—';
      const d = distMap[dk] || (distMap[dk] = { orders: 0, sum: 0, qty: 0 });
      d.orders++; d.sum += ot;

      // Hodim (zakazni kiritgan) kesimi
      const ek = o.createdBy || '—';
      const e = empMap[ek] || (empMap[ek] = { orders: 0, sum: 0, qty: 0 });
      e.orders++; e.sum += ot;

      (o.lines || []).forEach(l => {
        const q = l.qty || 0, v = q * (l.price || 0);
        totalQty += q; e.qty += q; d.qty += q;
        const p = prodMap[l.productId] || (prodMap[l.productId] = { qty: 0, sum: 0 });
        p.qty += q; p.sum += v;
        const prod = DB.PRODUCT_BY_ID[l.productId];
        const cid = prod ? prod.cat : null;
        if (cid) { const c = catMap[cid] || (catMap[cid] = { qty: 0, sum: 0 }); c.qty += q; c.sum += v; }
      });
    });

    const cnt = fOrders.length;
    const fmtQty = (n) => DB.fmtSum(Math.round(n));

    const topProducts = Object.entries(prodMap)
      .map(([id, v]) => ({ key: id, name: (DB.PRODUCT_BY_ID[id] || {}).name || '—', sum: v.sum, qty: v.qty, meta: fmtQty(v.qty) + ' dona' }))
      .sort((a, b) => b.sum - a.sum).slice(0, 8);

    const catRows = Object.entries(catMap)
      .map(([id, v]) => {
        const c = (DB.CATEGORIES || []).find(x => x.id === id);
        const bName = c ? DB.brandName(c.brand) : '';
        return { key: id, name: DB.categoryName(id) || '—', sum: v.sum, qty: v.qty, meta: (bName && bName !== '—' ? bName + ' · ' : '') + fmtQty(v.qty) + ' dona' };
      })
      .sort((a, b) => b.sum - a.sum).slice(0, 8);

    const empRows = Object.entries(empMap)
      .map(([name, v]) => ({ key: name, name, sum: v.sum, orders: v.orders, qty: v.qty, meta: v.orders + ' zakaz · ' + fmtQty(v.qty) + ' dona' }))
      .sort((a, b) => b.sum - a.sum).slice(0, 8);

    const distRows = Object.entries(distMap)
      .map(([id, v]) => ({ key: id, name: DB.distributorName(id), sum: v.sum, orders: v.orders, meta: v.orders + ' zakaz' }))
      .sort((a, b) => b.sum - a.sum).slice(0, 8);

    return {
      totalQty,
      avgQty: cnt ? Math.round(totalQty / cnt) : 0,
      activeProducts: Object.keys(prodMap).length,
      activeCategories: Object.keys(catMap).length,
      activeEmployees: Object.keys(empMap).filter(k => k !== '—').length,
      activeDistributors: Object.keys(distMap).filter(k => k !== '—').length,
      deliveredCount,
      fulfillPct: cnt ? Math.round(deliveredCount / cnt * 100) : 0,
      topProducts, catRows, empRows, distRows,
      maxProduct: Math.max(1, ...topProducts.map(p => p.sum)),
      maxCat: Math.max(1, ...catRows.map(c => c.sum)),
      maxEmp: Math.max(1, ...empRows.map(e => e.sum)),
      maxDist: Math.max(1, ...distRows.map(d => d.sum)),
    };
  }, [fOrders]);

  const overduePct = count ? Math.round(overdueOrders.length / count * 100) : 0;

  // Yuqori darajadagi puls KPI'lari (eng muhim operatsion raqamlar)
  const pulseKpis = [
    { label: 'Jami zakazlar', value: count, icon: 'box', suffix: 'ta', accent: 'var(--brand)' },
    { label: 'Yetkazilgan', value: pulse.deliveredCount, icon: 'truck', suffix: 'ta', sub: pulse.fulfillPct + '% bajarildi', accent: '#3DBE9C' },
    { label: 'Sotilgan dona', value: pulse.totalQty, icon: 'layers', suffix: 'dona', accent: '#3F7FB8' },
    { label: "O'rtacha dona/zakaz", value: pulse.avgQty, icon: 'box', suffix: 'dona', accent: '#7A5CF0' },
  ];

  // Holat bo'yicha summa
  const byStatus = DB.COLUMNS.map(c => {
    const sum = fOrders.filter(o => o.status === c.key).reduce((s, o) => s + DB.orderTotal(o), 0);
    return { ...c, sum };
  });
  const maxStatusSum = Math.max(1, ...byStatus.map(s => s.sum));

  // Viloyat bo'yicha top (summa)
  const regionMap = {};
  fOrders.forEach(o => { regionMap[o.region] = (regionMap[o.region] || 0) + DB.orderTotal(o); });
  const topRegions = Object.entries(regionMap).map(([id, sum]) => ({ name: DB.regionName(id), sum }))
    .sort((a, b) => b.sum - a.sum).slice(0, 6);
  const maxRegion = Math.max(1, ...topRegions.map(r => r.sum));

  // Brend ulushi (donut uchun) — birinchi brend foizi
  const primary = DB.BRANDS[0];
  const primaryPct = all.total ? Math.round((all.by[primary ? primary.id : ''] || 0) / all.total * 100) : 0;

  // So'nggi 7 kunlik real dinamika (createdAt bo'yicha kunlik summa)
  const trend = useMemo(() => {
    const wd = ['Ya', 'Du', 'Se', 'Ch', 'Pa', 'Ju', 'Sh'];
    const today = new Date(); today.setHours(0, 0, 0, 0);
    const out = [];
    for (let i = 6; i >= 0; i--) {
      const d = new Date(today); d.setDate(d.getDate() - i);
      const start = d.getTime(), end = start + 86400000;
      const v = baseOrders.reduce((s, o) => {
        const t = o.createdAt ? new Date(o.createdAt).getTime() : 0;
        return (t >= start && t < end) ? s + DB.orderTotal(o) : s;
      }, 0);
      out.push({ d: wd[d.getDay()], v });
    }
    return out;
  }, [baseOrders]);
  const maxTrend = Math.max(1, ...trend.map(t => t.v));

  // Vazifa statistikasi — ustunlardan mustaqil (category + completedAt asosida).
  // Oy tanlansa — o'sha oyda BERILGAN (createdAt) vazifalar bo'yicha; aks holda hammasi.
  const monthTasks = useMemo(() => {
    if (month === 'all') return tasks;
    const mi = DASH_MONTH_KEYS.indexOf(month);
    return (tasks || []).filter(t => {
      if (!t.createdAt) return false;
      const d = new Date(t.createdAt);
      return d.getFullYear() === MONTH_YEAR && d.getMonth() === mi;
    });
  }, [tasks, month]);
  const tStats = DB.taskStats(monthTasks);
  const taskCards = [
    { label: 'Jami berilgan vazifalar', value: tStats.total, icon: 'tasks', color: 'var(--brand)', tint: 'var(--brand-tint)', ink: 'var(--brand-700)' },
    { label: 'Jarayonda', value: tStats.doing, icon: 'clock', color: '#E3A23B', tint: '#F6E7CF', ink: '#A6651E' },
    { label: 'Bajarilgan', value: tStats.done, icon: 'check', color: '#3DBE9C', tint: '#D9F0E8', ink: '#1D8A6E' },
    { label: 'Muddatida bajarilgan', value: tStats.onTime, icon: 'shield', color: '#5A9FD4', tint: '#DCE9F4', ink: '#2F6F9E' },
    { label: "Muddati o'tib ketgan", value: tStats.overdue, icon: 'info', color: '#E8735F', tint: '#F6DCD6', ink: '#C2453A' },
  ];

  return (
    <div className="dash-wrap" style={{ padding: '8px 28px 32px', overflowY: 'auto', height: '100%' }}>
      {/* ====== Boshqaruv paneli — menejer + davr filtri (butun dashboardni filtrlaydi) ====== */}
      <div className="dx-toolbar dash-anim" style={{ marginBottom: 16 }}>
        {managerOptions.length > 0 && (
          <select className="dx-select" value={mgrFilter} onChange={e => setMgrFilter(e.target.value)} style={{ minWidth: 210 }}>
            <option value="all">Barcha regional menejerlar</option>
            {managerOptions.map(m => (<option key={m.id} value={m.id}>{m.name}</option>))}
          </select>
        )}
        {/* Oy tanlash — har bir ko'rsatkichni tanlangan oy bo'yicha ko'rsatadi */}
        <select className="dx-select" value={month} onChange={e => setMonth(e.target.value)} style={{ minWidth: 150 }} title="Oy bo'yicha ko'rish (sell-in zakazlar + sell-out)">
          {monthOptions.map(m => (<option key={m.key} value={m.key}>{m.label}</option>))}
        </select>
        {(scopeLabel || mgrLabel) && (
          <span className="dx-chip"><Icon name="pin" size={12} /> {scopeLabel || mgrLabel}</span>
        )}
        <div className="dx-toolbar__sp" />
        {/* Davr segmenti faqat "Barcha oylar" tanlanganda (oy tanlansa — o'sha oy oynasi) */}
        {month === 'all' && (
          <div className="dx-seg">
            {RANGES.map(([k, lbl]) => (
              <button key={k} className={range === k ? 'on' : ''} onClick={() => setRange(k)}>{lbl}</button>
            ))}
          </div>
        )}
      </div>

      {/* ====== PULS — sahifaning fokus nuqtasi: sell-in summa + 7 kunlik dinamika ====== */}
      <div className="px-pulse">
        <div className="dx-card px-hero dash-anim">
          <div className="px-hero__top">
            <div style={{ minWidth: 0 }}>
              <div className="px-eyebrow">Sell-in · {(monthOptions.find(m => m.key === month) || {}).label || 'Barcha oylar'}</div>
              <div className="px-hero__v tnum">{DB.fmtSum(Math.round(all.total || 0))}<small>so'm</small></div>
              <div className="px-hero__s">{count} ta zakaz · {pulse.fulfillPct}% yetkazildi</div>
            </div>
            {overdueOrders.length > 0 ? (
              <button className="px-flag px-flag--bad" onClick={() => setOverdueOpen(true)}>
                <Icon name="alert" size={14} /> {overdueOrders.length} ta kechikkan · {DB.fmtSum(Math.round(overdueSum))} so'm
              </button>
            ) : (
              <span className="px-flag"><Icon name="check" size={14} /> Kechikkan zakaz yo'q</span>
            )}
          </div>
          <div className="px-hero__chart">
            <div className="px-eyebrow" style={{ marginBottom: 6 }}>So'nggi 7 kun</div>
            <TrendChart trend={trend} max={maxTrend} />
            {trend.every(t => !t.v) && <div className="px-hero__empty">So'nggi 7 kunda zakaz kiritilmagan</div>}
          </div>
        </div>
        <div className="px-kpis">
          {pulseKpis.map((c, i) => (
            <div key={i} className="dx-kpi dx-kpi--hover" style={{ '--_a': c.accent }} onClick={() => go('board')} title="Zakazlar doskasiga o'tish">
              <div className="dx-kpi__l">{c.label}</div>
              <div className="dx-kpi__v tnum"><CountUp value={c.value} /> <small>{c.suffix}</small></div>
              {c.sub && <div className="dx-kpi__s">{c.sub}</div>}
            </div>
          ))}
        </div>
      </div>

      {/* ====== SELL-IN (zakaz) ↔ SELL-OUT (sheet) ====== */}
      <SellInOutSection orders={baseOrders} regionNames={effRegionNames} range={range} monthKey={soMonthKey} onNavigate={onNavigate} />

      {/* ====== VILOYATLAR BO'YICHA OYLIK PROGNOZ (Brend·Sell-in/out + Kunlik o'rniga ko'chirildi) ====== */}
      <RegionForecastCards orders={baseOrders} regionNames={effRegionNames} monthKey={soMonthKey} onNavigate={onNavigate} />

      {/* Regional menejerlar reytingi — motivatsiya (barchaga ko'rinadi); oy bo'yicha */}
      <ManagerLeaderboard ym={lbYm} />

      {/* ====== BREND ULUSHI — brendlar diagrammasi ====== */}
      <BrandShareCard by={all.by} total={all.total} />

      {/* ====== Mahsulot va kategoriya kesimi ====== */}
      <div className="dx-g2" style={{ marginBottom: 16 }}>
        <div className="dx-card dx-card--pad dash-anim" style={{ animationDelay: '.34s' }}>
          <SectionHead icon="layers" title="Top mahsulotlar" sub={"Eng ko'p sotilgan — summa bo'yicha (" + pulse.activeProducts + " tur faol)"} />
          <DonutChart rows={pulse.topProducts} empty="Bu davr uchun mahsulot yo'q" onPick={() => go('board')} />
        </div>
        <div className="dx-card dx-card--pad dash-anim" style={{ animationDelay: '.38s' }}>
          <SectionHead icon="grid" title="Kategoriya kesimi" sub={"Kategoriyalar bo'yicha savdo — summa (" + pulse.activeCategories + " ta faol)"} tint="#E7E1FB" ink="#5B45D6" />
          <DonutChart rows={pulse.catRows} empty="Bu davr uchun kategoriya yo'q" onPick={() => go('board')} />
        </div>
      </div>

      {/* ====== Distributorlar faolligi + Top viloyatlar (yonma-yon) ====== */}
      <div className="dx-g2" style={{ marginBottom: 16 }}>
        <div className="dx-card dx-card--pad dash-anim" style={{ animationDelay: '.46s' }}>
          <SectionHead icon="users" title="Distributorlar faolligi" sub={"Eng faol distributorlar — summa bo'yicha (" + pulse.activeDistributors + " ta faol — AKB)"} tint="#D9F0E8" ink="#1D8A6E" />
          <DonutChart rows={pulse.distRows} empty="Bu davr uchun distributor yo'q" onPick={() => go('board')} />
        </div>

        <div className="dx-card dx-card--pad dash-anim" style={{ animationDelay: '.54s' }}>
          <SectionHead icon="pin" title="Top viloyatlar" sub="Eng ko'p savdo qilingan viloyatlar — summa bo'yicha" tint="rgba(142,116,255,.12)" ink="#5B45D6" />
          <DonutChart rows={topRegions} empty="Bu davr uchun zakaz yo'q" onPick={() => go('board')} />
        </div>
      </div>

      {/* ====== Vazifalar statistikasi — kanban o'zgarsa ham barqaror ====== */}
      <div className="dx-card dx-card--pad dash-anim" style={{ animationDelay: '.66s' }}>
        <SectionHead icon="tasks" title="Vazifalar statistikasi" sub="Doskadagi ustunlar o'zgarsa ham ko'rsatkichlar barqaror qoladi" />
        <div className="dx-g5">
          {taskCards.map((c, i) => (
            <div key={i} onClick={() => perms.taskView && go('tasks')} title={perms.taskView ? "Vazifalar doskasiga o'tish" : undefined}
              className={'dx-kpi' + (perms.taskView ? ' dx-kpi--hover' : '')} style={{ '--_a': c.color }}>
              <div className="dx-kpi__l">
                <span className="dx-kpi__ic" style={{ background: c.tint, color: c.ink }}><Icon name={c.icon} size={15} /></span>
                {c.label}
              </div>
              <div className="dx-kpi__v tnum" style={{ color: c.color }}><CountUp value={c.value} /></div>
            </div>
          ))}
        </div>
      </div>

      {overdueOpen && (
        <OverdueModal orders={overdueOrders} sum={overdueSum} onClose={() => setOverdueOpen(false)}
          onGoBoard={() => { setOverdueOpen(false); go('board'); }} />
      )}
    </div>
  );
}

/* ---------- Kechikkan zakazlar ro'yxati (modal) ---------- */
function OverdueModal({ orders, sum, onClose, onGoBoard }) {
  const now = Date.now();
  return (
    <Modal onClose={onClose} width={640}>
      <ModalHeader title="Muddati o'tgan zakazlar"
        subtitle={orders.length + " ta · jami " + DB.fmtSum(sum) + " so'm kechikkan"} onClose={onClose} />
      <div style={{ padding: '8px 0', overflowY: 'auto' }}>
        {orders.map(o => {
          const days = Math.floor((now - new Date(o.deadline).getTime()) / 86400000);
          const col = DB.COLUMNS[DB.COL_INDEX[o.status]] || {};
          return (
            <div key={o.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 22px', borderBottom: '1px solid var(--border)' }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontWeight: 800, fontSize: 13 }}>{o.code}</span>
                  <span className="chip" style={{ background: (col.color || 'var(--ink-4)') + '1a', color: col.color || 'var(--ink-3)', padding: '1px 8px', fontSize: 10.5 }}>
                    {(col.title || '').replace(' Zakazlar', '')}
                  </span>
                </div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 3, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                  {DB.distributorName(o.distributorId)} · {DB.regionName(o.region)}
                </div>
              </div>
              <div style={{ textAlign: 'right', flex: 'none' }}>
                <div className="tnum" style={{ fontWeight: 700, fontSize: 13 }}>{DB.fmtSum(DB.orderTotal(o))} so'm</div>
                <div style={{ fontSize: 11.5, color: '#C2453A', fontWeight: 700, marginTop: 3 }}>
                  {DB.fmtDeadline(o.deadline)} · {days} kun kechikdi
                </div>
              </div>
            </div>
          );
        })}
        {orders.length === 0 && <Empty icon="check" text="Kechikkan zakaz yo'q" />}
      </div>
      <div style={{ padding: '14px 22px', borderTop: '1px solid var(--border)', display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
        <button className="btn btn--ghost" onClick={onClose}>Yopish</button>
        <button className="btn btn--primary" onClick={onGoBoard}><Icon name="board" size={15} /> Zakazlar doskasiga o'tish</button>
      </div>
    </Modal>
  );
}

/* ---------- Trend area chart (SVG, interaktiv) ---------- */
function TrendChart({ trend, max }) {
  const W = 560, H = 170, pad = 8;
  const stepX = (W - pad * 2) / (trend.length - 1);
  const y = v => H - pad - (v / (max || 1)) * (H - pad * 2 - 16);
  const pts = trend.map((t, i) => [pad + i * stepX, y(t.v)]);
  const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
  const area = line + ` L${pad + (trend.length - 1) * stepX} ${H - pad} L${pad} ${H - pad} Z`;

  const lineRef = useRef(null);
  const [hi, setHi] = useState(-1);

  useEffect(() => {
    const el = lineRef.current;
    if (!el) return;
    let len = 0;
    try { len = el.getTotalLength(); } catch (e) { return; }
    el.style.transition = 'none';
    el.style.strokeDasharray = len + ' ' + len;
    el.style.strokeDashoffset = String(len);
    void el.getBoundingClientRect();
    el.style.transition = 'stroke-dashoffset 1.1s var(--ease)';
    el.style.strokeDashoffset = '0';
  }, [line]);

  const onMove = (e) => {
    const r = e.currentTarget.getBoundingClientRect();
    const rx = (e.clientX - r.left) / r.width * W;
    let idx = Math.round((rx - pad) / stepX);
    idx = Math.max(0, Math.min(trend.length - 1, idx));
    setHi(idx);
  };

  const hp = hi >= 0 ? pts[hi] : null;

  return (
    <div style={{ position: 'relative' }} onMouseMove={onMove} onMouseLeave={() => setHi(-1)}>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: 'block' }} preserveAspectRatio="none">
        <defs>
          <linearGradient id="tg" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#EC7A55" stopOpacity=".22" />
            <stop offset="100%" stopColor="#EC7A55" stopOpacity="0" />
          </linearGradient>
        </defs>
        {[0.25, 0.5, 0.75].map((g, i) => <line key={i} x1={pad} x2={W - pad} y1={pad + g * (H - pad * 2)} y2={pad + g * (H - pad * 2)} stroke="var(--border)" strokeDasharray="3 4" />)}
        <path d={area} fill="url(#tg)" />
        <path ref={lineRef} d={line} fill="none" stroke="#EC7A55" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
        {hp && <line x1={hp[0]} x2={hp[0]} y1={pad} y2={H - pad} stroke="var(--brand)" strokeWidth="1.5" strokeDasharray="3 4" opacity=".55" />}
        {pts.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r={i === hi ? 6 : 4} fill={i === hi ? '#EC7A55' : '#fff'} stroke="#EC7A55" strokeWidth="2.5" style={{ transition: 'r .12s var(--ease), fill .12s var(--ease)' }} />)}
        {trend.map((t, i) => <text key={i} x={pad + i * stepX} y={H - 1} fontSize="11" fill={i === hi ? 'var(--brand)' : 'var(--ink-4)'} textAnchor="middle" fontWeight={i === hi ? 800 : 600} fontFamily="Manrope">{t.d}</text>)}
      </svg>
      {hp && (
        <div className="chart-tip" style={{ left: (hp[0] / W * 100) + '%', top: (hp[1] / H * 100) + '%', opacity: 1 }}>
          {trend[hi].d} · {DB.fmtSum(trend[hi].v)} so'm
        </div>
      )}
    </div>
  );
}

/* ---------- Donut (sweep animatsiya) ---------- */
function Donut({ pct, color = 'var(--brand)', label = '' }) {
  const r = 52, c = 2 * Math.PI * r, seg = c * pct / 100;
  const arcRef = useRef(null);
  useEffect(() => {
    const el = arcRef.current;
    if (!el) return;
    el.style.transition = 'none';
    el.style.strokeDashoffset = String(c);
    void el.getBoundingClientRect();
    el.style.transition = 'stroke-dashoffset 1.1s var(--ease)';
    el.style.strokeDashoffset = String(c - seg);
  }, [seg, c]);
  return (
    <div style={{ display: 'grid', placeItems: 'center', padding: '6px 0' }}>
      <svg width="140" height="140" viewBox="0 0 140 140">
        <circle cx="70" cy="70" r={r} fill="none" stroke="var(--bg-2)" strokeWidth="20" />
        <circle ref={arcRef} cx="70" cy="70" r={r} fill="none" stroke={color} strokeWidth="20"
                strokeDasharray={c} strokeDashoffset={c} transform="rotate(-90 70 70)" strokeLinecap="round" />
        <text x="70" y="66" textAnchor="middle" fontSize="24" fontWeight="800" fill="var(--ink)" fontFamily="Manrope"><CountUp value={pct} />%</text>
        <text x="70" y="84" textAnchor="middle" fontSize="11" fontWeight="600" fill="var(--ink-4)" fontFamily="Manrope">{label}</text>
      </svg>
    </div>
  );
}

window.Dashboard = Dashboard;
