/* ============================================================
   ui.jsx — shared primitives. Exports to window for screens.jsx
   ============================================================ */
const { useState, useEffect, useRef } = React;

/* ---------- icons (Lucide-style 1.5 stroke, per DS substitution note) ---------- */
const I = {
  refresh: (p) => <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>,
  back: (p) => <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m15 18-6-6 6-6"/></svg>,
  chevR: (p) => <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m9 18 6-6-6-6"/></svg>,
  search: (p) => <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>,
  x: (p) => <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M18 6 6 18M6 6l12 12"/></svg>,
  sliders: (p) => <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg>,
  alert: (p) => <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3Z"/><path d="M12 9v4M12 17h.01"/></svg>,
  lock: (p) => <svg viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>,
  // tabs
  grid: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="3" width="7" height="9" rx="1.5"/><rect x="14" y="3" width="7" height="5" rx="1.5"/><rect x="14" y="12" width="7" height="9" rx="1.5"/><rect x="3" y="16" width="7" height="5" rx="1.5"/></svg>,
  list: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="3.5" cy="6" r="1.2" fill="currentColor" stroke="none"/><circle cx="3.5" cy="12" r="1.2" fill="currentColor" stroke="none"/><circle cx="3.5" cy="18" r="1.2" fill="currentColor" stroke="none"/></svg>,
  repeat: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m17 2 4 4-4 4"/><path d="M3 11v-1a4 4 0 0 1 4-4h14"/><path d="m7 22-4-4 4-4"/><path d="M21 13v1a4 4 0 0 1-4 4H3"/></svg>,
  menu: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="9"/><path d="M8 12h8M12 8v8" opacity="0"/><circle cx="12" cy="9" r="3"/><path d="M6.5 18.5a6 6 0 0 1 11 0"/></svg>,
  user: (p) => <svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="8" r="4"/><path d="M5.5 21a6.5 6.5 0 0 1 13 0"/></svg>,
  bell: (p) => <svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg>,
  info: (p) => <svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="9"/><path d="M12 16v-4M12 8h.01"/></svg>,
  out: (p) => <svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="m16 17 5-5-5-5"/><path d="M21 12H9"/></svg>,
  wifiOff: (p) => <svg viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M2 2l20 20"/><path d="M8.5 16.5a5 5 0 0 1 7 0"/><path d="M2 8.8a16 16 0 0 1 4.2-2.7"/><path d="M10.7 5a16 16 0 0 1 11.3 3.8"/><path d="M5 12.5a11 11 0 0 1 3.4-2"/><path d="M14 9.2a11 11 0 0 1 5 2.8"/><path d="M12 20h.01"/></svg>,
};

const STAR_D = "M 164 30 C 164 18, 176 18, 176 30 C 172 100, 236 88, 284 100 C 236 112, 172 100, 176 170 C 176 182, 164 182, 164 170 C 168 100, 104 112, 56 100 C 104 88, 168 100, 164 30 Z";
const Star = ({ className, style }) => (
  <svg className={className} style={style} viewBox="0 0 300 200"><path d={STAR_D} vectorEffect="non-scaling-stroke" /></svg>
);

/* ---------- status bar ---------- */
const StatusBar = () => (
  <div className="statusbar">
    <span>9:41</span>
    <div className="statusbar__right statusbar__icns">
      <svg width="17" height="11" viewBox="0 0 17 11" fill="currentColor"><rect x="0" y="7" width="3" height="4" rx="1"/><rect x="4.5" y="5" width="3" height="6" rx="1"/><rect x="9" y="2.5" width="3" height="8.5" rx="1"/><rect x="13.5" y="0" width="3" height="11" rx="1"/></svg>
      <svg width="16" height="11" viewBox="0 0 16 11" fill="currentColor"><path d="M8 2.2c2 0 3.8.8 5.2 2L14.5 3A9 9 0 0 0 8 .4 9 9 0 0 0 1.5 3l1.3 1.3A7.2 7.2 0 0 1 8 2.2Z"/><path d="M8 5.4c1.1 0 2.1.4 2.9 1.2l1.3-1.3A6 6 0 0 0 8 3.6a6 6 0 0 0-4.2 1.7l1.3 1.3A4 4 0 0 1 8 5.4Z"/><circle cx="8" cy="9" r="1.6"/></svg>
      <svg width="25" height="12" viewBox="0 0 25 12" fill="none"><rect x="1" y="1" width="20" height="10" rx="2.5" stroke="currentColor" strokeOpacity="0.4"/><rect x="2.5" y="2.5" width="16" height="7" rx="1.3" fill="currentColor"/><rect x="22.5" y="4" width="1.5" height="4" rx="0.7" fill="currentColor" fillOpacity="0.5"/></svg>
    </div>
  </div>
);

