// pages-manage.jsx — Accounts + Prices

const { useState: useStateM, useMemo: useMemoM, useRef: useRefM, useEffect: useEffectM } = React;

/* ============================
   ACCOUNTS
============================ */

// Русская плюрализация слова «аккаунт» для подзаголовка.
function accountsWord(n) {
  const m10 = n % 10, m100 = n % 100;
  if (m10 === 1 && m100 !== 11) return "аккаунт";
  if (m10 >= 2 && m10 <= 4 && (m100 < 10 || m100 >= 20)) return "аккаунта";
  return "аккаунтов";
}

// Статус «реально работает» — по флагам с бэка (isActive / connected / synced)
// и активности. Порядок проверок = приоритет (сверху важнее). Возвращает
// {label (для пилюли), tone (для CSS-класса пилюли), title (hover)}.
function accountStatus(a) {
  if (a.isActive === false) return { tone: "off", label: "выкл.", title: "выключен" };
  if (!a.connected) return { tone: "fail", label: "не подкл.", title: "не подключён к Telegram" };
  if (!a.synced) return { tone: "warn", label: "не синхр.", title: "не синхронизирован — нажми «Подтянуть с Telegram»" };
  return { tone: "ok", label: "активен", title: "работает — подключён и синхронизирован" };
}

// Стили пилюли статуса — приглушённая бежевая гамма (emerald/amber/rose/grey).
const ACCOUNT_PILL_CLS = {
  ok:   "bg-emerald-500/10 text-emerald-400 border-emerald-500/20",
  warn: "bg-amber-500/10 text-amber-400 border-amber-500/20",
  fail: "bg-rose-500/10 text-rose-400 border-rose-500/20",
  off:  "bg-black/[0.04] text-zinc-500 border-black/[0.06]",
};

// 3px tone-бар слева у строки — по статусу аккаунта (тёплая гамма друга).
function accountTone(a) {
  if (a.isActive === false) return "#b4b2a9";     // выкл — серо-беж
  if (!a.connected) return "#b07373";              // не подключён — muted rose
  if (!a.synced) return "#b5c95c";                 // не синхр. — muted amber
  return "#5da27a";                                 // активен — muted emerald
}

// Относительное «было N назад» из ISO-строки lastInteractionAt (или «—»).
function accountLastSeen(iso) {
  if (!iso) return "—";
  const t = Date.parse(iso);
  if (!Number.isFinite(t)) return "—";
  const sec = Math.max(0, (Date.now() - t) / 1000);
  if (sec < 60) return "только что";
  const min = Math.floor(sec / 60);
  if (min < 60) return min + " мин";
  const hr = Math.floor(min / 60);
  if (hr < 24) return hr + " ч";
  const d = Math.floor(hr / 24);
  if (d < 30) return d + " дн";
  const mo = Math.floor(d / 30);
  if (mo < 12) return mo + " мес";
  return Math.floor(mo / 12) + " г";
}

// Крошечный спарклайн-тренд из [вчера, сегодня]: если данных мало — стрелка
// направления, иначе мини-SVG 60×20. Тон подкрашивается под статус.
function AccountTrend({ a, color }) {
  const y = Number(a.yesterday) || 0;
  const t = Number(a.today) || 0;
  if (y === 0 && t === 0) {
    return <span className="text-[11px] text-zinc-500">→</span>;
  }
  const max = Math.max(y, t, 1);
  const pts = [y, t];
  const w = 64, h = 26, pad = 3;
  const step = pts.length > 1 ? (w - pad * 2) / (pts.length - 1) : 0;
  const xy = pts.map((v, i) => [pad + i * step, h - pad - (v / max) * (h - pad * 2)]);
  const line = xy.map((p) => p[0].toFixed(1) + "," + p[1].toFixed(1)).join(" ");
  const area = pad + "," + (h - pad) + " " + line + " " + (w - pad) + "," + (h - pad);
  const end = xy[xy.length - 1];
  return (
    <svg width={w} height={h} viewBox={"0 0 " + w + " " + h} className="overflow-visible">
      <polygon points={area} fill={color} opacity="0.15" />
      <polyline points={line} fill="none" stroke={color} strokeWidth="2.4"
        strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={end[0]} cy={end[1]} r="2.7" fill={color} />
    </svg>
  );
}

// Кастомный дропдаун владельца — вместо нативного <select> (тот и уёбищно
// выглядит, и капризный). Стильный бежевый попап с реальными кнопками-опциями
// (клик гарантированно срабатывает), position:fixed (не обрезается таблицей),
// закрывается по клику-мимо / Esc / скроллу. Смена — та же changeOwner (мгновенно).
function OwnerPicker({ a, owners, onChange }) {
  const [open, setOpen] = useStateM(false);
  const [pos, setPos] = useStateM(null);
  const btnRef = React.useRef(null);
  const popRef = React.useRef(null);
  const toggle = (e) => {
    e.stopPropagation();
    if (open) { setOpen(false); return; }
    const r = btnRef.current.getBoundingClientRect();
    // Оценка высоты попапа (≈32px/опция, кап под max-h-64) → если снизу мало
    // места, разворачиваем вверх, чтобы не уезжал за край экрана.
    const count = (owners ? owners.length : 0) + 1;
    const estH = Math.min(count * 32 + 8, 264);
    const openUp = (window.innerHeight - r.bottom) < estH + 8 && r.top > estH + 8;
    setPos({
      left: r.left,
      top: openUp ? Math.max(8, r.top - estH - 4) : r.bottom + 4,
      minWidth: Math.max(r.width, 170),
    });
    setOpen(true);
  };
  useEffectM(() => {
    if (!open) return;
    const close = () => setOpen(false);
    const onKey = (e) => { if (e.key === "Escape") setOpen(false); };
    // scroll закрывает попап, НО не когда скроллят ВНУТРИ самого попапа
    // (иначе длинный список владельцев нельзя долистать — из адверс-вычитки).
    const onScroll = (e) => { if (popRef.current && popRef.current.contains(e.target)) return; setOpen(false); };
    window.addEventListener("mousedown", close);
    window.addEventListener("keydown", onKey);
    window.addEventListener("scroll", onScroll, true);
    return () => {
      window.removeEventListener("mousedown", close);
      window.removeEventListener("keydown", onKey);
      window.removeEventListener("scroll", onScroll, true);
    };
  }, [open]);
  const opts = [{ id: "", name: "Мои (админ)" }].concat(owners || []);
  const pick = (e, id) => { e.stopPropagation(); setOpen(false); onChange(a.id, id); };
  return (
    <>
      <button
        ref={btnRef}
        onClick={toggle}
        onMouseDown={(e) => e.stopPropagation()}
        className="inline-flex items-center gap-1.5 max-w-full px-2 py-1 rounded-full border border-transparent hover:border-black/[0.1] hover:bg-black/[0.04] cursor-pointer transition-colors"
      >
        <span className="w-2 h-2 rounded-full shrink-0" style={{ background: a.ownerId ? "#9ccc52" : "#b4b2a9" }} />
        <span className="text-[12.5px] text-zinc-50 truncate">{a.ownerName || "Мои"}</span>
        <Icon name="chevDown" className="w-3 h-3 text-zinc-500 shrink-0" />
      </button>
      {open && pos && (
        <div
          ref={popRef}
          onClick={(e) => e.stopPropagation()}
          onMouseDown={(e) => e.stopPropagation()}
          style={{ position: "fixed", left: pos.left, top: pos.top, minWidth: pos.minWidth, zIndex: 70 }}
          className="glass rounded-xl border border-black/[0.08] shadow-[0_10px_30px_rgba(60,58,52,0.18)] py-1 max-h-64 overflow-y-auto"
        >
          {opts.map((o) => {
            const active = (a.ownerId || "") === (o.id || "");
            return (
              <button
                key={o.id || "__admin__"}
                onClick={(e) => pick(e, o.id)}
                className={"w-full flex items-center gap-2 px-3 py-1.5 text-left text-[12.5px] transition-colors hover:bg-black/[0.05] " + (active ? "bg-[rgba(231,220,196,0.5)]" : "")}
              >
                <span className="w-2 h-2 rounded-full shrink-0" style={{ background: o.id ? "#9ccc52" : "#b4b2a9" }} />
                <span className="flex-1 truncate text-zinc-50">{o.name}</span>
                {active && <Icon name="check" className="w-3.5 h-3.5 text-emerald-500 shrink-0" />}
              </button>
            );
          })}
        </div>
      )}
    </>
  );
}

