// ============================================================
// UI — primitives, icons, formatters, theme context.
// ============================================================
const { useState, useEffect, useRef, createContext, useContext, useCallback } = React;

// ---------- formatters ----------
const fmtUSD = (n, sign = true) => {
  const s = n < 0 ? '−' : sign ? '+' : '';
  return s + '$' + Math.abs(Math.round(n)).toLocaleString('en-US');
};
const fmtNum = (n) => Math.round(n).toLocaleString('en-US');
const pnlClass = (n) => (n >= 0 ? 'pos' : 'neg');

const cjNow = () => new Date(window.CJData?.NOW ?? Date.now());

const _loc = () => (window.CJI18n ? window.CJI18n.locale : 'en-US');
const _tr = (k) => (window.CJI18n ? window.CJI18n.t(k) : k);
function relTime(ts) {
  const d = new Date(ts);
  const now = cjNow();
  const sameDay = d.toDateString() === now.toDateString();
  const yest = new Date(now); yest.setDate(now.getDate() - 1);
  const isYest = d.toDateString() === yest.toDateString();
  const time = d.toLocaleTimeString(_loc(), { hour: '2-digit', minute: '2-digit', hour12: false });
  if (sameDay) return _tr('date.today') + ' · ' + time;
  if (isYest) return _tr('date.yesterday') + ' · ' + time;
  return d.toLocaleDateString(_loc(), { month: 'short', day: '2-digit' }) + ' · ' + time;
}
const dayKey = (ts) => {
  const d = new Date(ts), now = cjNow();
  if (d.toDateString() === now.toDateString()) return _tr('date.today');
  const y = new Date(now); y.setDate(now.getDate() - 1);
  if (d.toDateString() === y.toDateString()) return _tr('date.yesterday');
  return d.toLocaleDateString(_loc(), { weekday: 'long', month: 'short', day: 'numeric' });
};

// ---------- theme ----------
const ThemeCtx = createContext(null);
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState(() => localStorage.getItem('cj-theme') || 'dark');
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('cj-theme', theme);
  }, [theme]);
  const toggle = useCallback(() => setTheme((t) => (t === 'dark' ? 'light' : 'dark')), []);
  return <ThemeCtx.Provider value={{ theme, toggle, setTheme }}>{children}</ThemeCtx.Provider>;
}
const useTheme = () => useContext(ThemeCtx);

// ---------- icons (stroke, 1.6, currentColor) ----------
const Ico = {
  ledger: 'M4 4h16v16H4zM4 9h16M9 4v16',
  chart: 'M4 19V5M4 19h16M8 16v-5M12 16V8M16 16v-8M20 16v-3',
  gear: 'M12 15a3 3 0 100-6 3 3 0 000 6zM19 12a7 7 0 00-.1-1l2-1.5-2-3.4-2.3.9a7 7 0 00-1.7-1l-.3-2.5h-4l-.3 2.5a7 7 0 00-1.7 1l-2.3-.9-2 3.4L4.1 11a7 7 0 000 2l-2 1.5 2 3.4 2.3-.9a7 7 0 001.7 1l.3 2.5h4l.3-2.5a7 7 0 001.7-1l2.3.9 2-3.4-2-1.5a7 7 0 00.1-1z',
  plus: 'M12 5v14M5 12h14',
  arrowR: 'M5 12h14M13 6l6 6-6 6',
  arrowL: 'M19 12H5M11 18l-6-6 6-6',
  up: 'M12 19V5M6 11l6-6 6 6',
  down: 'M12 5v14M18 13l-6 6-6-6',
  check: 'M5 12.5l4.2 4.5L19 7',
  x: 'M6 6l12 12M18 6L6 18',
  sun: 'M12 17a5 5 0 100-10 5 5 0 000 10zM12 1v3M12 20v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M1 12h3M20 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1',
  moon: 'M21 12.8A9 9 0 1111.2 3 7 7 0 0021 12.8z',
  upload: 'M12 16V4M7 9l5-5 5 5M5 16v3a1 1 0 001 1h12a1 1 0 001-1v-3',
  share: 'M16 6l-4-4-4 4M12 2v13M5 12v7a1 1 0 001 1h12a1 1 0 001-1v-7',
  download: 'M12 4v12M7 11l5 5 5-5M5 20h14',
  spark: 'M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8z',
  dot: 'M12 12h.01',
  grip: 'M9 6h.01M15 6h.01M9 12h.01M15 12h.01M9 18h.01M15 18h.01',
};
function Icon({ d, size = 16, sw = 1.6, fill = 'none', style }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke="currentColor"
      strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0, ...style }}>
      <path d={Ico[d] || d} />
    </svg>
  );
}

// ---------- buttons ----------
function Btn({ kind = 'primary', size = 'md', icon, iconR, children, style, ...p }) {
  return (
    <button {...p} className={'btn btn-' + kind + ' btn-' + size + (p.className ? ' ' + p.className : '')} style={style}>
      {icon && <Icon d={icon} size={size === 'sm' ? 14 : 16} />}
      {children}
      {iconR && <Icon d={iconR} size={size === 'sm' ? 14 : 16} />}
    </button>
  );
}

// ---------- small marks ----------
function DirTag({ dir }) {
  const long = dir === 'Long';
  return (
    <span className={'dirtag ' + (long ? 'is-long' : 'is-short')}>
      <Icon d={long ? 'up' : 'down'} size={11} sw={2.2} />
      {dir}
    </span>
  );
}

function ConfChip({ children, on, dim, onClick, big }) {
  return (
    <button type="button" onClick={onClick}
      className={'cchip' + (on ? ' on' : '') + (dim ? ' dim' : '') + (big ? ' big' : '') + (onClick ? ' click' : '')}>
      {children}
    </button>
  );
}

// threshold meter pip row
function ThresholdPips({ count, threshold, max = 5 }) {
  const n = Math.min(max, Math.max(count, threshold));
  return (
    <span className="pips" title={count + ' confluences · threshold ' + threshold}>
      {Array.from({ length: n }).map((_, i) => (
        <span key={i} className={'pip' + (i < count ? ' fill' : '') + (i + 1 === threshold ? ' thr' : '')} />
      ))}
    </span>
  );
}

// ---------- i18n helpers ----------
// t() reads the global dict; useLang() re-renders subscribers when the
// language changes (CJI18n.set dispatches a 'cj-lang' event).
const t = (k, v) => (window.CJI18n ? window.CJI18n.t(k, v) : k);
function useLang() {
  const [, force] = useState(0);
  useEffect(() => {
    const h = () => force((x) => x + 1);
    window.addEventListener('cj-lang', h);
    return () => window.removeEventListener('cj-lang', h);
  }, []);
  return window.CJI18n ? window.CJI18n.lang : 'en';
}
function LangToggle({ className }) {
  const lang = useLang();
  return (
    <div className={'lang-toggle' + (className ? ' ' + className : '')}>
      <button className={lang === 'en' ? 'on' : ''} onClick={() => window.CJI18n.set('en')}>EN</button>
      <button className={lang === 'nl' ? 'on' : ''} onClick={() => window.CJI18n.set('nl')}>NL</button>
    </div>
  );
}

window.CJUI = {
  fmtUSD, fmtNum, pnlClass, relTime, dayKey,
  ThemeProvider, useTheme, Icon, Ico, Btn, DirTag, ConfChip, ThresholdPips,
  t, useLang, LangToggle,
};
window.React_hooks = { useState, useEffect, useRef, createContext, useContext, useCallback };
