// ui.jsx — shared primitives. Class-based styling (see styles.css);
// no global `styles` object. Exports to window for other files.
const { useState, useRef, useEffect, useCallback, useContext, createContext } = React;

/* ---------- hooks ---------- */
function useOutside(ref, onClose) {
  useEffect(() => {
    function h(e){ if (ref.current && !ref.current.contains(e.target)) onClose(); }
    document.addEventListener('mousedown', h);
    return () => document.removeEventListener('mousedown', h);
  }, [onClose]);
}
function usePersist(key, initial) {
  const k = 'swo-portal-' + key;
  const [v, setV] = useState(() => {
    try { const s = localStorage.getItem(k); return s !== null ? JSON.parse(s) : initial; } catch { return initial; }
  });
  useEffect(() => { try { localStorage.setItem(k, JSON.stringify(v)); } catch {} }, [v]);
  return [v, setV];
}

/* ---------- toast ---------- */
const ToastContext = createContext(() => {});
function ToastProvider({ children }) {
  const [toasts, setToasts] = useState([]);
  const push = useCallback((msg, type = 'success') => {
    const id = Math.random().toString(36).slice(2);
    setToasts(t => [...t, { id, msg, type }]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 2800);
  }, []);
  const icon = { success:'bi-check-circle-fill', error:'bi-exclamation-circle-fill', info:'bi-info-circle-fill' };
  return (
    <ToastContext.Provider value={push}>
      {children}
      <div className="toast-wrap">
        {toasts.map(t => (
          <div key={t.id} className={'toast ' + t.type}>
            <i className={'bi ' + (icon[t.type] || icon.info)}></i><span>{t.msg}</span>
          </div>
        ))}
      </div>
    </ToastContext.Provider>
  );
}
function useToast(){ return useContext(ToastContext); }

/* ---------- avatar ---------- */
function Avatar({ name = '', size = 26, square, color }) {
  const initials = name.split(' ').filter(Boolean).slice(-2).map(w => w[0]).join('');
  return (
    <span className={'avatar' + (square ? ' sq' : '')}
      style={{ width:size, height:size, fontSize:Math.round(size*0.42), background:color || undefined }}>
      {initials}
    </span>
  );
}

/* ---------- placeholder image ---------- */
function PlaceholderImg({ label, className = '', style }) {
  return <div className={'ph-img ' + className} style={style}>{label && <span>{label}</span>}</div>;
}

/* ---------- popover ---------- */
function Popover({ button, children, align = 'left', width }) {
  const [open, setOpen] = useState(false);
  const ref = useRef();
  useOutside(ref, () => setOpen(false));
  const close = () => setOpen(false);
  return (
    <div ref={ref} style={{ position:'relative' }}>
      {button({ open, toggle:() => setOpen(o => !o), close })}
      {open && (
        <div className="pop" style={{ top:'calc(100% + 6px)', [align === 'right' ? 'right' : 'left']:0, width }}>
          {typeof children === 'function' ? children({ close }) : children}
        </div>
      )}
    </div>
  );
}

/* ---------- modal ---------- */
function Modal({ title, onClose, children, footer, width = 560 }) {
  useEffect(() => {
    const h = e => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [onClose]);
  return (
    <div className="modal-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth:width }}>
        <div className="modal-head">
          <h3>{title}</h3>
          <button className="iconbtn" onClick={onClose} aria-label="Close"><i className="bi bi-x-lg"></i></button>
        </div>
        <div className="modal-body">{children}</div>
        {footer && <div className="modal-foot">{footer}</div>}
      </div>
    </div>
  );
}

/* ---------- field / inputs ---------- */
function Field({ label, children, hint }) {
  return (
    <div className="field">
      {label && <label>{label}</label>}
      {children}
      {hint && <div className="subtle" style={{ fontSize:'var(--fs-sm)' }}>{hint}</div>}
    </div>
  );
}

function ChipInput({ value, onChange, suggestions = [], placeholder, listId }) {
  const [draft, setDraft] = useState('');
  const valid = s => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s);
  const add = (raw) => {
    const s = raw.trim().replace(/,$/, '');
    if (!s) return;
    if (!value.includes(s)) onChange([...value, s]);
    setDraft('');
  };
  return (
    <div className="chip-input">
      {value.map(v => (
        <span key={v} className={'chip' + (valid(v) ? '' : ' is-invalid')}>
          {v}<button onClick={() => onChange(value.filter(x => x !== v))}><i className="bi bi-x"></i></button>
        </span>
      ))}
      <input value={draft} placeholder={value.length ? '' : placeholder} list={listId}
        onChange={e => { const val = e.target.value; if (val.endsWith(',')) add(val); else setDraft(val); }}
        onKeyDown={e => { if (e.key === 'Enter' || e.key === ';') { e.preventDefault(); add(draft); }
          else if (e.key === 'Backspace' && !draft && value.length) onChange(value.slice(0, -1)); }}
        onBlur={() => add(draft)} />
      {listId && <datalist id={listId}>{suggestions.map(s => <option key={s} value={s} />)}</datalist>}
    </div>
  );
}

/* ---------- tabs / segmented ---------- */
function Tabs({ tabs, active, onChange }) {
  return (
    <div className="tabs">
      {tabs.map(t => (
        <button key={t.id} className={'tab' + (active === t.id ? ' is-active' : '')} onClick={() => onChange(t.id)}>
          {t.icon && <i className={'bi ' + t.icon}></i>}{t.label}{t.count != null && <span className="badge badge-neutral" style={{ marginLeft:2 }}>{t.count}</span>}
        </button>
      ))}
    </div>
  );
}
function Segmented({ options, value, onChange }) {
  return (
    <div className="seg">
      {options.map(o => (
        <button key={o.value} className={value === o.value ? 'is-active' : ''} onClick={() => onChange(o.value)}>{o.label}</button>
      ))}
    </div>
  );
}

/* ---------- misc ---------- */
function Kpi({ label, value, icon, delta, deltaDir }) {
  return (
    <div className="kpi">
      <div className="k-label">{icon && <i className={'bi ' + icon}></i>}{label}</div>
      <div className="k-val">{value}</div>
      {delta && <div className={'k-delta ' + (deltaDir || 'up')}><i className={'bi ' + (deltaDir === 'down' ? 'bi-arrow-down-right' : 'bi-arrow-up-right')}></i>{delta}</div>}
    </div>
  );
}
function EmptyState({ icon = 'bi-inbox', text }) {
  return <div className="empty"><i className={'bi ' + icon}></i><div>{text}</div></div>;
}
function StatusBadge({ status }) {
  const map = { active:'badge-success', prospect:'badge-warning', inactive:'badge-neutral' };
  const { t } = useLang();
  return <span className={'badge ' + (map[status] || 'badge-neutral')}><i className="dot"></i>{t('st.' + status)}</span>;
}
function DistribBars({ rows, max }) {
  const m = max || Math.max(...rows.map(r => r.value), 1);
  return (
    <div className="distrib">
      {rows.map(r => (
        <div key={r.label} className="distrib-row">
          <span className="truncate" title={r.label}>{r.label}</span>
          <span className="distrib-bar"><i style={{ width:(r.value / m * 100) + '%', background:r.color || 'var(--primary)' }}></i></span>
          <span className="num muted">{r.value}</span>
        </div>
      ))}
    </div>
  );
}

Object.assign(window, {
  useOutside, usePersist, ToastProvider, useToast, Avatar, PlaceholderImg,
  Popover, Modal, Field, ChipInput, Tabs, Segmented, Kpi, EmptyState, StatusBadge, DistribBars,
});
