/* MBEX — History, Profile, Referral and info screens */

function isHistoryFinal(order) {
  return ["completed", "cancelled"].includes(order.serverStatus);
}

function historyOrderSubtitle(order) {
  if (order.typeKey === "sell") {
    const status = order.depositStatus || "waiting";
    if (status === "aml_pending") {
      return "AML проверка депозита";
    }
    if (status === "aml_failed") {
      return "Нужен AML-разбор";
    }
    if (status === "limit_failed") {
      return "Сумма вне лимитов";
    }
    if (status === "refund_swept") {
      return "Средства на возвратном кошельке";
    }
    if (order.depositAmountReceived > 0) {
      return `${window.MBEX.fmtUsdt(order.depositAmountReceived)} USDT получено`;
    }
    if (status === "expired") {
      return "Депозитный адрес истёк";
    }
    return "Ожидаем USDT TRC-20";
  }
  if (order.typeKey === "transfer") {
    return [order.fromCity, order.toCity].filter(Boolean).join(" → ") || "Маршрут уточняется";
  }
  return order.wallet ? `На ${order.wallet}` : "TRC-20 кошелёк из заявки";
}

const HISTORY_TYPE_FILTERS = [
  { v: "all", l: "Все операции" },
  { v: "buy", l: "Покупка" },
  { v: "sell", l: "Продажа" },
];

const HISTORY_STATUS_FILTERS = [
  { v: "all", l: "Все статусы" },
  { v: "active", l: "В работе" },
  { v: "done", l: "Завершённые" },
];

function historyMatchesFilters(order, typeFilter, statusFilter) {
  const typeMatches = typeFilter === "all" || order.typeKey === typeFilter;
  const statusMatches = statusFilter === "all"
    || (statusFilter === "active" && !isHistoryFinal(order))
    || (statusFilter === "done" && isHistoryFinal(order));
  return typeMatches && statusMatches;
}

function historyFilterLabel(options, value) {
  return options.find((item) => item.v === value)?.l || options[0].l;
}

function HistoryFilterChip({ label, active, onClick, ariaLabel }) {
  return (
    <button
      type="button"
      className={`history-filter-chip${active ? " is-active" : ""}`}
      onClick={onClick}
      aria-label={ariaLabel}
      aria-haspopup="dialog"
    >
      <span>{label}</span>
      <Icons.chevR size={16} sw={2.2} />
    </button>
  );
}

function HistoryFilterSheet({ title, options, value, onSelect, onClose }) {
  React.useEffect(() => {
    const handleKeyDown = (event) => {
      if (event.key === "Escape") {
        onClose();
      }
    };
    document.addEventListener("keydown", handleKeyDown);
    return () => document.removeEventListener("keydown", handleKeyDown);
  }, [onClose]);

  return ReactDOM.createPortal(
    <div className="history-filter-overlay" onClick={onClose}>
      <section
        className="history-filter-sheet"
        role="dialog"
        aria-modal="true"
        aria-label={title}
        onClick={(event) => event.stopPropagation()}
      >
        <div className="history-filter-sheet-head">
          <strong>{title}</strong>
          <button type="button" onClick={onClose} aria-label="Закрыть фильтр">
            <Icons.close size={19} sw={2.2} />
          </button>
        </div>
        <div className="history-filter-options" role="radiogroup" aria-label={title}>
          {options.map((item) => {
            const selected = value === item.v;
            return (
              <button
                key={item.v}
                type="button"
                className={selected ? "is-selected" : ""}
                onClick={() => onSelect(item.v)}
                role="radio"
                aria-checked={selected}
              >
                <span>{item.l}</span>
                {selected ? <Icons.check size={19} sw={2.4} /> : null}
              </button>
            );
          })}
        </div>
      </section>
    </div>,
    document.body,
  );
}

function HistoryOrderRow({ order, app, onOpenOrder }) {
  const buying = order.typeKey === "buy";
  const selling = order.typeKey === "sell";
  const transfer = order.typeKey === "transfer";
  const badge = window.MBEX.getHistoryBadge(order, app.nowMs);
  const Icon = transfer ? Icons.swap : buying ? Icons.arrowDown : Icons.arrowUp;
  const iconClass = transfer ? "is-transfer" : buying ? "is-buy" : "is-sell";
  return (
    <div className="history-order-card" onClick={() => onOpenOrder(order.id)}>
      <div className={`history-order-icon ${iconClass}`}>
        <Icon size={19} sw={2.2} />
      </div>
      <div className="history-order-main">
        <div className="history-order-title">
          <strong>{window.MBEX.orderTypeLabel(order)}</strong>
          <span>{window.MBEX.orderDisplayCode(order)}</span>
        </div>
        <div className={`history-order-sub${buying && order.wallet ? " wallet-address-full" : ""}`}>
          {historyOrderSubtitle(order)}
        </div>
        <div className="history-order-meta">
          <span>{window.MBEX.formatDateTime(order.createdAt)}</span>
          {selling && order.depositStatus ? <em>{depositStatusText(order.depositStatus)}</em> : null}
        </div>
      </div>
      <div className="history-order-side">
        <strong className="num">{window.MBEX.orderDisplayAmount(order)}</strong>
        <Pill cls={badge.cls} dot={badge.dot}>{badge.label}</Pill>
      </div>
    </div>
  );
}

function HistoryScreen({ app, onOpenOrder }) {
  const [typeFilter, setTypeFilter] = React.useState("all");
  const [statusFilter, setStatusFilter] = React.useState("all");
  const [openFilter, setOpenFilter] = React.useState(null);
  const orders = app.privateState.orders || [];
  const list = orders.filter((order) => historyMatchesFilters(order, typeFilter, statusFilter));
  const activeOptions = openFilter === "type" ? HISTORY_TYPE_FILTERS : HISTORY_STATUS_FILTERS;
  const activeValue = openFilter === "type" ? typeFilter : statusFilter;
  const activeTitle = openFilter === "type" ? "Тип операции" : "Статус";

  function selectFilter(value) {
    if (openFilter === "type") {
      setTypeFilter(value);
    } else {
      setStatusFilter(value);
    }
    setOpenFilter(null);
  }

  return (
    <>
      <div className="body">
        <div className="stack screen-enter">
          <div className="history-filter-bar">
            <HistoryFilterChip
              label={historyFilterLabel(HISTORY_TYPE_FILTERS, typeFilter)}
              active={typeFilter !== "all"}
              onClick={() => setOpenFilter("type")}
              ariaLabel={`Тип операции: ${historyFilterLabel(HISTORY_TYPE_FILTERS, typeFilter)}`}
            />
            <HistoryFilterChip
              label={historyFilterLabel(HISTORY_STATUS_FILTERS, statusFilter)}
              active={statusFilter !== "all"}
              onClick={() => setOpenFilter("status")}
              ariaLabel={`Статус: ${historyFilterLabel(HISTORY_STATUS_FILTERS, statusFilter)}`}
            />
          </div>

          {list.length ? (
            <div className="history-list">
              {list.map((order) => (
                <HistoryOrderRow key={order.id} order={order} app={app} onOpenOrder={onOpenOrder} />
              ))}
            </div>
          ) : (
            <div className="card card-pad">
              <EmptyState
                icon={<Icons.history size={36} style={{ opacity: 0.5 }} />}
                title={orders.length ? "Ничего не найдено" : "Заявок пока нет"}
                text={orders.length
                  ? "Измените тип операции или статус."
                  : "После первой покупки или продажи история появится здесь."}
              />
            </div>
          )}
        </div>
      </div>
      {openFilter ? (
        <HistoryFilterSheet
          title={activeTitle}
          options={activeOptions}
          value={activeValue}
          onSelect={selectFilter}
          onClose={() => setOpenFilter(null)}
        />
      ) : null}
    </>
  );
}

