// lib.jsx — общие хелперы и UI-примитивы мобильного пульта.
(() => {
  const { useState, useEffect, useRef, useCallback } = React;

  // ── Форматирование ───────────────────────────────────────
  function fmtMoney(n) {
    const v = Number(n || 0);
    return v.toLocaleString('ru-RU', { maximumFractionDigits: 0 }) + ' ₽';
  }
  function fmtDate(iso) {
    if (!iso) return '';
    const d = new Date(iso);
    if (isNaN(d)) return '';
    return d.toLocaleDateString('ru-RU', { day: '2-digit', month: 'short' });
  }
  function fmtDateFull(iso) {
    if (!iso) return '';
    const d = new Date(iso);
    if (isNaN(d)) return '';
    return d.toLocaleDateString('ru-RU', { day: '2-digit', month: 'long', year: 'numeric' });
  }
  function fmtAgo(iso) {
    if (!iso) return '';
    const diff = (Date.now() - new Date(iso).getTime()) / 1000;
    if (diff < 60) return 'только что';
    if (diff < 3600) return Math.floor(diff / 60) + ' мин назад';
    if (diff < 86400) return Math.floor(diff / 3600) + ' ч назад';
    const days = Math.floor(diff / 86400);
    if (days === 1) return 'вчера';
    if (days < 7) return days + ' дн назад';
    return fmtDate(iso);
  }
  function initials(name) {
    if (!name) return '?';
    const parts = String(name).trim().split(/\s+/);
    return ((parts[0]?.[0] || '') + (parts[1]?.[0] || '')).toUpperCase() || '?';
  }
  function clientName(c) {
    if (!c) return '';
    return c.full_name || c.fio
      || [c.last_name, c.first_name, c.middle_name].filter(Boolean).join(' ').trim();
  }
  function firstPhone(c) {
    if (!c) return null;
    if (Array.isArray(c.phones)) return c.phones.find(Boolean) || null;
    return c.phone || null;
  }
  function telHref(phone) {
    if (!phone) return null;
    const digits = String(phone).replace(/[^\d+]/g, '');
    return 'tel:' + digits;
  }

  window.M = { fmtMoney, fmtDate, fmtDateFull, fmtAgo, initials, clientName, firstPhone, telHref };

  // ── Avatar ───────────────────────────────────────────────
  window.Avatar = function Avatar({ name, src, size }) {
    const st = size ? { width: size, height: size, fontSize: Math.round(size * 0.38) } : null;
    return (
      <div className="avatar" style={st}>
        {src ? <img src={src} alt="" /> : initials(name)}
      </div>
    );
  };

  // ── Spinner ──────────────────────────────────────────────
  window.Spinner = function Spinner() { return <div className="spinner" />; };

  // ── Toast (pub-sub) ──────────────────────────────────────
  const listeners = new Set();
  window.toast = function toast(msg, type) {
    listeners.forEach((fn) => fn({ id: Date.now() + Math.random(), msg, type }));
  };
  window.ToastHost = function ToastHost() {
    const [items, setItems] = useState([]);
    useEffect(() => {
      const fn = (t) => {
        setItems((prev) => [...prev, t]);
        setTimeout(() => setItems((prev) => prev.filter((x) => x.id !== t.id)), 2600);
      };
      listeners.add(fn);
      return () => listeners.delete(fn);
    }, []);
    return (
      <div className="toast-wrap">
        {items.map((t) => (
          <div key={t.id} className={'toast' + (t.type ? ' ' + t.type : '')}>{t.msg}</div>
        ))}
      </div>
    );
  };

  // ── Sheet (нижняя модалка) ───────────────────────────────
  // props: title, onClose, footer, children, wide
  window.Sheet = function Sheet({ title, onClose, footer, children }) {
    useEffect(() => {
      const onKey = (e) => { if (e.key === 'Escape') onClose && onClose(); };
      document.addEventListener('keydown', onKey);
      document.body.style.overflow = 'hidden';
      return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
    }, []);
    return (
      <div className="sheet-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose && onClose(); }}>
        <div className="sheet" role="dialog" aria-modal="true">
          <div className="sheet-grip" />
          <div className="sheet-head">
            <div className="sheet-title">{title}</div>
            <button className="sheet-close" onClick={onClose} aria-label="Закрыть">
              <Icon name="x" size={18} />
            </button>
          </div>
          <div className="sheet-body">{children}</div>
          {footer && <div className="sheet-foot">{footer}</div>}
        </div>
      </div>
    );
  };

  // ── Confirm-хелпер на базе Sheet ─────────────────────────
  // useConfirm() → [confirmNode, askConfirm(opts)] ; askConfirm возвращает Promise<bool>
  window.useConfirm = function useConfirm() {
    const [cfg, setCfg] = useState(null);
    const resolver = useRef(null);
    const ask = useCallback((opts) => new Promise((resolve) => {
      resolver.current = resolve;
      setCfg(opts || {});
    }), []);
    const done = (val) => { setCfg(null); resolver.current && resolver.current(val); resolver.current = null; };
    const node = cfg ? (
      <Sheet title={cfg.title || 'Подтверждение'} onClose={() => done(false)}
        footer={<>
          <button className="btn btn-ghost" onClick={() => done(false)}>{cfg.cancel || 'Отмена'}</button>
          <button className={'btn ' + (cfg.danger ? 'btn-danger' : 'btn-primary')} onClick={() => done(true)}>
            {cfg.ok || 'Подтвердить'}
          </button>
        </>}>
        <div style={{ padding: '4px 0 8px', color: 'var(--text-2)' }}>{cfg.message}</div>
      </Sheet>
    ) : null;
    return [node, ask];
  };

  // ── useAsync: загрузка с loading/error/reload ────────────
  window.useAsync = function useAsync(fn, deps) {
    const [state, setState] = useState({ loading: true, data: null, error: null });
    const tick = useRef(0);
    const reload = useCallback(() => {
      const my = ++tick.current;
      setState((s) => ({ ...s, loading: true, error: null }));
      Promise.resolve().then(fn).then(
        (data) => { if (my === tick.current) setState({ loading: false, data, error: null }); },
        (err) => { if (my === tick.current) setState({ loading: false, data: null, error: err.message || 'Ошибка' }); }
      );
    }, deps || []);
    useEffect(() => { reload(); }, [reload]);
    return { ...state, reload, setData: (d) => setState((s) => ({ ...s, data: d })) };
  };
})();