// Плотная строка аккаунта в стиле друга (.acc-row): чекбокс, tone-бар слева,
// аватар+имя+@username, дропдаун владельца, пилюля статуса, сегодня/7д
// (справа), тренд (по центру), «онлайн» (справа). Клик по строке → drawer.
function AccountRowFlat({ a, owners, checked, onToggleCheck, onOpen, onOwnerChange }) {
  const st = accountStatus(a);
  const tone = accountTone(a);
  return (
    <div
      onClick={onOpen}
      title={st.title}
      className={
        "relative grid items-center gap-3 pl-[18px] pr-3 py-[11px] cursor-pointer tabular-nums transition-colors border-b border-black/[0.06] " +
        (checked ? "bg-[rgba(231,220,196,0.55)]" : "hover:bg-black/[0.03]")
      }
      style={{ gridTemplateColumns: "24px minmax(0,1fr) 124px 118px 64px 56px 84px 76px" }}
    >
      <span className="absolute left-0 top-1.5 bottom-1.5 w-[3px] rounded-r" style={{ background: tone }} />

      <input
        type="checkbox"
        checked={checked}
        onChange={onToggleCheck}
        onClick={(e) => e.stopPropagation()}
        className="w-3.5 h-3.5 accent-[#9ccc52] cursor-pointer"
      />

      {/* Модель */}
      <div className="flex items-center gap-[11px] min-w-0">
        <Avatar name={a.name} color={a.color} avatarUrl={a.avatarUrl} size={34} />
        <div className="min-w-0">
          <div className="text-[13.5px] font-medium leading-tight truncate text-zinc-50">{a.name}</div>
          <div className="text-[11.5px] font-mono text-zinc-500 truncate">{a.username || "—"}</div>
        </div>
      </div>

      {/* Владелец — кастомный дропдаун (не нативный select) */}
      <div className="min-w-0" onClick={(e) => e.stopPropagation()}>
        <OwnerPicker a={a} owners={owners} onChange={onOwnerChange} />
      </div>

      {/* Статус */}
      <div className="min-w-0">
        <span className={"inline-flex items-center px-2 py-0.5 rounded-full text-[11px] font-medium border " + (ACCOUNT_PILL_CLS[st.tone] || ACCOUNT_PILL_CLS.off)}>
          {st.label}
        </span>
      </div>

      {/* Сегодня */}
      <div className="text-right text-[13.5px] text-zinc-50">{a.today || 0}</div>
      {/* 7 дней */}
      <div className="text-right text-[13.5px] font-semibold text-zinc-50">{a.week || 0}</div>
      {/* Тренд */}
      <div className="flex justify-center"><AccountTrend a={a} color={accountTone(a)} /></div>
      {/* Онлайн */}
      <div className="text-right text-[12.5px] text-zinc-500">{accountLastSeen(a.lastInteractionAt)}</div>
    </div>
  );
}

// Заголовок колонок плотной таблицы (.acc-row.is-head): UPPERCASE 10px.
function AccountTableHead({ allChecked, onToggleAll }) {
  return (
    <div
      className="grid items-center gap-3 pl-[18px] pr-3 py-[11px] text-[10px] uppercase tracking-[0.1em] text-zinc-500 font-semibold border-b border-black/[0.06] bg-black/[0.02]"
      style={{ gridTemplateColumns: "24px minmax(0,1fr) 124px 118px 64px 56px 84px 76px" }}
    >
      <input type="checkbox" checked={allChecked} onChange={onToggleAll} className="w-3.5 h-3.5 accent-[#9ccc52] cursor-pointer" />
      <span>Модель</span>
      <span>Владелец</span>
      <span>Статус</span>
      <span className="text-right">Сегодня</span>
      <span className="text-right">7д</span>
      <span className="text-center">Тренд</span>
      <span className="text-right">Онлайн</span>
    </div>
  );
}

// Owner-filter TAB (вкладка): «Все {N}» / «{имя} {count}» с цветной точкой.
function OwnerTab({ active, dot, label, count, onClick }) {
  return (
    <button onClick={onClick}
      className={"inline-flex items-center gap-1.5 px-3.5 py-1.5 rounded-lg text-[12.5px] font-medium whitespace-nowrap transition-colors " + (active ? "bg-[rgba(231,220,196,0.55)] text-zinc-50 shadow-sm" : "text-zinc-500 hover:text-zinc-50")}>
      {dot && <span className="w-2 h-2 rounded-full" style={{ background: dot }} />}
      {label}
      <span className="opacity-55 font-medium">{count}</span>
    </button>
  );
}