/* ---------- app bar (R7 refresh top-right) ---------- */
function AppBar({ title, brand, onBack, onRefresh }) {
  const [spin, setSpin] = useState(false);
  function refresh() {
    setSpin(true);
    if (onRefresh) onRefresh();
    setTimeout(() => setSpin(false), 850);
  }
  return (
    <div className="appbar">
      <div style={{ minWidth: 0, flex: '1 1 auto' }}>
        {onBack && <button className="appbar__back" onClick={onBack}>{I.back()}<span>Назад</span></button>}
        <h1 className="appbar__title">{title}</h1>
      </div>
      <button className={'refresh' + (spin ? ' is-spinning' : '')} onClick={refresh} aria-label="Обновить">{I.refresh()}</button>
    </div>
  );
}

/* ---------- footer freshness (R9) ---------- */
const Freshness = ({ stamp, stale, offline }) => {
  let text;
  if (offline) text = 'Нет сети · обновление недоступно';
  else if (stale) text = 'Данные могут быть устаревшими · ' + stamp;
  else text = 'Обновлено: ' + stamp;
  return (
    <div className={'freshness' + (stale || offline ? ' freshness--stale' : '')}>
      <span className="freshness__dot"></span><span>{text}</span>
    </div>
  );
};

/* ---------- bottom nav (DQ-1) ---------- */
function TabBar({ tab, onTab, notif }) {
  const tabs = [
    { id: 'dashboard', label: 'Дашборд', icon: I.grid },
    { id: 'events',    label: 'Мероприятия', icon: I.list },
    { id: 'subs',      label: 'Подписки', icon: I.repeat },
    { id: 'menu',      label: 'Меню', icon: I.menu },
  ];
  return (
    <nav className="tabbar">
      {tabs.map(t => (
        <button key={t.id} className={'tab' + (tab === t.id ? ' is-active' : '')} onClick={() => onTab(t.id)}>
          <span style={{ position: 'relative' }}>
            {t.icon({ width: 22, height: 22 })}
            {t.id === 'menu' && notif ? <span className="tab__badge">{notif}</span> : null}
          </span>
          {t.label}
        </button>
      ))}
    </nav>
  );
}

/* ---------- two-currency stack (DQ-4) ---------- */
function MoneyStack({ sums, small, showTags }) {
  const cls = small ? 'cur__amt cur__amt--sm' : 'cur__amt';
  return (
    <div className="cur-stack">
      <div className="cur cur--rub">
        <span className={cls}>{fmt(sums.rub)}</span><span className="cur__sym">₽</span>
        {showTags ? <span className="cur__tag">руб</span> : null}
      </div>
      {sums.eur != null && (
        <div className="cur cur--eur">
          <span className={cls}>{fmt(sums.eur)}</span><span className="cur__sym">€</span>
          {showTags ? <span className="cur__tag">евро</span> : null}
        </div>
      )}
    </div>
  );
}