function formatProfilePct(value) {
  const number = Number(value || 0);
  return `${number.toLocaleString("ru-RU", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  })}%`;
}

function formatLoyaltyPct(value) {
  const number = Number(value || 0);
  return `${number.toLocaleString("ru-RU", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 3,
  })}%`;
}

function formatLoyaltyUsdt(value) {
  return Number(value || 0).toLocaleString("ru-RU", {
    minimumFractionDigits: 0,
    maximumFractionDigits: 2,
  });
}

function ProfileInfoRow({ label, value, tone }) {
  const color = tone === "pos" ? "var(--pos)" : tone === "warn" ? "var(--warn)" : "var(--text)";
  return (
    <div className="profile-info-row">
      <span>{label}</span>
      <strong style={{ color }}>{value}</strong>
    </div>
  );
}

const MINIAPP_TRC20_RE = /^T[a-zA-Z0-9]{33}$/;

function referralDeepLink(referral, botUrl) {
  return referral.refCode ? `https://t.me/mbex_exchange_bot?start=${referral.refCode}` : botUrl;
}

async function shareReferralLink(app, deepLink) {
  const ok = await window.MBEX.shareText({
    title: "MBEX",
    text: `Обменивай USDT в MBEX: ${deepLink}`,
    url: deepLink,
  });
  if (!ok) {
    const copied = await window.MBEX.copyText(deepLink);
    app.pushToast(copied ? "Ссылка скопирована" : "Не удалось поделиться", copied ? "success" : "error");
  }
}

function ProfileMenuRow({ title, detail, onClick, muted = false }) {
  return (
    <button type="button" className={`profile-menu-row${muted ? " is-muted" : ""}`} onClick={onClick}>
      <span>{title}</span>
      <span className="profile-menu-row-tail">
        {detail ? <em>{detail}</em> : null}
        <Icons.chevR size={16} sw={2.2} />
      </span>
    </button>
  );
}

function ProfileScreen({ app, nav }) {
  const profile = app.privateState.profile || {};
  const referral = app.privateState.referral || {};
  const vip = referral.vip || {};
  const telegramUser = window.MBEX.getTelegramUser() || {};
  const canLogoutWeb = Boolean(app.authState && app.authState.isWebSession);
  const displayName = profile.fio || [telegramUser.first_name, telegramUser.last_name].filter(Boolean).join(" ") || "Клиент MBEX";
  const shortName = displayName.trim().split(/\s+/).slice(0, 2).join(" ");
  const avatarLetter = shortName.charAt(0).toUpperCase() || "M";
  const wallets = app.privateState.wallets || [];
  const couriers = app.privateState.couriers || [];
  const totalUsdt = Number(vip.total_usdt ?? profile.vip_total_usdt ?? profile.total_usdt ?? 0);
  const vipLevel = Number(vip.level ?? profile.vip_level ?? 0);
  const vipName = vip.name || profile.vip_name || (vipLevel > 0 ? `VIP ${vipLevel}` : "Standard");
  const vipDiscountPct = Number(vip.commission_discount_pct ?? profile.commission_discount_pct ?? 0);
  const hasReferralDiscount = Boolean(referral.hasFirstOrderDiscount || referral.has_first_order_discount);
  const buyBasePct = Number(profile.commission_pct || 0);
  const buyAfterVipPct = buyBasePct * Math.max(0, 1 - vipDiscountPct / 100);
  const buyEffectivePct = hasReferralDiscount ? buyAfterVipPct * 0.5 : buyAfterVipPct;
  const nextTier = Number(vip.next_tier ?? profile.next_tier ?? 0);
  const remaining = nextTier > 0 ? Math.max(0, nextTier - totalUsdt) : 0;
  const progress = nextTier > 0 ? Math.max(0, Math.min(100, (totalUsdt / nextTier) * 100)) : 100;
  const webLogin = profile.web_login || telegramUser.username || "";
  const loginDisplay = webLogin ? `@${webLogin}` : "client";
  const deepLink = referralDeepLink(referral, app.botUrl);
  const referralDisplayLink = referral.refCode ? `mbex.pro/r/${referral.refCode}` : "Ссылка появится после загрузки";
  const referralSharePct = Number(referral.commissionSharePct || 35);
  const globalBuyPct = Number(app.publicState?.config?.commission_settings?.buy_pct ?? 0.1);
  const referralTurnoverPct = globalBuyPct * referralSharePct / 100;
  const referralTurnoverText = referralTurnoverPct.toLocaleString("ru-RU", {
    minimumFractionDigits: 3,
    maximumFractionDigits: 3,
  });
  const [editing, setEditing] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const [form, setForm] = React.useState({
    fio: profile.fio || "",
    phone: profile.phone || "",
    email: profile.email || "",
  });

  React.useEffect(() => {
    if (!editing) {
      setForm({
        fio: profile.fio || "",
        phone: profile.phone || "",
        email: profile.email || "",
      });
    }
  }, [profile.fio, profile.phone, profile.email, editing]);

  function startEdit() {
    setForm({
      fio: profile.fio || "",
      phone: profile.phone || "",
      email: profile.email || "",
    });
    setEditing(true);
  }

  function updateField(key, value) {
    setForm((prev) => ({ ...prev, [key]: value }));
  }

  async function saveProfile() {
    setSaving(true);
    try {
      await app.updateProfile({
        fio: form.fio.trim(),
        phone: form.phone.trim(),
        email: form.email.trim(),
      });
      setEditing(false);
    } catch (error) {
      // toast handled by bridge
    } finally {
      setSaving(false);
    }
  }

  async function handleShare() {
    await shareReferralLink(app, deepLink);
  }

  return (
    <div className="body profile-screen">
      <div className="profile-stack screen-enter">
        <button type="button" className="profile-identity-card" onClick={startEdit}>
          <span className="profile-avatar">{avatarLetter}</span>
          <span className="profile-identity-main">
            <strong>{shortName}</strong>
            <em>{loginDisplay}</em>
          </span>
          <span className={`profile-kyc-badge ${profile.verified ? "is-verified" : ""}`}>
            {profile.verified ? "KYC ✓" : "Без KYC"}
          </span>
          <Icons.chevR className="profile-identity-chevron" size={16} sw={2.2} />
        </button>

        <section className="profile-level-card">
          <div className="profile-level-head">
            <div>
              <span className="profile-card-kicker">Ваш уровень</span>
              <strong className="profile-level-name">{vipName}</strong>
            </div>
            <div className="profile-level-commission">
              <span className="profile-card-kicker">Комиссия</span>
              <strong className="num">{formatProfilePct(buyEffectivePct)}</strong>
            </div>
          </div>
          <div className="profile-level-progress-head">
            <span>Объём за 30 дней</span>
            <strong className="num">
              {window.MBEX.fmtUsdt(totalUsdt)}{nextTier > 0 ? ` / ${window.MBEX.fmtUsdt(nextTier)} USDT` : " USDT"}
            </strong>
          </div>
          <div className="profile-level-progress" aria-label={`Прогресс уровня ${progress.toFixed(1)}%`}>
            {progress > 0 ? <span style={{ width: `${progress}%` }} /> : null}
          </div>
          <p>
            {nextTier > 0
              ? `Ещё ${window.MBEX.fmtUsdt(remaining)} USDT за 30 дней — и комиссия станет ниже на уровне VIP`
              : "У вас максимальный доступный уровень и минимальная комиссия"}
          </p>
          <button type="button" className="profile-level-link" onClick={() => nav("loyalty")}>
            <span>Все уровни и комиссии</span>
            <Icons.chevR size={16} sw={2.2} />
          </button>
        </section>

        <section className="profile-friends-card">
          <div className="profile-friends-head">
            <h2>Друзья</h2>
            <button type="button" onClick={() => nav("referral")}>Подробнее ›</button>
          </div>
          <div className="profile-friends-stats">
            <div>
              <span>Приглашено</span>
              <strong className="num">{referral.refCount || 0}</strong>
            </div>
            <div>
              <span>Заработано, USDT</span>
              <strong className="num">{window.MBEX.fmtUsdt(referral.refEarned || 0)}</strong>
            </div>
          </div>
          <p>Вам — {referralTurnoverText}% с оборота каждого приглашённого, пожизненно.</p>
          <div className="profile-referral-action">
            <span>{referralDisplayLink}</span>
            <button type="button" onClick={handleShare}>Отправить</button>
          </div>
        </section>

        {editing ? (
          <div className="card card-pad stack-sm profile-edit-card">
            <div className="section-headline">
              <span>Редактировать профиль</span>
            </div>
            <div>
              <label className="field-lbl">ФИО</label>
              <input
                className="field"
                value={form.fio}
                maxLength="200"
                placeholder="Как обращаться"
                onChange={(event) => updateField("fio", event.target.value)}
              />
            </div>
            <div>
              <label className="field-lbl">Телефон</label>
              <input
                className="field"
                value={form.phone}
                maxLength="50"
                placeholder="+7..."
                inputMode="tel"
                onChange={(event) => updateField("phone", event.target.value)}
              />
            </div>
            <div>
              <label className="field-lbl">Email</label>
              <input
                className="field"
                value={form.email}
                maxLength="200"
                placeholder="name@example.com"
                inputMode="email"
                onChange={(event) => updateField("email", event.target.value)}
              />
            </div>
            <div className="profile-edit-actions">
              <button type="button" className="btn btn-primary btn-sm" disabled={saving} onClick={saveProfile}>
                <Icons.check size={17} />
                {saving ? "Сохраняем..." : "Сохранить"}
              </button>
              <button type="button" className="btn btn-ghost btn-sm" disabled={saving} onClick={() => setEditing(false)}>
                <Icons.close size={17} />
                Отмена
              </button>
            </div>
          </div>
        ) : null}

        <section className="profile-menu-card">
          <ProfileMenuRow
            title="Данные и безопасность"
            detail={profile.verified ? "Подтверждён" : "Не пройден"}
            onClick={startEdit}
          />
          <ProfileMenuRow title="Кошельки TRC-20" detail={wallets.length || ""} onClick={() => nav("wallets")} />
          <ProfileMenuRow title="Получатели" detail={couriers.length || ""} onClick={() => nav("couriers")} />
          <ProfileMenuRow title="Поддержка" onClick={() => nav("support")} />
          <ProfileMenuRow title="Офисы MBEX" onClick={() => nav("offices")} />
          <ProfileMenuRow title="AML / KYC / KYT" onClick={() => nav("aml")} />
          {canLogoutWeb ? (
            <ProfileMenuRow title="Выйти из web-сессии" muted onClick={app.logout} />
          ) : null}
        </section>
      </div>
    </div>
  );
}