function AccountsPage() {
  // Live data из /api/accounts. Загружается в useEffect один раз.
  // ВАЖНО: НЕТ polling. На этой странице справа editable-поля (имя/username/
  // возраст). Polling раз в 30 сек перезатирал бы введённые пользователем
  // значения обратно к серверным значениям. Для обновления статистики
  // (today/yesterday/week) — кнопка «Обновить» в заголовке.
  const [accounts, setAccounts] = useStateM([]);
  const [loading, setLoading] = useStateM(true);
  const [selected, setSelected] = useStateM(null);
  const [search, setSearch] = useStateM("");
  // showAll=false → только реально работающие (активность < 2 дней). Остальные
  // скрыты, чтобы видеть, сколько аккаунтов сейчас реально подключено к боту.
  const [showAll, setShowAll] = useStateM(false);
  const [syncing, setSyncing] = useStateM(false);
  const [syncMsg, setSyncMsg] = useStateM("");
  const [tab, setTab] = useStateM("accounts");  // "accounts" | "owners"
  const [owners, setOwners] = useStateM([]);
  const [ownerFilter, setOwnerFilter] = useStateM("all");  // "all" | "mine" | <ownerId>
  const [showUnsynced, setShowUnsynced] = useStateM(false);
  // Presentational-only: свёрнутые группы владельцев в списке (UI-состояние
  // сворачивания групп в стиле друга). На данные/поведение не влияет.
  const [collapsedGroups, setCollapsedGroups] = useStateM({});
  // Плотная таблица: bulk-выбор (Set id), сортировка, drawer с деталью.
  const [checkedIds, setCheckedIds] = useStateM(() => new Set());
  const [sortKey, setSortKey] = useStateM("today");   // today | week | name | online
  const [sortDir, setSortDir] = useStateM("desc");     // desc | asc
  const [drawerOpen, setDrawerOpen] = useStateM(false);

  const reload = React.useCallback(async (all) => {
    setLoading(true);
    const data = await fetchAccounts(all);
    setAccounts(data);
    setLoading(false);
    setSelected((cur) => cur || (data[0] ? data[0].id : null));
  }, []);

  useEffectM(() => {
    let stopped = false;
    (async () => {
      const data = await fetchAccounts(showAll);
      if (stopped) return;
      setAccounts(data);
      setLoading(false);
      setSelected((cur) => cur || (data[0] ? data[0].id : null));
    })();
    return () => { stopped = true; };
  }, [showAll]);

  useEffectM(() => { fetchOwners().then(setOwners); }, []);

  // «Подтянуть с Telegram»: обновляет имя/username/avatar/активность по всем
  // подключённым бизнес-аккаунтам, затем перезагружает список.
  const onSync = React.useCallback(async () => {
    setSyncing(true);
    setSyncMsg("");
    try {
      const res = await syncAccounts();
      const items = (res && res.items) || [];
      const ok = items.filter((i) => i && i.ok).length;
      const fail = items.length - ok;
      setSyncMsg(`Подтянуто: ${ok}${fail ? `, с ошибкой: ${fail}` : ""}`);
      await reload(showAll);
    } catch (e) {
      setSyncMsg("Ошибка синхронизации: " + (e && e.message ? e.message : e));
    } finally {
      setSyncing(false);
    }
  }, [reload, showAll]);

  const current = accounts.find((a) => a.id === selected);

  const matched = useMemoM(() => {
    let arr = accounts;
    if (ownerFilter === "mine") arr = arr.filter((a) => !a.ownerId);
    else if (ownerFilter !== "all") arr = arr.filter((a) => a.ownerId === ownerFilter);
    if (search) {
      const q = search.toLowerCase();
      arr = arr.filter((a) => a.name.toLowerCase().includes(q) || (a.username || "").toLowerCase().includes(q));
    }
    return arr;
  }, [search, accounts, ownerFilter]);

  const syncedRows = matched.filter((a) => a.synced);
  const unsyncedRows = matched.filter((a) => !a.synced);

  // Presentational-only: группировка видимых (synced) строк по владельцу для
  // плотной таблицы в стиле друга. Порядок групп: «Мои» (админ) первым, затем
  // владельцы по алфавиту. НЕ меняет данные — только раскладку.
  const syncedGroups = useMemoM(() => {
    const map = new Map();
    for (const a of syncedRows) {
      const key = a.ownerId || "__mine__";
      const label = a.ownerId ? (a.ownerName || "Владелец") : "Мои";
      if (!map.has(key)) map.set(key, { key, label, rows: [] });
      map.get(key).rows.push(a);
    }
    const groups = Array.from(map.values());
    groups.sort((g1, g2) => {
      if (g1.key === "__mine__") return -1;
      if (g2.key === "__mine__") return 1;
      return g1.label.localeCompare(g2.label);
    });
    return groups;
  }, [syncedRows]);

  const toggleGroup = (key) => setCollapsedGroups((m) => ({ ...m, [key]: !m[key] }));

  // Смена владельца аккаунта — ТА ЖЕ операция, что в редакторе профиля и во
  // вкладке «Владельцы»: saveAccountProfile(id, {ownerId}) → перезагрузка.
  const changeOwner = React.useCallback(async (accId, ownerId) => {
    // Оптимистично: сразу меняем владельца в UI (контролируемый select не
    // откатывается и не ждём медленный reload account-stats). Сохраняем в
    // фоне; при ошибке — откат перезагрузкой.
    const ownerName = ownerId ? ((owners.find((o) => o.id === ownerId) || {}).name || "") : "";
    setAccounts((prev) => prev.map((a) => (a.id === accId ? { ...a, ownerId, ownerName } : a)));
    try { await saveAccountProfile(accId, { ownerId }); }
    catch (e) { console.error("changeOwner failed", e); await reload(showAll); }
  }, [owners, reload, showAll]);

  // Bulk: сменить владельца у всех выделенных (цикл той же операции).
  const bulkChangeOwner = React.useCallback(async (ownerId) => {
    const ids = Array.from(checkedIds);
    const ownerName = ownerId ? ((owners.find((o) => o.id === ownerId) || {}).name || "") : "";
    // Оптимистично меняем всех выделенных сразу, сохраняем в фоне.
    setAccounts((prev) => prev.map((a) => (ids.includes(a.id) ? { ...a, ownerId, ownerName } : a)));
    setCheckedIds(new Set());
    for (const id of ids) {
      try { await saveAccountProfile(id, { ownerId }); }
      catch (e) { console.error("bulkChangeOwner failed", id, e); }
    }
  }, [checkedIds, owners]);

  // Клиентская сортировка видимых строк (презентационная).
  const SORT_FNS = {
    today:  (a, b) => (a.today || 0) - (b.today || 0),
    week:   (a, b) => (a.week || 0) - (b.week || 0),
    name:   (a, b) => String(a.name || "").localeCompare(String(b.name || ""), "ru"),
    online: (a, b) => Date.parse(a.lastInteractionAt || 0) - Date.parse(b.lastInteractionAt || 0),
  };
  const visibleRows = useMemoM(() => {
    const cmp = SORT_FNS[sortKey] || SORT_FNS.today;
    return [...matched].sort((a, b) => (sortDir === "desc" ? cmp(b, a) : cmp(a, b)));
  }, [matched, sortKey, sortDir]);

  const toggleCheck = (id) => setCheckedIds((prev) => {
    const next = new Set(prev);
    if (next.has(id)) next.delete(id); else next.add(id);
    return next;
  });
  const allInViewChecked = visibleRows.length > 0 && visibleRows.every((a) => checkedIds.has(a.id));
  const toggleAll = () => setCheckedIds((prev) => {
    const next = new Set(prev);
    const ids = visibleRows.map((a) => a.id);
    const all = ids.every((id) => next.has(id));
    ids.forEach((id) => (all ? next.delete(id) : next.add(id)));
    return next;
  });
  const clearChecked = () => setCheckedIds(new Set());
  const openAccount = (id) => { setSelected(id); setDrawerOpen(true); };
  const closeDrawer = () => setDrawerOpen(false);

  // Закрытие drawer по Esc.
  useEffectM(() => {
    if (!drawerOpen) return;
    const onKey = (e) => { if (e.key === "Escape") setDrawerOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [drawerOpen]);

  const ownerCount = (oid) => accounts.filter((a) => a.ownerId === oid).length;
  const ownerColor = (oid) => (oid ? "#9ccc52" : "#b4b2a9");

  return (
    <div className="space-y-6">
      <SectionTitle title="Аккаунты" subtitle="Профили и настройки селлеров">
        {tab === "accounts" ? (
          <>
            {syncMsg ? <span className="text-[11px] text-zinc-400 self-center mr-1">{syncMsg}</span> : null}
            <button
              onClick={() => reload(showAll)}
              disabled={loading || syncing}
              className="flex items-center gap-2 px-3.5 py-2 rounded-lg bg-zinc-800/60 border border-zinc-700/60 hover:bg-zinc-800 text-zinc-300 text-sm disabled:opacity-50"
            >
              <Icon name="refresh" className="w-3.5 h-3.5" /> Обновить
            </button>
            <button
              onClick={onSync}
              disabled={syncing}
              className="flex items-center gap-2 px-3.5 py-2 rounded-lg bg-indigo-500 hover:bg-indigo-600 text-white text-sm font-medium transition-colors disabled:opacity-50"
            >
              <Icon name={syncing ? "refresh" : "download"} className={"w-3.5 h-3.5" + (syncing ? " animate-spin" : "")} />
              {syncing ? "Тянем…" : "Подтянуть с Telegram"}
            </button>
          </>
        ) : null}
      </SectionTitle>

      <div className="flex gap-1 p-1 bg-zinc-800/40 border border-zinc-700/50 rounded-lg w-fit">
        <button onClick={() => setTab("accounts")}
          className={"px-4 py-1.5 rounded-md text-sm font-medium transition-colors " + (tab === "accounts" ? "bg-indigo-500 text-white" : "text-zinc-400 hover:text-zinc-200")}>
          Аккаунты
        </button>
        <button onClick={() => setTab("owners")}
          className={"px-4 py-1.5 rounded-md text-sm font-medium transition-colors " + (tab === "owners" ? "bg-indigo-500 text-white" : "text-zinc-400 hover:text-zinc-200")}>
          Владельцы
        </button>
      </div>

      {tab === "owners" ? <OwnersPanel /> : (
      <>
      {/* Owner-filter TABS справа от заголовка секции */}
      <div className="flex items-center justify-between gap-3 flex-wrap">
        <div className="text-sm text-zinc-500">
          {loading ? "…" : matched.length} {accountsWord(matched.length)} моделей
        </div>
        <div className="inline-flex items-center gap-1 p-1 rounded-xl bg-black/[0.03] border border-black/[0.06]">
          <OwnerTab active={ownerFilter === "all"} label="Все" count={accounts.length} onClick={() => setOwnerFilter("all")} />
          {/* «Мои» = не привязаны ни к какому владельцу (чеки идут админу).
              Новые/неопределённые аккаунты автоматически попадают сюда. */}
          <OwnerTab active={ownerFilter === "mine"} dot="#b4b2a9" label="Мои · не определены" count={accounts.filter((a) => !a.ownerId).length} onClick={() => setOwnerFilter("mine")} />
          {owners.map((o) => (
            <OwnerTab key={o.id} active={ownerFilter === o.id} dot={ownerColor(o.id)} label={o.name} count={ownerCount(o.id)} onClick={() => setOwnerFilter(o.id)} />
          ))}
        </div>
      </div>

      <Card className="p-0 overflow-hidden stagger-rows">
        {/* Панель фильтра: поиск + сортировка */}
        <div className="flex items-center gap-3 flex-wrap px-4 py-3.5 border-b border-black/[0.06]">
          <div className="relative flex-1 min-w-[240px]">
            <Icon name="search" className="w-4 h-4 text-zinc-500 absolute left-3 top-1/2 -translate-y-1/2" />
            <input
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder="Поиск аккаунта…"
              className="w-full bg-black/[0.03] border border-black/[0.06] rounded-lg pl-9 pr-3 py-2 text-sm text-zinc-50 placeholder:text-zinc-500 focus:outline-none focus:border-black/[0.14]"
            />
          </div>
          <div className="flex items-center gap-2">
            <select
              value={sortKey}
              onChange={(e) => setSortKey(e.target.value)}
              className="bg-black/[0.03] border border-black/[0.06] rounded-lg px-2.5 py-2 text-[13px] text-zinc-50 focus:outline-none focus:border-black/[0.14]"
            >
              <option value="today">По активности</option>
              <option value="week">По 7 дням</option>
              <option value="name">По имени</option>
              <option value="online">По онлайну</option>
            </select>
            <button
              onClick={() => setSortDir((d) => (d === "desc" ? "asc" : "desc"))}
              title={sortDir === "desc" ? "По убыванию" : "По возрастанию"}
              className="w-9 h-9 flex items-center justify-center rounded-lg bg-black/[0.03] border border-black/[0.06] text-zinc-50 hover:bg-black/[0.05]"
            >
              {sortDir === "desc" ? "↓" : "↑"}
            </button>
          </div>
        </div>

        {loading ? (
          <div className="divide-y divide-black/[0.06]">
            {Array.from({ length: 8 }).map((_, i) => (
              <div key={"sk" + i} className="grid items-center gap-2.5 pl-4 pr-3 py-2.5" style={{ gridTemplateColumns: "24px minmax(0,1fr) 124px 118px 64px 56px 84px 76px" }}>
                <div className="w-3.5 h-3.5 rounded bg-black/[0.05] animate-pulse" />
                <div className="flex items-center gap-2.5">
                  <div className="w-[30px] h-[30px] rounded-full bg-black/[0.05] animate-pulse" />
                  <div className="space-y-1.5 flex-1">
                    <div className="h-3 bg-black/[0.05] rounded animate-pulse w-2/3" />
                    <div className="h-2.5 bg-black/[0.04] rounded animate-pulse w-1/2" />
                  </div>
                </div>
                <div className="h-3 bg-black/[0.04] rounded animate-pulse" />
                <div className="h-4 bg-black/[0.04] rounded-full animate-pulse w-16" />
                <div className="h-3 bg-black/[0.04] rounded animate-pulse justify-self-end w-6" />
                <div className="h-3 bg-black/[0.04] rounded animate-pulse justify-self-end w-5" />
                <div />
                <div className="h-3 bg-black/[0.04] rounded animate-pulse justify-self-end w-8" />
              </div>
            ))}
          </div>
        ) : visibleRows.length === 0 ? (
          <div className="text-center text-sm text-zinc-500 py-14">
            {accounts.length === 0 ? "Аккаунтов нет" : "Нет аккаунтов под текущие фильтры"}
          </div>
        ) : (
          <>
            <AccountTableHead allChecked={allInViewChecked} onToggleAll={toggleAll} />
            {visibleRows.map((a) => (
              <AccountRowFlat
                key={a.id}
                a={a}
                owners={owners}
                checked={checkedIds.has(a.id)}
                onToggleCheck={() => toggleCheck(a.id)}
                onOpen={() => openAccount(a.id)}
                onOwnerChange={changeOwner}
              />
            ))}
          </>
        )}
      </Card>
      </>
      )}

      {/* Bulk-бар: смена владельца у выделенных */}
      {tab === "accounts" && checkedIds.size > 0 && (
        <div className="fixed left-1/2 bottom-6 -translate-x-1/2 z-40 flex items-center gap-3 pl-5 pr-3 py-2.5 rounded-full glass shadow-2xl border border-black/[0.08]">
          <span className="text-[13px] text-zinc-50"><b className="font-semibold">{checkedIds.size}</b> выделено</span>
          <span className="w-px h-5 bg-black/[0.12]" />
          <span className="text-[12px] text-zinc-500">Сменить владельца:</span>
          <select
            value=""
            onChange={(e) => { if (e.target.value !== "") bulkChangeOwner(e.target.value === "__admin__" ? "" : e.target.value); }}
            className="bg-black/[0.04] border border-black/[0.08] rounded-lg px-2.5 py-1.5 text-[13px] text-zinc-50 focus:outline-none focus:border-black/[0.16]"
          >
            <option value="">— выбрать —</option>
            <option value="__admin__">Я (админ)</option>
            {owners.map((o) => (<option key={o.id} value={o.id}>{o.name}</option>))}
          </select>
          <button onClick={clearChecked} title="Снять выделение"
            className="w-8 h-8 flex items-center justify-center rounded-full text-zinc-500 hover:text-zinc-50 hover:bg-black/[0.06]">
            <Icon name="x" className="w-4 h-4" />
          </button>
        </div>
      )}

      {/* Drawer с деталью аккаунта (редактор профиля) */}
      {tab === "accounts" && drawerOpen && current && (
        <div className="fixed inset-0 z-50">
          <div className="absolute inset-0 bg-black/40 backdrop-blur-[2px]" onClick={closeDrawer} />
          <div
            className="absolute top-0 right-0 bottom-0 w-[460px] glass border-l border-black/[0.08] shadow-2xl flex flex-col"
            style={{ animation: "drawerIn .28s cubic-bezier(0.2,0,0,1) both" }}
          >
            <div className="flex items-center gap-4 px-6 py-5 border-b border-black/[0.06] shrink-0">
              <Avatar name={current.name} color={current.color} avatarUrl={current.avatarUrl} size={56} />
              <div className="min-w-0 flex-1">
                <div className="text-lg font-semibold truncate text-zinc-50">{current.name}</div>
                <div className="text-[12px] font-mono text-zinc-500 truncate">{current.username || "—"}</div>
              </div>
              <button onClick={closeDrawer} title="Закрыть"
                className="w-8 h-8 flex items-center justify-center rounded-lg text-zinc-500 hover:text-zinc-50 hover:bg-black/[0.05] shrink-0">
                <Icon name="x" className="w-4 h-4" />
              </button>
            </div>
            <div className="flex-1 overflow-y-auto hide-scrollbar px-6 py-5">
              <div className="grid grid-cols-3 gap-3 mb-6">
                <Metric label="Сегодня" value={current.today} sublabel="клиентов" />
                <Metric label="Вчера" value={current.yesterday} sublabel="клиентов" />
                <Metric label="7 дней" value={current.week} sublabel="клиентов" />
              </div>
              <AccountProfileEditor accountId={current.id} owners={owners} onSaved={reload} />
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// Вкладка «Владельцы» (master-detail): слева список владельцев со «Я (админ)»
// сверху как основной; клик → справа его аккаунты + смена владельца у каждого.
function OwnersPanel() {
  const [owners, setOwners] = useStateM([]);
  const [accounts, setAccounts] = useStateM([]);
  const [loading, setLoading] = useStateM(true);
  const [sel, setSel] = useStateM("admin");   // "admin" | <ownerId>
  const [adding, setAdding] = useStateM(false);
  const [name, setName] = useStateM("");
  const [tgId, setTgId] = useStateM("");
  const [busy, setBusy] = useStateM(false);
  const [msg, setMsg] = useStateM("");

  const reload = React.useCallback(async () => {
    setLoading(true);
    const [os, accs] = await Promise.all([fetchOwners(), fetchAccounts(true)]);
    setOwners(os);
    setAccounts(accs);
    setLoading(false);
  }, []);
  useEffectM(() => { reload(); }, [reload]);

  const accFor = (ownerId) => accounts.filter((a) => a.ownerId === ownerId);
  const adminAccounts = accounts.filter((a) => !a.ownerId);

  const onAdd = async () => {
    const nm = name.trim(); const id = tgId.trim();
    if (!nm || !id) { setMsg("Укажи имя и Telegram ID"); return; }
    setBusy(true); setMsg("");
    try {
      await createOwner(nm, id);
      setName(""); setTgId(""); setAdding(false);
      await reload();
    } catch (e) { setMsg("Ошибка: " + (e && e.message ? e.message : e)); }
    finally { setBusy(false); setTimeout(() => setMsg(""), 3000); }
  };

  const onDelete = async (o) => {
    if (!window.confirm("Удалить владельца «" + o.name + "»? Его аккаунты вернутся к админу.")) return;
    setBusy(true); setMsg("");
    try { await deleteOwner(o.id); if (sel === o.id) setSel("admin"); await reload(); }
    catch (e) { setMsg("Ошибка: " + (e && e.message ? e.message : e)); }
    finally { setBusy(false); }
  };

  const onReassign = async (accId, ownerId) => {
    setBusy(true); setMsg("");
    try { await saveAccountProfile(accId, { ownerId }); await reload(); }
    catch (e) { setMsg("Ошибка: " + (e && e.message ? e.message : e)); }
    finally { setBusy(false); }
  };

  const inputCls = "w-full bg-zinc-800/60 border border-zinc-700/60 rounded-lg px-3 py-2 text-sm placeholder:text-zinc-500 focus:outline-none focus:border-indigo-500/50";
  const selOwner = sel === "admin" ? null : owners.find((o) => o.id === sel);
  const detailAccounts = sel === "admin" ? adminAccounts : accFor(sel);

  return (
    <div className="grid grid-cols-3 gap-4">
      <Card className="p-3 flex flex-col" style={{ height: "calc(100vh - 230px)", minHeight: 500 }}>
        <div className="px-2 mb-2 text-[11px] text-zinc-500 shrink-0">Владельцы</div>
        <ScrollList>
          <button onClick={() => setSel("admin")}
            className={"w-full flex items-center gap-3 p-3 rounded-lg text-left transition-colors mb-1 " + (sel === "admin" ? "bg-indigo-500/15 ring-1 ring-indigo-500/30" : "hover:bg-zinc-800/50")}>
            <div className="w-10 h-10 rounded-full bg-indigo-500/80 flex items-center justify-center shrink-0"><Icon name="star" className="w-5 h-5 text-white" /></div>
            <div className="flex-1 min-w-0">
              <div className="text-sm font-medium">Я (админ)</div>
              <div className="text-[11px] text-zinc-500">основной · все чеки мне</div>
            </div>
            <Pill tone="zinc">{loading ? "…" : adminAccounts.length}</Pill>
          </button>
          {owners.map((o) => (
            <button key={o.id} onClick={() => setSel(o.id)}
              className={"w-full flex items-center gap-3 p-3 rounded-lg text-left transition-colors " + (sel === o.id ? "bg-indigo-500/15 ring-1 ring-indigo-500/30" : "hover:bg-zinc-800/50")}>
              <Avatar name={o.name} color="from-indigo-400 to-violet-600" avatarUrl={o.avatarUrl} size={40} />
              <div className="flex-1 min-w-0">
                <div className="text-sm font-medium truncate">{o.name}</div>
                <div className="text-[11px] text-zinc-500 font-mono truncate">ID {o.telegramId}</div>
              </div>
              <Pill tone="zinc">{accFor(o.id).length}</Pill>
            </button>
          ))}
        </ScrollList>

        <div className="shrink-0 pt-2 mt-1 border-t border-zinc-800/60">
          {!adding ? (
            <button onClick={() => setAdding(true)}
              className="w-full flex items-center justify-center gap-2 px-3 py-2 rounded-lg text-sm text-indigo-300 hover:bg-indigo-500/10">
              <Icon name="plus" className="w-3.5 h-3.5" /> Добавить владельца
            </button>
          ) : (
            <div className="space-y-2 p-1">
              <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Имя (напр. Рома)" className={inputCls} />
              <input value={tgId} onChange={(e) => setTgId(e.target.value.replace(/[^0-9]/g, ""))}
                placeholder="Telegram ID" inputMode="numeric" className={inputCls + " font-mono"} />
              <div className="text-[10px] text-zinc-500 leading-relaxed">
                Друг должен раз нажать <span className="text-zinc-300">Start</span> у бота, иначе бот не сможет слать ему чеки.
              </div>
              <div className="flex gap-2">
                <button onClick={onAdd} disabled={busy}
                  className="flex-1 px-3 py-2 rounded-lg bg-indigo-500 hover:bg-indigo-600 text-white text-sm font-medium disabled:opacity-50">Добавить</button>
                <button onClick={() => { setAdding(false); setName(""); setTgId(""); }}
                  className="px-3 py-2 rounded-lg bg-zinc-800/60 border border-zinc-700/60 text-zinc-300 text-sm">Отмена</button>
              </div>
              {msg && <div className="text-[11px] text-zinc-400 text-center">{msg}</div>}
            </div>
          )}
        </div>
      </Card>

      <Card className="col-span-2 p-6">
        {loading ? (
          <div className="text-sm text-zinc-500 py-6">Загрузка…</div>
        ) : (
          <>
            <div className="flex items-center gap-4 mb-1">
              {sel === "admin"
                ? <div className="w-14 h-14 rounded-full bg-indigo-500/80 flex items-center justify-center shrink-0"><Icon name="star" className="w-7 h-7 text-white" /></div>
                : <Avatar name={(selOwner || {}).name} color="from-indigo-400 to-violet-600" avatarUrl={(selOwner || {}).avatarUrl} size={56} />}
              <div className="flex-1 min-w-0">
                <div className="text-xl font-semibold truncate">{sel === "admin" ? "Я (админ)" : (selOwner || {}).name}</div>
                <div className="text-[12px] text-zinc-500 truncate">
                  {sel === "admin" ? "основной — все аккаунты без отдельного владельца" : ("друг · ID " + ((selOwner || {}).telegramId || ""))}
                </div>
              </div>
              {sel !== "admin" && selOwner && (
                <button onClick={() => onDelete(selOwner)} disabled={busy}
                  className="flex items-center gap-1.5 text-zinc-500 hover:text-rose-400 text-sm disabled:opacity-50">
                  <Icon name="trash" className="w-4 h-4" /> Удалить
                </button>
              )}
            </div>

            {sel !== "admin" && (
              <div className="text-[12px] text-zinc-400 my-3 flex items-start gap-2 bg-amber-500/10 border border-amber-500/20 rounded-lg px-3 py-2">
                <Icon name="clock" className="w-3.5 h-3.5 mt-0.5 shrink-0 text-amber-400" />
                <span>Друг должен один раз нажать <span className="text-zinc-200">Start</span> у бота — иначе копии чеков ему не дойдут (правило Telegram).</span>
              </div>
            )}

            <div className="text-[12px] text-zinc-500 my-3">
              {sel === "admin"
                ? "Чеки со всех этих аккаунтов приходят тебе. Чтобы отдать аккаунт другу — поменяй владельца в строке справа."
                : ("Копии чеков с этих аккаунтов уходят " + ((selOwner || {}).name || "") + "; тебе приходят все.")}
            </div>

            <div className="text-[11px] text-zinc-500 uppercase tracking-wider mb-2">Аккаунты ({detailAccounts.length})</div>
            {detailAccounts.length === 0 ? (
              <div className="text-sm text-zinc-500 py-6">
                {sel === "admin" ? "Все аккаунты розданы владельцам." : "У этого владельца пока нет аккаунтов — назначь его аккаунтам тут или во вкладке «Аккаунты»."}
              </div>
            ) : (
              <div className="space-y-2 overflow-y-auto hide-scrollbar pr-1" style={{ maxHeight: "calc(100vh - 460px)" }}>
                {detailAccounts.map((a) => (
                  <div key={a.id} className="flex items-center gap-3 p-2.5 rounded-lg bg-zinc-800/40 border border-zinc-700/40">
                    <Avatar name={a.name} color={a.color} avatarUrl={a.avatarUrl} size={38} />
                    <div className="flex-1 min-w-0">
                      <div className="text-sm font-medium truncate">{a.name}</div>
                      <div className="text-[11px] text-zinc-500 truncate">{a.username || "—"}</div>
                    </div>
                    <select value={a.ownerId || ""} disabled={busy}
                      onChange={(e) => onReassign(a.id, e.target.value)}
                      className="bg-zinc-900/70 border border-zinc-700/60 rounded-lg px-2 py-1.5 text-[12px] text-zinc-200 focus:outline-none focus:border-indigo-500/50"
                      style={{ maxWidth: 150 }}>
                      <option value="">Я (админ)</option>
                      {owners.map((o) => (<option key={o.id} value={o.id}>{o.name}</option>))}
                    </select>
                  </div>
                ))}
              </div>
            )}
          </>
        )}
      </Card>
    </div>
  );
}

// Профиль → web: редактор настроек аккаунта (заменяет desktop).
// имя / возраст / username / вкл-выкл / промпт-поля / аватар.
function AccountProfileEditor({ accountId, owners = [], onSaved }) {
  const [form, setForm] = useStateM(null);
  const [pairs, setPairs] = useStateM([]); // promptFields как [[k,v],...]
  const [saving, setSaving] = useStateM(false);
  const [msg, setMsg] = useStateM("");
  const [loadError, setLoadError] = useStateM(false);
  const fileRef = useRefM(null);

  useEffectM(() => {
    let stopped = false;
    setForm(null); setLoadError(false);
    fetchAccountProfile(accountId).then((p) => {
      if (stopped) return;
      if (!p) { setLoadError(true); return; }
      setForm({ ...p, age: p.age || "18" });
      setPairs(Object.entries(p.promptFields || {}));
    });
    return () => { stopped = true; };
  }, [accountId]);

  if (loadError) return (
    <div className="text-sm text-zinc-400 py-6">
      Не удалось загрузить профиль. Если бэкенд только что обновлён — перезапусти сервер
      (новые эндпоинты профиля появляются после рестарта).
    </div>
  );
  if (!form) return <div className="text-sm text-zinc-500 py-6">Загрузка профиля…</div>;

  const set = (k, v) => setForm({ ...form, [k]: v });
  const setPair = (i, idx, val) => { const a = pairs.map((p) => p.slice()); a[i][idx] = val; setPairs(a); };
  const addPair = () => setPairs([...pairs, ["", ""]]);
  const delPair = (i) => setPairs(pairs.filter((_, j) => j !== i));

  const handleSave = async () => {
    setSaving(true); setMsg("");
    try {
      const promptFields = {};
      for (const pr of pairs) { if (String(pr[0]).trim()) promptFields[String(pr[0]).trim()] = pr[1]; }
      await saveAccountProfile(accountId, {
        name: form.name, age: form.age || "18",
        isActive: form.isActive, defaultCurrency: form.defaultCurrency, promptFields,
        ownerId: form.ownerId || "",
      });
      setMsg("Сохранено");
      if (onSaved) await onSaved();
    } catch (e) { setMsg("Ошибка: " + (e && e.message ? e.message : e)); }
    finally { setSaving(false); setTimeout(() => setMsg(""), 3000); }
  };

  const handleAvatar = async (e) => {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    setSaving(true); setMsg("");
    try { await uploadAccountAvatar(accountId, file); setMsg("Аватар обновлён"); if (onSaved) await onSaved(); }
    catch (err) { setMsg("Ошибка аватара: " + (err && err.message ? err.message : err)); }
    finally { setSaving(false); setTimeout(() => setMsg(""), 3000); }
  };

  const inputCls = "mt-1 w-full bg-zinc-800/60 border border-zinc-700/60 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-indigo-500/50";

  return (
    <div className="space-y-4">
      <div className="grid grid-cols-2 gap-3">
        <label className="block">
          <span className="text-[11px] text-zinc-500 uppercase tracking-wider">Имя</span>
          <input value={form.name || ""} onChange={(e) => set("name", e.target.value)} className={inputCls} />
        </label>
        <label className="block">
          <span className="text-[11px] text-zinc-500 uppercase tracking-wider">Возраст</span>
          <input value={form.age || ""} onChange={(e) => set("age", e.target.value)} placeholder="например, 19" className={inputCls} />
        </label>
        <div className="flex items-end">
          <button onClick={() => set("isActive", !form.isActive)}
            className={"flex items-center gap-2 px-3 py-2 rounded-lg border text-sm " + (form.isActive ? "bg-emerald-500/15 border-emerald-500/30 text-emerald-300" : "bg-zinc-800/60 border-zinc-700/60 text-zinc-400")}>
            <span className={"w-2 h-2 rounded-full " + (form.isActive ? "bg-emerald-400" : "bg-zinc-500")} />
            {form.isActive ? "Аккаунт включён" : "Аккаунт выключен"}
          </button>
        </div>
      </div>

      <label className="block">
        <span className="text-[11px] text-zinc-500 uppercase tracking-wider">Владелец</span>
        <select value={form.ownerId || ""} onChange={(e) => set("ownerId", e.target.value)} className={inputCls}>
          <option value="">— админ (по умолчанию, все чеки тебе)</option>
          {owners.map((o) => (<option key={o.id} value={o.id}>{o.name}</option>))}
        </select>
        <span className="text-[11px] text-zinc-600 mt-1 block">владельцу пойдут копии чеков с этого аккаунта</span>
      </label>

      <div>
        <div className="flex items-center justify-between mb-2">
          <span className="text-[11px] text-zinc-500 uppercase tracking-wider">Промпт (поля персоны)</span>
          <button onClick={addPair} className="text-xs text-indigo-300 hover:text-indigo-200 flex items-center gap-1">
            <Icon name="plus" className="w-3 h-3" /> добавить
          </button>
        </div>
        <div className="space-y-2">
          {pairs.length === 0 && <div className="text-xs text-zinc-600">нет полей — добавь ключ/значение (видит LLM в PROFILE_JSON)</div>}
          {pairs.map((p, i) => (
            <div key={i} className="flex items-center gap-2">
              <input value={p[0]} onChange={(e) => setPair(i, 0, e.target.value)} placeholder="ключ"
                className="w-1/3 bg-zinc-800/60 border border-zinc-700/60 rounded-md px-2 py-1.5 text-sm font-mono focus:outline-none focus:border-indigo-500/50" />
              <input value={p[1]} onChange={(e) => setPair(i, 1, e.target.value)} placeholder="значение"
                className="flex-1 bg-zinc-800/60 border border-zinc-700/60 rounded-md px-2 py-1.5 text-sm focus:outline-none focus:border-indigo-500/50" />
              <button onClick={() => delPair(i)} className="text-zinc-500 hover:text-rose-400 px-1 text-lg leading-none">×</button>
            </div>
          ))}
        </div>
      </div>

      <div className="flex items-center justify-end gap-2 mt-2 pt-4 border-t border-zinc-800/80">
        {msg && <span className="text-[11px] text-zinc-400 mr-auto">{msg}</span>}
        <input ref={fileRef} type="file" accept="image/*" onChange={handleAvatar} className="hidden" />
        <button onClick={() => fileRef.current && fileRef.current.click()} disabled={saving}
          className="flex items-center gap-2 px-3.5 py-2 rounded-lg bg-zinc-800/60 border border-zinc-700/60 hover:bg-zinc-800 text-zinc-300 text-sm disabled:opacity-50">
          <Icon name="image" className="w-3.5 h-3.5" /> Аватар
        </button>
        <button onClick={handleSave} disabled={saving}
          className="flex items-center gap-2 px-3.5 py-2 rounded-lg bg-indigo-500 hover:bg-indigo-600 text-white text-sm font-medium disabled:opacity-50">
          <Icon name="save" className="w-3.5 h-3.5" /> {saving ? "Сохраняется…" : "Сохранить"}
        </button>
      </div>
    </div>
  );
}

/* ============================
   PRICES
============================ */

function PricesPage() {
  // Прайсы per-currency: у каждой валюты свои прайсы («Гривны 1», «Гривны 2»…).
  // Базовый каждой валюты (id="base") = срез defaults (его читает бот сейчас).
  // sel = выбранный прайс {id, currency} либо {id:"__emoji__"} (общие эмодзи).
  const [variants, setVariants] = useStateM([]); // [{id,currency,label,base}]
  const [sel, setSel] = useStateM(null);
  const [editing, setEditing] = useStateM(null); // {id,currency,label} при переименовании
  const [vbusy, setVbusy] = useStateM(false);
  const [services, setServices] = useStateM([]); // услуги выбранной валюты
  const [emojis, setEmojis] = useStateM([]); // общие premium-эмодзи
  const [loading, setLoading] = useStateM(true);

  const ccyTabs = PRICE_TABS.filter((t) => t.id !== "emoji"); // uah/rub/usd/stars
  const isEmoji = !!(sel && sel.id === "__emoji__");

  const loadVariants = React.useCallback(async () => {
    const list = await fetchPriceVariants();
    setVariants(list);
    setSel((prev) => prev || (list[0] ? { id: list[0].id, currency: list[0].currency } : null));
  }, []);
  useEffectM(() => { loadVariants(); }, []);

  // Эмодзи общие — грузим один раз.
  useEffectM(() => {
    fetchPrices(null, null).then((data) => {
      setEmojis(Array.isArray(data.emojis) ? data.emojis.map((e) => ({
        symbol: e.token || e.symbol || "", id: e.customEmojiId || e.id || "", on: e.enabled !== false,
      })) : []);
    });
  }, []);

  const reload = React.useCallback(async () => {
    if (!sel || sel.id === "__emoji__") { setLoading(false); return; }
    setLoading(true);
    const data = await fetchPrices(sel.id === "base" ? null : sel.id, sel.currency);
    setServices(Array.isArray(data.services) ? data.services : []);
    setLoading(false);
  }, [sel]);

  useEffectM(() => {
    let stopped = false;
    if (!sel || sel.id === "__emoji__") { setLoading(false); return; }
    setLoading(true);
    fetchPrices(sel.id === "base" ? null : sel.id, sel.currency).then((data) => {
      if (stopped) return;
      setServices(Array.isArray(data.services) ? data.services : []);
      setLoading(false);
    });
    return () => { stopped = true; };
  }, [sel]);

  const byCcy = {};
  for (const v of variants) (byCcy[v.currency] = byCcy[v.currency] || []).push(v);
  const rowKey = (v) => v.currency + ":" + v.id;

  const handleAdd = async (ccy) => {
    setVbusy(true);
    try {
      const r = await createPriceVariant(ccy, "");
      await loadVariants();
      if (r && r.id) setSel({ id: r.id, currency: ccy });
    } finally { setVbusy(false); }
  };
  const handleDelete = async (v) => {
    setVbusy(true);
    try {
      await deletePriceVariant(v.id);
      if (sel && sel.id === v.id && sel.currency === v.currency) setSel({ id: "base", currency: v.currency });
      await loadVariants();
    } finally { setVbusy(false); }
  };
  const commitRename = async () => {
    const ed = editing;
    setEditing(null);
    if (!ed) return;
    const trimmed = (ed.label || "").trim();
    if (!trimmed) return;
    await renamePriceVariant(ed.id, trimmed, ed.currency);
    await loadVariants();
  };

  return (
    <div className="space-y-5">
      <SectionTitle title="Прайсы" subtitle="У каждой валюты свои прайсы — бот случайно шлёт один (цены не повторяются между аккаунтами)" />

      <div className="grid grid-cols-12 gap-5 items-start">
        {/* Список прайсов по валютам */}
        <Card className="col-span-3 overflow-hidden">
          <div className="max-h-[68vh] overflow-y-auto">
            {ccyTabs.map((m) => (
              <div key={m.id} className="border-b border-black/[0.06]">
                <div className="px-4 pt-3 pb-1 text-[11px] uppercase tracking-wider text-zinc-500 font-semibold flex items-center gap-1.5">
                  <span className="text-sm">{m.symbol}</span> {m.label}
                </div>
                {(byCcy[m.id] || []).map((v) => {
                  const isSel = sel && !isEmoji && sel.id === v.id && sel.currency === v.currency;
                  const isEd = editing && editing.id === v.id && editing.currency === v.currency;
                  return (
                    <div
                      key={rowKey(v)}
                      onClick={() => { if (!isEd) setSel({ id: v.id, currency: v.currency }); }}
                      className={"group pl-4 pr-2 py-2 flex items-center gap-2 cursor-pointer transition-colors " + (isSel ? "bg-[rgba(231,220,196,0.55)]" : "hover:bg-black/[0.03]")}
                    >
                      {isEd ? (
                        <input
                          autoFocus
                          value={editing.label}
                          onChange={(e) => setEditing({ ...editing, label: e.target.value })}
                          onClick={(e) => e.stopPropagation()}
                          onKeyDown={(e) => { if (e.key === "Enter") commitRename(); if (e.key === "Escape") setEditing(null); }}
                          onBlur={commitRename}
                          className="flex-1 min-w-0 bg-white/70 border border-black/15 rounded-lg px-2 py-1 text-sm outline-none"
                        />
                      ) : (
                        <div className="flex-1 min-w-0 flex items-center gap-2">
                          <span className="text-sm truncate">{v.label}</span>
                          {v.base && <span className="text-[9px] px-1.5 py-0.5 rounded-full bg-emerald-400/15 text-emerald-600 shrink-0">бот</span>}
                        </div>
                      )}
                      {!isEd && (
                        <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity" onClick={(e) => e.stopPropagation()}>
                          <button title="Переименовать" onClick={() => setEditing({ id: v.id, currency: v.currency, label: v.label })}
                            className="p-1 rounded hover:bg-zinc-700/50 text-zinc-400 hover:text-zinc-200">
                            <Icon name="pencil" className="w-3.5 h-3.5" />
                          </button>
                          {!v.base && (
                            <button title="Удалить" onClick={() => handleDelete(v)}
                              className="p-1 rounded hover:bg-red-500/15 text-zinc-400 hover:text-red-400">
                              <Icon name="trash" className="w-3.5 h-3.5" />
                            </button>
                          )}
                        </div>
                      )}
                    </div>
                  );
                })}
                <button onClick={() => handleAdd(m.id)} disabled={vbusy}
                  className="w-full pl-4 pr-2 py-2 flex items-center gap-1.5 text-[12px] text-zinc-400 hover:text-zinc-50 hover:bg-black/[0.03] disabled:opacity-40">
                  <Icon name="plus" className="w-3.5 h-3.5" /> добавить {m.label.toLowerCase()}
                </button>
              </div>
            ))}
            {/* Премиум-эмодзи (общие, не зависят от валюты) */}
            <div onClick={() => setSel({ id: "__emoji__" })}
              className={"px-4 py-3 flex items-center gap-2 cursor-pointer transition-colors " + (isEmoji ? "bg-[rgba(231,220,196,0.55)]" : "hover:bg-black/[0.03]")}>
              <Icon name="sparkles" className="w-4 h-4 text-amber-400" />
              <span className="text-sm">Премиум-эмодзи</span>
              <span className="text-[10px] text-zinc-500 ml-auto">общие</span>
            </div>
          </div>
        </Card>

        {/* Редактор выбранного прайса */}
        <div className="col-span-9">
          {!sel && <Card className="p-10"><EmptyState icon="tags" title="Выбери прайс" hint="Слева выбери прайс валюты или добавь новый." /></Card>}
          {isEmoji && (
            <div className="space-y-3">
              <div className="flex items-center justify-between">
                <div className="text-[11px] text-zinc-500">Общие для всех прайсов — подмена символов на кастом-эмодзи в витрине</div>
                <SaveButton onSave={async () => { await saveEmojis(emojis); }} />
              </div>
              <EmojiTable emojis={emojis} setEmojis={setEmojis} />
            </div>
          )}
          {sel && !isEmoji && (
            <ItemsEditor key={rowKey(sel)} currency={sel.currency} services={services} variant={sel.id} loading={loading} onSaved={reload} />
          )}
        </div>
      </div>
    </div>
  );
}

// Редактор услуг ОДНОЙ валюты в прайсе: правим названия + суммы + заголовки групп.
// serviceKey/serviceFamily не трогаем (контракт бота — матчинг/выдача).
function ItemsEditor({ currency, services, variant, loading, onSaved }) {
  const meta = PRICE_TABS.find((t) => t.id === currency) || { symbol: "", label: currency };
  const [draft, setDraft] = useStateM({}); // serviceKey -> {title?, amount?}
  const [headings, setHeadings] = useStateM({}); // origHeading -> newHeading
  const [saving, setSaving] = useStateM(false);
  const [msg, setMsg] = useStateM("");
  const [pasteOpen, setPasteOpen] = useStateM(false);
  const [pasteText, setPasteText] = useStateM("");
  const [importing, setImporting] = useStateM(false);

  const ordered = [...services].sort((a, b) => (a.order ?? 1e9) - (b.order ?? 1e9));
  const groups = [];
  let cur = null;
  for (const s of ordered) {
    const h = s.heading || "—";
    if (!cur || cur.h !== h) { cur = { h, items: [] }; groups.push(cur); }
    cur.items.push(s);
  }

  const tOf = (s) => (draft[s.serviceKey] && draft[s.serviceKey].title !== undefined ? draft[s.serviceKey].title : s.title);
  const aOf = (s) => (draft[s.serviceKey] && draft[s.serviceKey].amount !== undefined ? draft[s.serviceKey].amount : String(s.amount));
  const hOf = (h) => (headings[h] !== undefined ? headings[h] : h);
  const setT = (sk, v) => setDraft({ ...draft, [sk]: { ...(draft[sk] || {}), title: v } });
  const setA = (sk, v) => setDraft({ ...draft, [sk]: { ...(draft[sk] || {}), amount: v.replace(/[^0-9]/g, "") } });

  const handleSave = async () => {
    setSaving(true);
    setMsg("");
    try {
      const items = [];
      for (const s of ordered) {
        const it = { serviceKey: s.serviceKey };
        let changed = false;
        const t = tOf(s);
        if (t !== s.title) { it.title = t; changed = true; }
        const a = parseInt(aOf(s), 10);
        if (Number.isFinite(a) && a > 0 && a !== s.amount) { it.amount = a; changed = true; }
        const h = hOf(s.heading || "—");
        if (h !== (s.heading || "—") && h !== "—") { it.heading = h; changed = true; }
        if (changed) items.push(it);
      }
      if (!items.length) { setMsg("Нет изменений"); setSaving(false); setTimeout(() => setMsg(""), 3000); return; }
      const res = await savePriceItems(variant === "base" ? null : variant, currency, items);
      setMsg("Сохранено: " + (res?.updated ?? items.length));
      setDraft({});
      setHeadings({});
      if (onSaved) await onSaved();
    } catch (e) {
      setMsg("Ошибка: " + (e?.message || e));
    } finally {
      setSaving(false);
      setTimeout(() => setMsg(""), 4000);
    }
  };

  const handleImport = async () => {
    if (!pasteText.trim()) { setPasteOpen(false); return; }
    setImporting(true);
    try {
      const res = await importPrices(variant === "base" ? null : variant, currency, pasteText);
      setMsg("Разобрано услуг: " + (res?.count ?? "?"));
      setPasteText("");
      setPasteOpen(false);
      if (onSaved) await onSaved();
    } catch (e) {
      setMsg("Ошибка: " + (e?.message || e));
    } finally {
      setImporting(false);
      setTimeout(() => setMsg(""), 4000);
    }
  };

  return (
    <Card className="flex flex-col" style={{ minHeight: 520 }}>
      <div className="px-5 py-4 border-b border-zinc-800/80 flex items-center justify-between shrink-0">
        <div>
          <div className="text-sm font-semibold flex items-center gap-2"><span className="text-base">{meta.symbol}</span>Услуги · {meta.label}</div>
          <div className="text-[11px] text-zinc-500 mt-0.5">{services.length} услуг · правь названия и цены, или вставь готовый прайс</div>
        </div>
        <div className="flex items-center gap-2">
          {msg && <span className="text-[11px] text-zinc-400">{msg}</span>}
          {!pasteOpen && (
            <button onClick={() => setPasteOpen(true)} disabled={loading}
              className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-zinc-800/60 border border-zinc-700/60 text-zinc-300 text-xs hover:bg-zinc-700/60 disabled:opacity-40">
              <Icon name="upload" className="w-3.5 h-3.5" /> Вставить прайс
            </button>
          )}
          <button onClick={handleSave} disabled={saving || loading || pasteOpen}
            className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-indigo-500/15 border border-indigo-500/30 text-indigo-300 text-xs hover:bg-indigo-500/25 disabled:opacity-40">
            <Icon name="save" className="w-3.5 h-3.5" /> Сохранить
          </button>
        </div>
      </div>
      {pasteOpen ? (
        <div className="p-4 flex flex-col gap-3" style={{ minHeight: 420 }}>
          <div className="text-[11px] text-zinc-500 leading-relaxed">
            Вставь готовый прайс текстом (как в телеге). Система сама разберёт на услуги, цены и заголовки.
            <br />Услуги этой валюты в <b>этом прайсе</b> заменятся на разобранные.
          </div>
          <textarea
            autoFocus
            value={pasteText}
            onChange={(e) => setPasteText(e.target.value)}
            placeholder={"ФОТО\n5 шт - 150\n10 шт - 250\n\nВИДЕО\nСекс видео - 350\nВидео на заказ - 700"}
            className="flex-1 w-full bg-zinc-900/40 border border-zinc-800/60 rounded-lg px-3 py-2.5 text-sm font-mono outline-none focus:border-indigo-500/40 resize-none"
            style={{ minHeight: 320 }}
          />
          <div className="flex items-center justify-end gap-2">
            <button onClick={() => { setPasteOpen(false); setPasteText(""); }}
              className="px-3 py-1.5 rounded-lg text-xs text-zinc-400 hover:text-zinc-200">Отмена</button>
            <button onClick={handleImport} disabled={importing || !pasteText.trim()}
              className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-indigo-500/15 border border-indigo-500/30 text-indigo-300 text-xs hover:bg-indigo-500/25 disabled:opacity-40">
              <Icon name="check" className="w-3.5 h-3.5" /> {importing ? "Разбираю…" : "Разобрать и применить"}
            </button>
          </div>
        </div>
      ) : (
        <div className="p-4 overflow-y-auto space-y-4" style={{ maxHeight: "calc(100vh - 320px)" }}>
          {loading && <div className="text-sm text-zinc-500 text-center py-10">Загрузка…</div>}
          {!loading && groups.map((g, gi) => (
            <div key={gi} className="space-y-1.5">
              <input
                value={hOf(g.h)}
                onChange={(e) => setHeadings({ ...headings, [g.h]: e.target.value })}
                className="w-full bg-transparent text-[11px] uppercase tracking-wider text-zinc-500 font-semibold px-1 py-1 border-b border-zinc-800/50 focus:border-indigo-500/40 outline-none"
              />
              {g.items.map((s) => (
                <div key={s.serviceKey} className="flex items-center gap-2">
                  <input value={tOf(s)} onChange={(e) => setT(s.serviceKey, e.target.value)}
                    className="flex-1 min-w-0 bg-zinc-900/40 border border-zinc-800/60 rounded-lg px-3 py-2 text-sm focus:border-indigo-500/40 outline-none" />
                  <input value={aOf(s)} onChange={(e) => setA(s.serviceKey, e.target.value)} inputMode="numeric"
                    className="w-24 shrink-0 bg-zinc-900/40 border border-zinc-800/60 rounded-lg px-3 py-2 text-sm text-right tabular-nums focus:border-indigo-500/40 outline-none" />
                  <span className="text-xs text-zinc-500 w-4 shrink-0 text-center">{meta.symbol}</span>
                </div>
              ))}
            </div>
          ))}
          {!loading && services.length === 0 && <div className="text-sm text-zinc-500 text-center py-10">В этом прайсе пока нет услуг — нажми «Вставить прайс»</div>}
        </div>
      )}
    </Card>
  );
}

// Этап-1 фикс цен: редактор СУММ услуг. amount — единственный источник цифры;
// витрина (предпросмотр) генерится из amount на бэке. Меняем только числа.
function AmountsEditor({ currency, services, preview, loading, scope, onSaved }) {
  const tab = PRICE_TABS.find((t) => t.id === currency) || { symbol: "", label: currency };
  const [edited, setEdited] = useStateM({}); // serviceKey -> новое значение (строка)
  const [saving, setSaving] = useStateM(false);
  const [msg, setMsg] = useStateM("");
  const editorStyle = { height: "calc(100vh - 380px)", minHeight: 500 };

  // Группируем по заголовку (heading), сохраняя порядок order
  const ordered = [...services].sort((a, b) => (a.order ?? 1e9) - (b.order ?? 1e9));
  const groups = [];
  let cur = null;
  for (const s of ordered) {
    if (!cur || cur.heading !== (s.heading || "")) {
      cur = { heading: s.heading || "—", items: [] };
      groups.push(cur);
    }
    cur.items.push(s);
  }

  const changedList = Object.keys(edited)
    .map((sk) => {
      const svc = services.find((x) => x.serviceKey === sk);
      const val = parseInt(edited[sk], 10);
      if (!svc || !Number.isFinite(val) || val <= 0 || val === svc.amount) return null;
      return { currency: svc.currency, serviceKey: sk, amount: val };
    })
    .filter(Boolean);

  const handleSave = async () => {
    if (!changedList.length) return;
    setSaving(true);
    setMsg("");
    try {
      const res = await savePriceAmounts(scope === "base" ? null : scope, changedList);
      setMsg(`Сохранено: ${res?.updated ?? changedList.length}`);
      setEdited({});
      if (onSaved) await onSaved();
    } catch (e) {
      setMsg("Ошибка: " + (e?.message || e));
    } finally {
      setSaving(false);
      setTimeout(() => setMsg(""), 4000);
    }
  };

  return (
    <div className="grid grid-cols-2 gap-4">
      <Card className="flex flex-col" style={editorStyle}>
        <div className="px-5 py-4 border-b border-zinc-800/80 flex items-center justify-between shrink-0">
          <div>
            <div className="text-sm font-semibold flex items-center gap-2">
              <span className="text-base">{tab.symbol}</span>
              Суммы услуг · {tab.label}
            </div>
            <div className="text-[11px] text-zinc-500 mt-0.5">
              {services.length} услуг · цена — единый источник, витрина обновится автоматически
            </div>
          </div>
          <div className="flex items-center gap-2">
            {msg && <span className="text-[11px] text-zinc-400">{msg}</span>}
            <button
              onClick={handleSave}
              disabled={saving || loading || !changedList.length}
              className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-indigo-500/15 border border-indigo-500/30 text-indigo-300 text-xs hover:bg-indigo-500/25 disabled:opacity-40"
            >
              <Icon name="check" className="w-3 h-3" />
              {saving ? "Сохраняется…" : (changedList.length ? `Сохранить (${changedList.length})` : "Сохранить")}
            </button>
          </div>
        </div>
        <div className="flex-1 overflow-y-auto hide-scrollbar p-3 space-y-3">
          {loading ? (
            <div className="text-sm text-zinc-500 p-2">Загружается…</div>
          ) : groups.map((g, gi) => (
            <div key={gi}>
              <div className="text-[11px] uppercase tracking-wider text-zinc-500 px-2 mb-1">{g.heading}</div>
              <div className="space-y-1">
                {g.items.map((s) => {
                  const val = edited[s.serviceKey] != null ? edited[s.serviceKey] : String(s.amount);
                  const dirty = edited[s.serviceKey] != null && parseInt(edited[s.serviceKey], 10) !== s.amount;
                  return (
                    <div key={s.serviceKey} className={"flex items-center gap-2 px-2 py-1.5 rounded-lg " + (dirty ? "bg-indigo-500/10" : "hover:bg-zinc-800/40")}>
                      <span className="flex-1 text-sm text-zinc-300 truncate">{s.displayLabel || s.title}</span>
                      <input
                        type="number"
                        min="1"
                        value={val}
                        onChange={(e) => setEdited({ ...edited, [s.serviceKey]: e.target.value })}
                        className="w-24 bg-zinc-900/70 border border-zinc-700/60 rounded-md px-2 py-1 text-sm text-right text-zinc-100 focus:outline-none focus:border-indigo-500/50"
                      />
                      <span className="text-xs text-zinc-500 w-4">{tab.symbol}</span>
                    </div>
                  );
                })}
              </div>
            </div>
          ))}
        </div>
      </Card>

      <Card className="flex flex-col" style={editorStyle}>
        <div className="px-5 py-4 border-b border-zinc-800/80 shrink-0">
          <div className="text-sm font-semibold">Предпросмотр витрины</div>
          <div className="text-[11px] text-zinc-500 mt-0.5">как клиент увидит — генерится из сумм</div>
        </div>
        <pre className="flex-1 overflow-y-auto hide-scrollbar text-sm leading-relaxed p-5 font-mono text-zinc-300 whitespace-pre-wrap">{preview}</pre>
      </Card>
    </div>
  );
}

function PriceEditor({ currency, value, onChange, loading = false }) {
  const tab = PRICE_TABS.find((t) => t.id === currency);
  const lines = (value || "").split("\n").filter(Boolean);
  const editorStyle = { height: "calc(100vh - 380px)", minHeight: 500 };

  return (
    <div className="grid grid-cols-2 gap-4">
      <Card className="flex flex-col" style={editorStyle}>
        <div className="px-5 py-4 border-b border-zinc-800/80 flex items-center justify-between shrink-0">
          <div>
            <div className="text-sm font-semibold flex items-center gap-2">
              <span className="text-base">{tab.symbol}</span>
              Текст прайса · {tab.label}
            </div>
            <div className="text-[11px] text-zinc-500 mt-0.5">
              {lines.length} строк · поддерживаются Premium эмодзи
            </div>
          </div>
          <button className="flex items-center gap-1.5 text-xs text-zinc-400 hover:text-zinc-200">
            <Icon name="refresh" className="w-3 h-3" /> Обновить
          </button>
        </div>
        <textarea
          value={value}
          onChange={(e) => onChange(e.target.value)}
          spellCheck={false}
          placeholder={loading ? "Загружается..." : "Прайс для этой валюты не настроен. Введи текст или скопируй с базовых настроек."}
          className="flex-1 bg-transparent text-sm leading-relaxed p-5 font-mono text-zinc-200 resize-none focus:outline-none hide-scrollbar"
        />
      </Card>

      <Card className="flex flex-col" style={editorStyle}>
        <div className="px-5 py-4 border-b border-zinc-800/80 flex items-center justify-between shrink-0">
          <div>
            <div className="text-sm font-semibold">Предпросмотр</div>
            <div className="text-[11px] text-zinc-500 mt-0.5">как клиент увидит в Telegram</div>
          </div>
          <Pill tone={tab.tone}>{tab.symbol} {tab.label}</Pill>
        </div>
        <div className="flex-1 p-5 overflow-y-auto hide-scrollbar">
          <div className="max-w-[420px]">
            <div className="bg-indigo-500/90 text-white rounded-2xl rounded-tl-md px-4 py-3 text-[13.5px] leading-relaxed whitespace-pre-wrap font-medium shadow-lg">
              {value}
            </div>
            <div className="text-[10px] text-zinc-500 mt-1 ml-2">14:32 · отправлено ботом</div>
          </div>
        </div>
      </Card>
    </div>
  );
}

function EmojiTable({ emojis, setEmojis }) {
  const toggle = (i) => {
    const next = [...emojis];
    next[i] = { ...next[i], on: !next[i].on };
    setEmojis(next);
  };
  const update = (i, key, val) => {
    const next = [...emojis];
    next[i] = { ...next[i], [key]: val };
    setEmojis(next);
  };
  const remove = (i) => setEmojis(emojis.filter((_, idx) => idx !== i));
  const add = () => setEmojis([...emojis, { symbol: "", id: "", on: true }]);

  return (
    <Card className="p-5">
      <div className="flex items-start justify-between mb-5">
        <div>
          <div className="text-sm font-semibold">Premium эмодзи</div>
          <div className="text-[11px] text-zinc-500 mt-0.5 max-w-md">
            Эмодзи отправляются ботом как Premium-эмодзи в Telegram. ID можно скопировать из любого Telegram-сообщения.
          </div>
        </div>
        <button
          onClick={add}
          className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-indigo-500 hover:bg-indigo-600 text-white text-xs font-medium"
        >
          <Icon name="plus" className="w-3 h-3" /> Добавить
        </button>
      </div>

      <div className="grid grid-cols-[60px_80px_1fr_40px] gap-3 px-3 pb-2 mb-1 text-[10px] uppercase tracking-wider text-zinc-500 font-semibold border-b border-zinc-800/80">
        <div>Вкл</div>
        <div>Символ</div>
        <div>Premium ID</div>
        <div />
      </div>

      <div className="space-y-1">
        {emojis.map((e, i) => (
          <div
            key={i}
            className={"grid grid-cols-[60px_80px_1fr_40px] gap-3 items-center px-3 py-2 rounded-lg transition-colors " + (e.on ? "hover:bg-zinc-800/40" : "opacity-50 hover:opacity-100 hover:bg-zinc-800/40")}
          >
            <Toggle on={e.on} onChange={() => toggle(i)} />
            <input
              value={e.symbol}
              onChange={(ev) => update(i, "symbol", ev.target.value)}
              className="bg-zinc-800/60 border border-zinc-700/60 rounded-md px-2.5 py-1.5 text-base focus:outline-none focus:border-indigo-500/50 text-center"
              maxLength={4}
            />
            <input
              value={e.id}
              onChange={(ev) => update(i, "id", ev.target.value)}
              placeholder="5379732703489630126"
              className="bg-zinc-800/60 border border-zinc-700/60 rounded-md px-3 py-1.5 text-sm font-mono tabular-nums focus:outline-none focus:border-indigo-500/50"
            />
            <button
              onClick={() => remove(i)}
              className="w-8 h-8 rounded-md flex items-center justify-center text-zinc-500 hover:text-rose-400 hover:bg-rose-500/10 transition-colors"
            >
              <Icon name="trash" className="w-3.5 h-3.5" />
            </button>
          </div>
        ))}
        {emojis.length === 0 && (
          <div className="text-center text-sm text-zinc-500 py-12">Нет эмодзи — добавьте первый</div>
        )}
      </div>
    </Card>
  );
}

Object.assign(window, { AccountsPage, PricesPage });