/* ---------- delta (R17 · DQ-2 percent big + abs small · DQ-3 prev=0 → 0%) ---------- */
function Delta({ d }) {
  // d: {dir:'pos'|'neg', pct, abs, base} OR {na:true, base} OR {fromZero:true, abs, base} OR {bothZero:true, base}
  if (d.bothZero) {
    // R17 edge: оба периода считаются, оба = 0 — отличается от «нет базы»
    return (
      <div className="delta delta--na">
        <span className="delta__base">{d.base}</span>
        <div className="delta__main"><span className="delta__pct">—</span></div>
        <span className="delta__na-note">без активности · н/д</span>
      </div>
    );
  }
  if (d.na) {
    return (
      <div className="delta delta--na">
        <span className="delta__base">{d.base}</span>
        <div className="delta__main"><span className="delta__pct">—</span></div>
        <span className="delta__na-note">нет базы · н/д</span>
      </div>
    );
  }
  if (d.fromZero) { // DQ-3 v2: prev = 0, current > 0 → 0 (без специального бейджа)
    return (
      <div className="delta delta--na">
        <span className="delta__base">{d.base}</span>
        <div className="delta__main"><span className="delta__pct">0</span></div>
        <span className="delta__na-note">+{fmt(d.abs)} подп.</span>
      </div>
    );
  }
  const sign = d.dir === 'pos' ? '+' : '−';
  return (
    <div className={'delta delta--' + d.dir}>
      <span className="delta__base">{d.base}</span>
      <div className="delta__main">
        <span className="delta__pct">{sign}{Math.abs(d.pct)}%</span>
        <span className="delta__abs">{sign}{fmt(Math.abs(d.abs))} подп.</span>
      </div>
    </div>
  );
}

/* ---------- conclusion plate ---------- */
const Conclusion = ({ lead, children, neutral }) => (
  <div className={'conclusion' + (neutral ? ' conclusion--neutral' : '')}>
    <b>{lead}</b> {children}
  </div>
);

/* ---------- empty / loading / banner ---------- */
const EmptyState = ({ title, text }) => (
  <div className="empty">
    <Star className="empty__star" style={{ stroke: 'var(--ink-3)', opacity: .45 }} />
    <p className="empty__title">{title}</p>
    <p className="empty__text">{text}</p>
  </div>
);

const SkelCard = () => (
  <div className="card" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
    <div className="skel skel-line" style={{ width: '55%', height: 14 }}></div>
    <div className="skel skel-line" style={{ width: '35%' }}></div>
    <div className="skel" style={{ height: 46, marginTop: 6 }}></div>
    <div className="skel skel-line" style={{ width: '70%' }}></div>
  </div>
);

const Banner = ({ children, onRetry }) => (
  <div className="banner">
    {I.alert()}
    <div className="banner__txt">{children}{onRetry ? <span className="banner__act" onClick={onRetry}>Обновить ещё раз</span> : null}</div>
  </div>
);

/* ---------- offline state (NFR-6: отсутствие сети — не выдаём устаревшее за актуальное) ---------- */
function OfflineState({ onRetry }) {
  return (
    <div className="empty" style={{ paddingTop: 84 }}>
      <div style={{ width: 72, height: 72, borderRadius: '50%', background: 'rgba(224,166,89,.10)', border: '1px solid rgba(224,166,89,.30)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--amber)' }}>{I.wifiOff()}</div>
      <p className="empty__title" style={{ color: 'var(--ink)' }}>Нет сети</p>
      <p className="empty__text">Нет соединения с интернетом. Чтобы не вводить в заблуждение, цифры не показываем — они могли устареть.</p>
      <button className="show-more" style={{ maxWidth: 200, marginTop: 8 }} onClick={onRetry}>
        <span className="show-more__main">Повторить</span>
        <span className="show-more__count">проверить соединение</span>
      </button>
    </div>
  );
}

/* ---------- made in Integramma (показывается только в Меню) ---------- */
const MadeIn = () => (
  <div className="madein">
    made in{' '}<a href="https://integramma.ru" target="_blank" rel="noopener">Integramma</a>
  </div>
);

Object.assign(window, {
  I, Star, STAR_D, StatusBar, AppBar, Freshness, TabBar,
  MoneyStack, Delta, Conclusion, EmptyState, SkelCard, Banner, OfflineState, MadeIn,
});