function WalletsScreen({ app }) {
  const wallets = app.privateState.wallets || [];
  const [showForm, setShowForm] = React.useState(false);
  const [name, setName] = React.useState("");
  const [address, setAddress] = React.useState("");
  const [saving, setSaving] = React.useState(false);
  const [menuId, setMenuId] = React.useState(null);
  const [confirmingId, setConfirmingId] = React.useState(null);
  const [renamingId, setRenamingId] = React.useState(null);
  const [renameValue, setRenameValue] = React.useState("");

  const addressValue = address.trim();
  const nameValue = name.trim();
  const validAddress = MINIAPP_TRC20_RE.test(addressValue);
  const canAdd = validAddress && !saving && wallets.length < 20;

  function formatWalletUse(value) {
    if (!value) {
      return "ещё не использован";
    }
    const parsed = new Date(value);
    if (Number.isNaN(parsed.getTime())) {
      return "Использован ранее";
    }
    const date = parsed.toLocaleDateString("ru-RU", { day: "numeric", month: "long" });
    return `использован ${date}`;
  }

  function openForm() {
    setMenuId(null);
    setConfirmingId(null);
    setShowForm(true);
  }

  function closeForm() {
    setName("");
    setAddress("");
    setShowForm(false);
  }

  async function pasteAddress() {
    if (!navigator.clipboard || !navigator.clipboard.readText) {
      app.pushToast("Вставьте адрес вручную", "error");
      return;
    }
    try {
      const text = (await navigator.clipboard.readText()).trim();
      if (!text) {
        app.pushToast("Буфер обмена пуст", "error");
        return;
      }
      setAddress(text.slice(0, 34));
    } catch (error) {
      app.pushToast("Не удалось прочитать буфер. Вставьте адрес вручную.", "error");
    }
  }

  async function addWallet() {
    if (!validAddress) {
      app.pushToast("Адрес TRC-20 начинается с T и состоит из 34 символов", "error");
      return;
    }
    setSaving(true);
    try {
      await app.addWallet(nameValue || "Кошелёк", addressValue);
      closeForm();
    } catch (error) {
      // toast handled by bridge
    } finally {
      setSaving(false);
    }
  }

  async function deleteWallet(walletId) {
    if (confirmingId !== walletId) {
      setConfirmingId(walletId);
      return;
    }
    setConfirmingId(null);
    try {
      await app.deleteWallet(walletId);
    } catch (error) {
      // toast handled by bridge
    }
  }

  async function setDefault(walletId) {
    setMenuId(null);
    try {
      await app.updateWallet(walletId, { is_default: true });
    } catch (error) {
      // toast handled by bridge
    }
  }

  function startRename(wallet) {
    setRenameValue(wallet.name || "Кошелёк");
    setRenamingId(wallet.id);
    setMenuId(null);
  }

  async function saveRename(walletId) {
    const nextName = renameValue.trim();
    if (!nextName) {
      app.pushToast("Укажите название кошелька", "error");
      return;
    }
    try {
      await app.updateWallet(walletId, { name: nextName });
      setRenamingId(null);
      setRenameValue("");
    } catch (error) {
      // toast handled by bridge
    }
  }

  return (
    <div className="body wallets-screen">
      <div className="wallets-shell screen-enter">
        {!wallets.length && !showForm ? (
          <div className="wallet-empty-state">
            <section className="wallet-empty-card">
              <h2>Сохраните адрес — и он будет подставляться в заявку</h2>
              <p>При покупке USDT адрес не придётся вводить и сверять заново: выберете его из списка одним касанием. До 20 адресов.</p>
            </section>
            <button className="btn btn-primary wallet-primary-action" type="button" onClick={openForm}>
              <Icons.plus size={19} />
              Добавить адрес
            </button>
          </div>
        ) : null}

        {showForm ? (
          <section className="wallet-editor-card">
            <div className="wallet-editor-head">
              <h2>Куда получать USDT</h2>
              <button type="button" onClick={closeForm}>Отмена</button>
            </div>

            <label className="wallet-field-group">
              <span>TRC-20 адрес</span>
              <div className={`wallet-address-input${validAddress ? " is-valid" : addressValue ? " is-error" : ""}`}>
                <input
                  className="num"
                  placeholder="T… 34 символа"
                  maxLength="34"
                  value={address}
                  onChange={(event) => setAddress(event.target.value.trim())}
                  autoCapitalize="off"
                  autoCorrect="off"
                  spellCheck="false"
                />
                {!addressValue ? <button type="button" onClick={pasteAddress}>Вставить</button> : null}
              </div>
            </label>

            {addressValue ? (
              validAddress ? (
                <div className="wallet-validation is-valid">
                  <span>✓ Формат верный — сеть TRON</span>
                  <button type="button" onClick={() => setAddress("")}>Очистить</button>
                </div>
              ) : (
                <div className="wallet-validation is-error">Адрес TRC-20 начинается с T и состоит из 34 символов</div>
              )
            ) : null}

            <label className="wallet-field-group">
              <span className="wallet-name-label">
                <span>Название — необязательно</span>
                <em>{name.length}/20</em>
              </span>
              <input
                className="wallet-name-input"
                placeholder="Например, основной"
                maxLength="20"
                value={name}
                onChange={(event) => setName(event.target.value)}
              />
            </label>

            <button className="btn btn-primary wallet-primary-action" type="button" disabled={!canAdd} onClick={addWallet}>
              {saving ? "Сохраняем..." : "Сохранить адрес"}
            </button>
          </section>
        ) : null}

        {wallets.length ? (
          <section className="wallet-addresses-section">
            <div className="wallet-list-head">
              <span>Адреса для получения USDT</span>
              <em>{wallets.length} из 20</em>
            </div>
            <div className="wallet-address-list">
              {wallets.map((wallet) => (
                <div key={wallet.id} className={`wallet-address-row${wallet.is_default ? " is-default" : ""}`}>
                  {renamingId === wallet.id ? (
                    <div className="wallet-rename-panel">
                      <input
                        value={renameValue}
                        maxLength="20"
                        autoFocus
                        onChange={(event) => setRenameValue(event.target.value)}
                      />
                      <div>
                        <button type="button" onClick={() => saveRename(wallet.id)}>Сохранить</button>
                        <button type="button" onClick={() => setRenamingId(null)}>Отмена</button>
                      </div>
                    </div>
                  ) : (
                    <React.Fragment>
                      <button
                        type="button"
                        className="wallet-default-button"
                        aria-label={wallet.is_default ? "Кошелёк по умолчанию" : "Сделать кошельком по умолчанию"}
                        onClick={() => !wallet.is_default && setDefault(wallet.id)}
                      >
                        <span />
                      </button>
                      <div className="wallet-address-main">
                        <div className="wallet-address-title">
                          <strong>{wallet.name || "Кошелёк"}</strong>
                          {wallet.is_default ? <span>По умолчанию</span> : null}
                        </div>
                        <button
                          type="button"
                          className="wallet-address-value num wallet-address-full"
                          onClick={() => window.MBEX.copyText(wallet.address)}
                        >
                          {wallet.address}
                        </button>
                        <small>{formatWalletUse(wallet.last_used_at)}</small>
                      </div>
                      <div className="wallet-row-menu-wrap">
                        <button
                          type="button"
                          className="wallet-row-menu-button"
                          aria-label={`Действия с кошельком ${wallet.name || "Кошелёк"}`}
                          onClick={() => {
                            setConfirmingId(null);
                            setMenuId(menuId === wallet.id ? null : wallet.id);
                          }}
                        >
                          <Icons.dots size={20} />
                        </button>
                        {menuId === wallet.id ? (
                          <div className="wallet-row-menu">
                            <button type="button" onClick={() => startRename(wallet)}>Переименовать</button>
                            <button
                              type="button"
                              className="is-danger"
                              onClick={() => deleteWallet(wallet.id)}
                            >
                              {confirmingId === wallet.id ? "Подтвердить удаление" : "Удалить"}
                            </button>
                          </div>
                        ) : null}
                      </div>
                    </React.Fragment>
                  )}
                </div>
              ))}
            </div>
            {!showForm && wallets.length < 20 ? (
              <button type="button" className="wallet-add-secondary" onClick={openForm}>
                <Icons.plus size={18} />
                Добавить адрес
              </button>
            ) : null}
          </section>
        ) : showForm ? (
          <p className="wallet-empty-note">Сохранённых адресов пока нет — первый появится здесь после сохранения. Всего можно хранить до 20.</p>
        ) : (
          <div className="wallet-info-note">
            <p>Сохранённый адрес используется только для получения USDT по вашим заявкам. Изменить или удалить его можно в любой момент.</p>
          </div>
        )}

        {wallets.length ? (
          <div className="wallet-info-note wallet-default-note">
            <p>Адрес по умолчанию подставляется в заявку на покупку — его можно сменить в один тап при оформлении.</p>
          </div>
        ) : null}
      </div>
    </div>
  );
}

function CouriersScreen({ app }) {
  const couriers = app.privateState.couriers || [];
  const [fio, setFio] = React.useState("");
  const [saving, setSaving] = React.useState(false);
  const [confirmingId, setConfirmingId] = React.useState(null);
  const fioValue = fio.trim();
  const canAdd = fioValue.length > 2 && !saving;

  async function addCourier() {
    if (fioValue.length <= 2) {
      app.pushToast("Укажите ФИО получателя", "error");
      return;
    }
    setSaving(true);
    try {
      await app.addCourier(fioValue);
      setFio("");
    } catch (error) {
      // toast handled by bridge
    } finally {
      setSaving(false);
    }
  }

  async function deleteCourier(courierId) {
    if (confirmingId !== courierId) {
      setConfirmingId(courierId);
      return;
    }
    setConfirmingId(null);
    try {
      await app.deleteCourier(courierId);
    } catch (error) {
      // toast handled by bridge
    }
  }

  return (
    <div className="body">
      <div className="stack screen-enter">
        <div className="card card-pad stack-sm saved-manager-card">
          <div className="section-headline">
            <span>Новое ФИО</span>
            <em>{couriers.length}/20</em>
          </div>
          <div>
            <label className="field-lbl">ФИО получателя</label>
            <input
              className="field"
              placeholder="Фамилия Имя Отчество"
              maxLength="200"
              value={fio}
              onChange={(event) => setFio(event.target.value)}
            />
          </div>
          <button className="btn btn-primary btn-sm" type="button" disabled={!canAdd} onClick={addCourier}>
            <Icons.plus size={18} />
            {saving ? "Сохраняем..." : "Сохранить ФИО"}
          </button>
        </div>

        <div>
          <div className="eyebrow" style={{ marginLeft: 4, marginBottom: 8 }}>Сохранённые получатели</div>
          {couriers.length ? (
            <div className="saved-item-list">
              {couriers.map((courier) => (
                <div key={courier.id} className="saved-item-card">
                  <div className="saved-item-icon"><Icons.user size={20} /></div>
                  <div className="saved-item-main">
                    <strong>{courier.fio || "Получатель"}</strong>
                    <span>Для заявок с другим ФИО</span>
                  </div>
                  <button
                    type="button"
                    className={`saved-delete-btn ${confirmingId === courier.id ? "is-confirm" : ""}`}
                    onClick={() => deleteCourier(courier.id)}
                  >
                    {confirmingId === courier.id ? "Подтвердить" : <Icons.close size={17} />}
                  </button>
                </div>
              ))}
            </div>
          ) : (
            <div className="card card-pad">
              <EmptyState
                icon={<Icons.user size={26} />}
                title="Получателей пока нет"
                text="Сохранённые ФИО будут доступны в формах покупки и продажи."
              />
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function parseReferralAmount(value) {
  const parsed = Number(String(value || "").replace(/\s/g, "").replace(",", ".") || 0);
  return Number.isFinite(parsed) ? parsed : 0;
}

function referralStatusText(status) {
  const key = String(status || "pending").toLowerCase();
  const labels = {
    pending: "На проверке",
    approved: "Одобрено",
    paid: "Выплачено",
    completed: "Выплачено",
    rejected: "Отклонено",
    cancelled: "Отменено",
  };
  return labels[key] || status || "На проверке";
}

function referralPersonName(item) {
  return item?.referred_fio || item?.fio || item?.tg_username || `ID ${item?.referred_tg_id || item?.tg_id || "—"}`;
}

function ReferralScreen({ app, nav }) {
  const referral = app.privateState.referral || {};
  const profile = app.privateState.profile || {};
  const wallets = app.privateState.wallets || [];
  const accruals = app.privateState.referralLog || [];
  const withdrawals = app.privateState.referralWithdrawals || [];
  const referrals = referral.referrals || [];
  const vip = referral.vip || {};
  const [code, setCode] = React.useState("");
  const [withdrawAmount, setWithdrawAmount] = React.useState("");
  const [withdrawWallet, setWithdrawWallet] = React.useState(
    wallets[0] ? wallets[0].address : ""
  );
  const [selectedWalletId, setSelectedWalletId] = React.useState(wallets[0] ? wallets[0].id : null);
  const [historyTab, setHistoryTab] = React.useState("accruals");
  const [showWithdrawForm, setShowWithdrawForm] = React.useState(false);
  const [showApplyForm, setShowApplyForm] = React.useState(false);
  const [applying, setApplying] = React.useState(false);
  const [withdrawing, setWithdrawing] = React.useState(false);
  const deepLink = referralDeepLink(referral, app.botUrl);
  const refBalance = Number(referral.refBalance || 0);
  const refEarned = Number(referral.refEarned || 0);
  const withdrawMin = 100;
  const withdrawMissing = Math.max(0, withdrawMin - refBalance);
  const withdrawProgress = Math.max(0, Math.min(100, (refBalance / withdrawMin) * 100));
  const withdrawAmountNum = parseReferralAmount(withdrawAmount);
  const withdrawWalletValue = withdrawWallet.trim();
  const withdrawWalletOk = MINIAPP_TRC20_RE.test(withdrawWalletValue);
  const canWithdraw = refBalance >= withdrawMin && withdrawAmountNum >= withdrawMin && withdrawAmountNum <= refBalance && withdrawWalletOk && !withdrawing;
  const buyBasePct = Number(profile.commission_pct || app.publicState?.config?.commission_settings?.buy_pct || 0);
  const vipDiscountPct = Number(vip.commission_discount_pct ?? profile.commission_discount_pct ?? 0);
  const buyAfterVipPct = buyBasePct * Math.max(0, 1 - vipDiscountPct / 100);
  const buyEffectivePct = referral.hasFirstOrderDiscount ? buyAfterVipPct * 0.5 : buyAfterVipPct;
  const vipName = vip.name || profile.vip_name || (Number(vip.level || profile.vip_level || 0) > 0 ? `VIP ${vip.level || profile.vip_level}` : "Standard");
  const withdrawHint = refBalance < withdrawMin
    ? `Вывод откроется после накопления ${window.MBEX.fmtUsdt(withdrawMin)} USDT.`
    : withdrawAmountNum > refBalance
      ? "Сумма больше доступного баланса."
      : withdrawAmountNum > 0 && withdrawAmountNum < withdrawMin
        ? "Минимальная сумма вывода — 100 USDT."
        : withdrawWalletValue && !withdrawWalletOk
          ? "Укажите корректный TRC-20 адрес: T + 33 символа."
          : "Заявка уйдёт оператору, статус появится в истории выводов.";
  const historyTabs = [
    { id: "accruals", label: "Начисления", count: accruals.length },
    { id: "friends", label: "Друзья", count: referrals.length },
    { id: "withdrawals", label: "Выводы", count: withdrawals.length },
  ];

  React.useEffect(() => {
    if (!withdrawWallet && wallets[0]) {
      setWithdrawWallet(wallets[0].address);
      setSelectedWalletId(wallets[0].id);
    }
  }, [wallets, withdrawWallet]);

  async function handleShare() {
    await shareReferralLink(app, deepLink);
  }

  async function handleCopyCode() {
    if (!referral.refCode) {
      app.pushToast("Код ещё не загрузился", "error");
      return;
    }
    const copied = await window.MBEX.copyText(referral.refCode);
    app.pushToast(copied ? "Код скопирован" : "Не удалось скопировать", copied ? "success" : "error");
  }

  async function handleApply() {
    if (!code.trim()) {
      app.pushToast("Введите реферальный код", "error");
      return;
    }
    setApplying(true);
    try {
      await app.applyReferralCode(code.trim().toUpperCase());
      setCode("");
    } catch (error) {
      // toast handled by bridge
    } finally {
      setApplying(false);
    }
  }

  async function handleWithdraw() {
    if (withdrawAmountNum < withdrawMin) {
      app.pushToast("Минимальная сумма вывода — 100 USDT", "error");
      return;
    }
    if (withdrawAmountNum > refBalance) {
      app.pushToast("Недостаточно реферального баланса", "error");
      return;
    }
    if (!withdrawWalletOk) {
      app.pushToast("Укажите корректный TRC-20 адрес", "error");
      return;
    }
    setWithdrawing(true);
    try {
      await app.withdrawReferral(withdrawAmountNum, withdrawWalletValue);
      setWithdrawAmount("");
    } catch (error) {
      // toast handled by bridge
    } finally {
      setWithdrawing(false);
    }
  }

  function selectWallet(wallet) {
    setSelectedWalletId(wallet.id);
    setWithdrawWallet(wallet.address || "");
  }

  function historyContent() {
    if (historyTab === "accruals" && accruals.length) {
      return (
        <div className="ref-list">
          {accruals.slice(0, 8).map((item) => (
            <div key={item.id} className="ref-list-row">
              <div>
                <strong>{referralPersonName(item)}</strong>
                <span>{window.MBEX.formatDateTime(item.created_at)}</span>
              </div>
              <em className="num">+{window.MBEX.fmtUsdt(item.bonus_usdt)} USDT</em>
            </div>
          ))}
        </div>
      );
    }
    if (historyTab === "friends" && referrals.length) {
      return (
        <div className="ref-list">
          {referrals.slice(0, 8).map((item) => (
            <div key={item.tg_id || item.referred_tg_id} className="ref-list-row">
              <div>
                <strong>{referralPersonName(item)}</strong>
                <span>{Number(item.order_count || 0)} заявок · {window.MBEX.formatDateTime(item.created_at)}</span>
              </div>
              <em className="num">{window.MBEX.fmtUsdt(item.earned_usdt)} USDT</em>
            </div>
          ))}
        </div>
      );
    }
    if (historyTab === "withdrawals" && withdrawals.length) {
      return (
        <div className="ref-list">
          {withdrawals.map((item) => (
            <div key={item.id} className="ref-list-row">
              <div>
                <strong>#{item.id} · {referralStatusText(item.status)}</strong>
                <span className="ref-withdrawal-meta wallet-address-full">
                  {item.wallet || item.address || ""} · {window.MBEX.formatDateTime(item.created_at)}
                </span>
              </div>
              <em className="num">{window.MBEX.fmtUsdt(item.amount || item.amount_usdt)} USDT</em>
            </div>
          ))}
        </div>
      );
    }
    const empty = {
      accruals: ["Начислений пока нет", "Появятся после первого обмена приглашённого друга."],
      friends: ["Друзей пока нет", "Поделитесь ссылкой — приглашённые появятся здесь."],
      withdrawals: ["Выводов пока нет", "История появится после первого запроса на вывод."],
    }[historyTab];
    return (
      <div className="ref-history-empty">
        <strong>{empty[0]}</strong>
        <p>{empty[1]}</p>
      </div>
    );
  }

  return (
    <div className="body referral-screen">
      <div className="referral-stack screen-enter">
        <section className="ref-program-card">
          <h2>
            Другу — −{referral.firstOrderDiscountPct || 50}% на первую<br />
            сделку, вам — {referral.commissionSharePct || 35}% с<br />
            его комиссии
          </h2>
          <p>
            Скидка срабатывает на первом обмене друга.<br />
            Ваши {referral.commissionSharePct || 35}% начисляются в USDT после каждого<br />
            его обмена.
          </p>
          <button type="button" className="ref-share-btn" onClick={handleShare}>Поделиться ссылкой</button>
          <div className="ref-code-row">
            <span>Код {referral.refCode || "—"}</span>
            <button type="button" onClick={handleCopyCode}>Скопировать</button>
          </div>
        </section>

        <section className="ref-balance-card">
          <div className="ref-balance-grid">
            <div>
              <span>Доступно к выводу</span>
              <strong className="num">{window.MBEX.fmtUsdt(refBalance)} USDT</strong>
            </div>
            <div>
              <span>Всего заработано</span>
              <strong className="num">{window.MBEX.fmtUsdt(refEarned)} USDT</strong>
            </div>
          </div>
          <div className="ref-withdraw-progress" aria-label={`Прогресс до вывода ${withdrawProgress.toFixed(1)}%`}>
            {withdrawProgress > 0 ? <span style={{ width: `${withdrawProgress}%` }} /> : null}
          </div>
          <div className="ref-withdraw-status">
            <p>
              {refBalance < withdrawMin ? (
                <>Вывод открывается с {window.MBEX.fmtUsdt(withdrawMin)} USDT — не хватает <strong className="num">{window.MBEX.fmtUsdt(withdrawMissing)} USDT</strong>.</>
              ) : "Вывод доступен — выберите сумму и кошелёк."}
            </p>
            {refBalance >= withdrawMin ? (
              <button type="button" onClick={() => setShowWithdrawForm((value) => !value)}>
                {showWithdrawForm ? "Скрыть" : "Вывести"}
              </button>
            ) : null}
          </div>
        </section>

        {showWithdrawForm ? (
          <section className="card card-pad stack-sm ref-withdraw-card">
            <div className="section-headline">
              <span>Вывод USDT</span>
              <em className="num">{window.MBEX.fmtUsdt(refBalance)} USDT</em>
            </div>
            <input
              className="field num"
              placeholder="Сумма USDT"
              value={withdrawAmount}
              onChange={(event) => setWithdrawAmount(event.target.value.replace(/[^\d.,]/g, ""))}
            />
            <input
              className="field num"
              placeholder="TRC-20 кошелёк"
              value={withdrawWallet}
              onChange={(event) => {
                setWithdrawWallet(event.target.value);
                setSelectedWalletId(null);
              }}
            />
            {wallets.length ? (
              <div className="ref-wallet-picker">
                {wallets.slice(0, 5).map((wallet) => (
                  <button
                    key={wallet.id}
                    type="button"
                    className={selectedWalletId === wallet.id ? "is-active" : ""}
                    onClick={() => selectWallet(wallet)}
                  >
                    <strong>{wallet.name || "Кошелёк"}</strong>
                    <span className="num wallet-address-full">{wallet.address}</span>
                  </button>
                ))}
              </div>
            ) : (
              <div className="status-note">
                Сохранённых кошельков нет. Можно ввести адрес вручную или добавить его в профиле.
              </div>
            )}
            {nav ? (
              <button type="button" className="btn-link saved-manage-link" onClick={() => nav("wallets")}>
                Управлять кошельками
              </button>
            ) : null}
            <button className="btn btn-primary btn-sm" disabled={!canWithdraw} onClick={handleWithdraw}>
              {withdrawing ? "Создаём заявку..." : "Вывести баланс"}
            </button>
            <div className={`status-note ${withdrawWalletValue && !withdrawWalletOk ? "error" : ""}`}>{withdrawHint}</div>
          </section>
        ) : null}

        <section className="ref-people-card">
          <div>
            <span>Приглашено</span>
            <strong className="num">{referral.refCount || 0}</strong>
          </div>
          <div>
            <span>Активных за 30 дней</span>
            <strong className="num">{referral.activeReferrals || 0}</strong>
          </div>
        </section>

        <section className="ref-history-card">
          <div className="ref-history-tabs" role="tablist" aria-label="История реферальной программы">
            {historyTabs.map((tab) => (
              <button
                key={tab.id}
                type="button"
                role="tab"
                aria-selected={historyTab === tab.id}
                className={historyTab === tab.id ? "is-active" : ""}
                onClick={() => setHistoryTab(tab.id)}
              >
                {tab.label} <span className="num">{tab.count}</span>
              </button>
            ))}
          </div>
          <div className="ref-history-body" role="tabpanel">{historyContent()}</div>
        </section>

        <section className="ref-menu-card">
          <button type="button" onClick={() => nav && nav("loyalty")}>
            <strong>Уровень лояльности</strong>
            <span>{vipName} · {formatLoyaltyPct(buyEffectivePct)} <Icons.chevR size={14} /></span>
          </button>
          <button type="button" onClick={() => nav && nav("wallets")}>
            <strong>Кошельки TRC-20</strong>
            <span>{wallets.length} <Icons.chevR size={14} /></span>
          </button>
        </section>

        {referral.canApplyReferral ? (
          <section className="ref-apply-card">
            <button type="button" className="ref-apply-toggle" onClick={() => setShowApplyForm((value) => !value)}>
              <span>Есть код друга?</span>
              <strong>{showApplyForm ? "Скрыть" : "Ввести код"}</strong>
            </button>
            {showApplyForm ? (
              <div className="ref-apply-form">
                <input
                  className="field"
                  placeholder="Введите код"
                  value={code}
                  onChange={(event) => setCode(event.target.value.toUpperCase())}
                />
                <button className="btn btn-soft btn-sm" disabled={applying || !code.trim()} onClick={handleApply}>
                  {applying ? "Применяем..." : "Применить код"}
                </button>
              </div>
            ) : null}
          </section>
        ) : null}
      </div>
    </div>
  );
}

function LoyaltyScreen({ app }) {
  const profile = app.privateState.profile || {};
  const referral = app.privateState.referral || {};
  const vip = referral.vip || {};
  const totalUsdt = Number(vip.total_usdt ?? profile.vip_total_usdt ?? profile.total_usdt ?? 0);
  const nextTier = Number(vip.next_tier ?? profile.next_tier ?? 0);
  const vipLevel = Number(vip.level ?? profile.vip_level ?? 0);
  const vipName = vip.name || profile.vip_name || (vipLevel > 0 ? `VIP ${vipLevel}` : "Standard");
  const vipDiscountPct = Number(vip.commission_discount_pct ?? profile.commission_discount_pct ?? 0);
  const configBuyPct = Number(app.publicState?.config?.commission_settings?.buy_pct || 0);
  const buyBasePct = Number(profile.commission_pct || configBuyPct || Number(vip.commission_rate || 0) * 100);
  const buyAfterVipPct = buyBasePct * Math.max(0, 1 - vipDiscountPct / 100);
  const hasReferralDiscount = Boolean(referral.hasFirstOrderDiscount);
  const buyEffectivePct = hasReferralDiscount ? buyAfterVipPct * 0.5 : buyAfterVipPct;
  const sellEffectivePct = Number(
    profile.sell_commission_pct || app.publicState?.config?.commission_settings?.sell_pct || 0
  );
  const remaining = nextTier > 0 ? Math.max(0, nextTier - totalUsdt) : 0;
  const progress = nextTier > 0 ? Math.max(0, Math.min(100, (totalUsdt / nextTier) * 100)) : 100;
  const vipTiers = Array.isArray(referral.vipTiers) ? referral.vipTiers : [];
  const currentTierIndex = vipTiers.findIndex((tier) => Number(tier.level) === vipLevel);
  const levelPosition = currentTierIndex >= 0 ? currentTierIndex + 1 : Math.max(1, vipLevel + 1);
  const levelCount = Math.max(vipTiers.length, levelPosition);
  const nextTierData = vipTiers.find((tier) => Number(tier.minUsdt) === nextTier)
    || vipTiers.find((tier) => Number(tier.minUsdt) > totalUsdt)
    || null;
  const nextTierName = nextTierData?.name || "следующего уровня";
  const nextTierCommissionPct = nextTierData
    ? buyBasePct * Math.max(0, 1 - Number(nextTierData.commissionDiscountPct || 0) / 100)
    : buyAfterVipPct;
  const deepLink = referralDeepLink(referral, app.botUrl);
  const displayLink = referral.refCode ? `mbex.pro/r/${referral.refCode}` : "Ссылка появится после загрузки";
  const commissionSharePct = Number(referral.commissionSharePct || 35);
  const firstOrderDiscountPct = Number(referral.firstOrderDiscountPct || 50);
  const [showAllTiers, setShowAllTiers] = React.useState(false);
  const previewStart = currentTierIndex < 2
    ? 0
    : Math.min(Math.max(0, currentTierIndex - 1), Math.max(0, vipTiers.length - 3));
  const visibleTiers = showAllTiers ? vipTiers : vipTiers.slice(previewStart, previewStart + 3);

  async function handleShare() {
    await shareReferralLink(app, deepLink);
  }

  function tierSubtitle(tier, index) {
    const next = vipTiers[index + 1];
    if (Number(tier.level) === 0 && next) {
      return `оборот до ${formatLoyaltyUsdt(next.minUsdt)} USDT`;
    }
    return `от ${formatLoyaltyUsdt(tier.minUsdt)} USDT за 30 дней`;
  }

  return (
    <div className="body loyalty-screen">
      <div className="loyalty-stack screen-enter">
        <section className="loyalty-hero-card">
          <div className="loyalty-hero-head">
            <div>
              <span className="loyalty-kicker">Ваш уровень</span>
              <strong className="loyalty-level-name">{vipName}</strong>
            </div>
            <span className="loyalty-level-count num">{levelPosition} из {levelCount}</span>
          </div>
          <div className="loyalty-commission-grid">
            <div>
              <span>Комиссия покупки</span>
              <strong className="num">{formatLoyaltyPct(buyEffectivePct)}</strong>
            </div>
            <div>
              <span>Комиссия продажи</span>
              <strong className="num">{formatLoyaltyPct(sellEffectivePct)}</strong>
            </div>
          </div>
          <p>
            {vipDiscountPct > 0
              ? `На уровне ${vipName} комиссия покупки ниже базовой на ${vipDiscountPct}%.`
              : `На Standard скидки нет: комиссия покупки равна базовой ${formatLoyaltyPct(buyBasePct)}.`}
            {hasReferralDiscount ? ` Для первой заявки действует дополнительная скидка ${firstOrderDiscountPct}%.` : ""}
          </p>
        </section>

        <section className="loyalty-progress-card">
          <div className="loyalty-progress-head">
            <strong>{nextTier > 0 ? `До уровня ${nextTierName}` : "Максимальный уровень"}</strong>
            <span className="num">
              {formatLoyaltyUsdt(totalUsdt)}{nextTier > 0 ? ` / ${formatLoyaltyUsdt(nextTier)} USDT` : " USDT"}
            </span>
          </div>
          <div className="loyalty-progress" aria-label={`Прогресс уровня ${progress.toFixed(1)}%`}>
            <span style={{ width: `${progress}%` }} />
          </div>
          <p>
            {nextTier > 0 ? (
              <>
                Ещё <strong className="num">{formatLoyaltyUsdt(remaining)} USDT</strong> оборота за 30 дней — и комиссия покупки станет <strong className="num">{formatLoyaltyPct(nextTierCommissionPct)}</strong>.
              </>
            ) : "У вас максимальный уровень и минимальная доступная комиссия покупки."}
          </p>
        </section>

        <section className="loyalty-tiers-section">
          <div className="loyalty-tiers-head">
            <h2>Уровни и комиссии</h2>
            {vipTiers.length > 3 ? (
              <button type="button" className="loyalty-tiers-toggle" onClick={() => setShowAllTiers((value) => !value)}>
                {showAllTiers ? "Свернуть" : `Все ${vipTiers.length}`}
              </button>
            ) : null}
          </div>
          <div className="loyalty-tiers-card">
            {visibleTiers.length ? visibleTiers.map((tier) => {
              const tierIndex = vipTiers.indexOf(tier);
              const isCurrent = Number(tier.level) === vipLevel;
              const tierCommissionPct = buyBasePct * Math.max(
                0,
                1 - Number(tier.commissionDiscountPct || 0) / 100
              );
              return (
                <div key={`${tier.level}:${tier.name}`} className={`loyalty-tier-row${isCurrent ? " is-current" : ""}`}>
                  <div>
                    <strong>{tier.name || `Уровень ${Number(tier.level) + 1}`}</strong>
                    <span>{tierSubtitle(tier, tierIndex)}</span>
                  </div>
                  <div className="loyalty-tier-tail">
                    {isCurrent ? <em>Сейчас</em> : null}
                    <strong className="num">{formatLoyaltyPct(tierCommissionPct)}</strong>
                  </div>
                </div>
              );
            }) : (
              <div className="loyalty-tier-row is-current">
                <div>
                  <strong>{vipName}</strong>
                  <span>Текущий уровень</span>
                </div>
                <div className="loyalty-tier-tail">
                  <em>Сейчас</em>
                  <strong className="num">{formatLoyaltyPct(buyAfterVipPct)}</strong>
                </div>
              </div>
            )}
          </div>
        </section>

        <section className="loyalty-referral-card">
          <h2>Приводите друзей — вам {commissionSharePct}% с комиссии каждого обмена</h2>
          <p>
            Начисляем в USDT после каждой завершённой заявки друга. Друг получает скидку {firstOrderDiscountPct}% на первую комиссию.
          </p>
          <div className="loyalty-referral-action">
            <span>{displayLink}</span>
            <button type="button" onClick={handleShare}>Пригласить</button>
          </div>
        </section>

        <p className="loyalty-disclaimer">
          Скидка уровня и реферальные начисления не уменьшают комиссию продажи — она считается по правилам сервера.
        </p>
      </div>
    </div>
  );
}

function SupportScreen({ app }) {
  const links = app.supportLinks || [];
  const openSupport = () => window.MBEX.openTelegramUrl(app.supportUrl);
  const openLink = (item) => {
    if (item.kind === "telegram") {
      window.MBEX.openTelegramUrl(item.url);
      return;
    }
    window.MBEX.openExternalUrl(item.url);
  };

  return (
    <div className="body">
      <div className="stack screen-enter info-screen">
        <div className="card card-pad info-hero-card">
          <div className="info-hero-icon">
            <Icons.support size={28} />
          </div>
          <div>
            <div className="eyebrow">Support</div>
            <div className="h2">Поддержка MBEX</div>
            <p>
              Напишите оператору, если нужна помощь по заявке, депозиту,
              кошельку, верификации или возврату.
            </p>
          </div>
          <button className="btn btn-primary btn-sm" onClick={openSupport}>
            <Icons.support size={18} />
            Написать в поддержку
          </button>
        </div>

        <div className="status-note">
          По активной заявке приложите код заявки и коротко опишите ситуацию.
          Полные seed-фразы, приватные ключи и пароли поддержка не запрашивает.
        </div>

        <div className="card info-link-card">
          {links.map((item) => (
            <Row
              key={item.url}
              icon={<Icons.globe size={19} />}
              accent={item.kind === "telegram"}
              title={item.label}
              sub={item.sub || item.url.replace(/^https?:\/\//, "")}
              onClick={() => openLink(item)}
            />
          ))}
        </div>

        <div className="card card-pad stack-sm">
          <div className="section-headline">
            <span>Что подготовить</span>
          </div>
          <InfoBullet icon={<Icons.doc size={18} />} title="Заявка" text="Номер заявки, направление и сумма ускоряют проверку." />
          <InfoBullet icon={<Icons.wallet size={18} />} title="Кошелёк" text="Для TRC-20 вопросов укажите только публичный адрес или tx hash." />
          <InfoBullet icon={<Icons.info size={18} />} title="Возвраты" text="Если депозит попал на ручную проверку, оператор подскажет следующий шаг." />
        </div>
      </div>
    </div>
  );
}

function OfficesScreen({ app }) {
  const offices = app.offices || [];
  const openSupport = () => window.MBEX.openTelegramUrl(app.supportUrl);

  return (
    <div className="body">
      <div className="stack screen-enter info-screen">
        <div className="status-note">
          Адреса и материалы взяты из текущего Mini App. Перед визитом уточните
          детали и доступность оператора в поддержке.
        </div>

        {offices.map((office) => (
          <div key={office.city} className="card card-pad office-card">
            <div className="office-head">
              <div className="row-ic accent">
                <Icons.pin size={20} />
              </div>
              <div>
                <div className="eyebrow">Office</div>
                <div className="h2">{office.city}</div>
                <p>{office.addr}</p>
                {office.details ? <p>{office.details}</p> : null}
              </div>
            </div>

            <div className="office-meta-grid">
              <div>
                <span>Режим работы</span>
                <strong>{office.hours}</strong>
              </div>
              <div>
                <span>Визит</span>
                <strong>По согласованию</strong>
              </div>
            </div>

            {office.photos && office.photos.length ? (
              <div className="office-photo-strip" aria-label="Фото офиса">
                {office.photos.map((photo) => (
                  <img key={photo.src} src={photo.src} alt={photo.alt} loading="lazy" />
                ))}
              </div>
            ) : null}

            <div className="office-actions">
              <button className="btn btn-soft btn-sm" onClick={() => window.MBEX.openExternalUrl(office.mapUrl)}>
                <Icons.pin size={17} />
                Карта
              </button>
              {office.videoUrl ? (
                <button className="btn btn-ghost btn-sm" onClick={() => window.MBEX.openExternalUrl(office.videoUrl)}>
                  <Icons.eye size={17} />
                  Как найти
                </button>
              ) : null}
              <button className="btn btn-ghost btn-sm" onClick={openSupport}>
                <Icons.support size={17} />
                Поддержка
              </button>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function AmlScreen({ app }) {
  const profile = app.privateState.profile || {};
  const kycVerified = Boolean(profile.verified);
  const items = [
    {
      icon: <Icons.user size={18} />,
      title: "KYC — идентификация клиента",
      text: "Верификация может потребоваться для лимитов, спорных операций и соблюдения правил обмена.",
    },
    {
      icon: <Icons.arrowUp size={18} />,
      title: "Продажа: проверка депозита",
      text: "Когда USDT поступают на депозитный адрес, сервер проверяет TRC-20 транзакцию до выдачи RUB.",
    },
    {
      icon: <Icons.arrowDown size={18} />,
      title: "Покупка: проверка кошелька",
      text: "Перед отправкой USDT операторский сервер проверяет адрес получателя. При ожидании или отказе отправка блокируется до решения.",
    },
    {
      icon: <Icons.shield size={18} />,
      title: "AML / KYT статусы",
      text: "Ожидание означает, что результат ещё не получен; отказ или ошибка требуют ручного разбора. Для проблемного депозита продажи доступно обращение на возврат.",
    },
  ];

  return (
    <div className="body">
      <div className="stack screen-enter info-screen">
        <div className="card card-pad info-hero-card aml-hero-card">
          <div className="info-hero-icon">
            <Icons.shield size={28} />
          </div>
          <div>
            <div className="eyebrow">Compliance</div>
            <div className="h2">AML / KYC / KYT</div>
            <p>
              Кратко о проверках, которые защищают клиента и обменный процесс.
            </p>
          </div>
          <div className="info-status-pill">
            <Pill cls={kycVerified ? "pill-pos" : "pill-muted"} dot={kycVerified ? "var(--pos)" : ""}>
              {kycVerified ? "KYC пройден" : "KYC не пройден"}
            </Pill>
          </div>
        </div>

        <div className="card info-policy-card">
          {items.map((item) => (
            <InfoBullet key={item.title} icon={item.icon} title={item.title} text={item.text} />
          ))}
        </div>

        <div className="status-note warn">
          Мы не показываем клиенту внутренние provider details и raw-проверки.
          Если заявка ушла на ручной разбор, решение и дальнейшие действия
          подтверждает оператор.
        </div>

        <button className="btn btn-primary" onClick={() => window.MBEX.openTelegramUrl(app.supportUrl)}>
          <Icons.support size={18} />
          Задать вопрос по проверке
        </button>
      </div>
    </div>
  );
}

function InfoBullet({ icon, title, text }) {
  return (
    <div className="info-bullet">
      <div className="info-bullet-icon">{icon}</div>
      <div>
        <strong>{title}</strong>
        <span>{text}</span>
      </div>
    </div>
  );
}

window.HistoryScreen = HistoryScreen;
window.ProfileScreen = ProfileScreen;
window.WalletsScreen = WalletsScreen;
window.CouriersScreen = CouriersScreen;
window.ReferralScreen = ReferralScreen;
window.LoyaltyScreen = LoyaltyScreen;
window.SupportScreen = SupportScreen;
window.OfficesScreen = OfficesScreen;
window.AmlScreen = AmlScreen;
