// ui.jsx — theme + shared UI primitives for PsyFit

const { createContext, useContext } = React;
const ThemeContext = createContext(null);
const useTheme = () => useContext(ThemeContext);

// Accent palette options (color + readable ink color on top of it)
const ACCENTS = [
  { c: '#C8FF2E', ink: '#0A0B0D' }, // volt lime
  { c: '#FF6A2B', ink: '#140600' }, // electric orange
  { c: '#36A6FF', ink: '#04101F' }, // electric blue
  { c: '#FF407A', ink: '#190008' }, // hot magenta
];

const FONT_SETS = {
  Anton:  { d: '"Anton", sans-serif',      b: '"Barlow", sans-serif' },
  Bebas:  { d: '"Bebas Neue", sans-serif', b: '"Saira", sans-serif' },
  Oswald: { d: '"Oswald", sans-serif',     b: '"Manrope", sans-serif' },
};

// Resolve a full colors object from tweak state
function makeColors(t) {
  const acc = ACCENTS.find(a => a.c.toLowerCase() === String(t.accent).toLowerCase()) || ACCENTS[0];
  const fonts = FONT_SETS[t.font] || FONT_SETS.Anton;
  const dark = t.dark;
  return {
    accent: acc.c,
    accentInk: acc.ink,
    bg:       dark ? '#0A0B0D' : '#F3F4F1',
    surface:  dark ? '#141619' : '#FFFFFF',
    surface2: dark ? '#1D2025' : '#ECEDE9',
    surface3: dark ? '#23262C' : '#E2E3DE',
    border:   dark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.09)',
    text:     dark ? '#F4F5F7' : '#15171B',
    muted:    dark ? '#9298A1' : '#6B7077',
    dim:      dark ? '#5A5F68' : '#9AA0A6',
    danger:   '#FF4D4D',
    good:     acc.c,
    radius:   t.radius,
    radiusSm: Math.max(6, Math.round(t.radius * 0.55)),
    fontD: fonts.d,
    fontB: fonts.b,
    imagery: t.imagery,
    dark,
  };
}

// CSS custom-properties to drop on the app root
function cssVars(c) {
  return {
    '--accent': c.accent, '--accent-ink': c.accentInk,
    '--bg': c.bg, '--surface': c.surface, '--surface-2': c.surface2, '--surface-3': c.surface3,
    '--border': c.border, '--text': c.text, '--muted': c.muted, '--dim': c.dim,
    '--danger': c.danger, '--good': c.good,
    '--radius': c.radius + 'px', '--radius-sm': c.radiusSm + 'px',
    '--font-display': c.fontD, '--font-body': c.fontB,
  };
}

// ── Units (lb / kg) ──────────────────────────────────────────
const LB_PER_KG = 2.2046226218;
function makeUnit(unit) {
  const kg = unit === 'kg';
  return {
    unit: kg ? 'kg' : 'lb',
    wtLabel: kg ? 'kg' : 'lb',
    toDisp: (lb) => kg ? Math.round((lb / LB_PER_KG) * 2) / 2 : Math.round(lb),
    toLb:   (d) => kg ? Math.round(d * LB_PER_KG) : Math.round(d),
    wtStep: kg ? 2.5 : 5,
    wtPresets: kg ? [20, 40, 60, 80, 100] : [45, 95, 135, 185, 225],
    abbrWt: (lb) => {
      const n = kg ? lb / LB_PER_KG : lb;
      if (n >= 1e6) return (n / 1e6).toFixed(2).replace(/\.?0+$/, '') + 'M';
      if (n >= 1e3) return Math.round(n / 1e3) + 'k';
      return '' + Math.round(n);
    },
  };
}

// ── Photo store (localStorage data-URLs — works on the deployed PWA) ──
const PHOTO_PREFIX = 'psyfit:photo:';
function loadPhoto(id) { try { return localStorage.getItem(PHOTO_PREFIX + id) || null; } catch (e) { return null; } }
function savePhoto(id, dataUrl) {
  try { if (dataUrl) localStorage.setItem(PHOTO_PREFIX + id, dataUrl); else localStorage.removeItem(PHOTO_PREFIX + id); } catch (e) {}
  window.dispatchEvent(new CustomEvent('psyfit-photo', { detail: { id } }));
}
function allPhotos() {
  const out = {};
  try { for (let i = 0; i < localStorage.length; i++) { const k = localStorage.key(i); if (k && k.startsWith(PHOTO_PREFIX)) out[k.slice(PHOTO_PREFIX.length)] = localStorage.getItem(k); } } catch (e) {}
  return out;
}
async function fileToDataUrl(file, maxDim) {
  const bitmap = await createImageBitmap(file);
  try {
    const scale = Math.min(1, maxDim / Math.max(bitmap.width, bitmap.height));
    const w = Math.max(1, Math.round(bitmap.width * scale));
    const h = Math.max(1, Math.round(bitmap.height * scale));
    const canvas = document.createElement('canvas');
    canvas.width = w; canvas.height = h;
    canvas.getContext('2d').drawImage(bitmap, 0, 0, w, h);
    return canvas.toDataURL('image/webp', 0.85);
  } finally { bitmap.close && bitmap.close(); }
}

// Tap-to-pick photo. interactive=false → display-only (e.g. nav avatar).
function AppPhoto({ id, radius = 0, shape = 'rounded', placeholder = 'Add photo', placeholderIcon = 'dumbbell',
  maxDim = 1400, interactive = true, onClick, overlay, style = {} }) {
  const [url, setUrl] = React.useState(() => loadPhoto(id));
  const inputRef = React.useRef(null);
  React.useEffect(() => {
    const h = (e) => { if (!e.detail || e.detail.id === id) setUrl(loadPhoto(id)); };
    window.addEventListener('psyfit-photo', h);
    setUrl(loadPhoto(id));
    return () => window.removeEventListener('psyfit-photo', h);
  }, [id]);
  const radiusCss = shape === 'circle' ? '50%' : (radius || 0) + 'px';
  const handleClick = (e) => {
    if (onClick) return onClick(e);
    if (interactive && inputRef.current) inputRef.current.click();
  };
  const onFile = async (e) => {
    const f = e.target.files && e.target.files[0];
    if (f) { try { const d = await fileToDataUrl(f, maxDim); savePhoto(id, d); } catch (err) {} }
    e.target.value = '';
  };
  return (
    <div onClick={handleClick} style={{ position: 'relative', overflow: 'hidden', borderRadius: radiusCss,
      background: 'var(--surface-2)', cursor: (interactive || onClick) ? 'pointer' : 'default', ...style }}>
      {url ? (
        <img src={url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
      ) : (
        <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center',
          justifyContent: 'center', gap: 7, color: 'var(--dim)' }}>
          <Icon name={placeholderIcon} size={26} />
          {placeholder ? <span style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, fontWeight: 600, textAlign: 'center', padding: '0 12px', lineHeight: 1.25 }}>{placeholder}</span> : null}
        </div>
      )}
      {overlay}
      {interactive && <input ref={inputRef} type="file" accept="image/*" onChange={onFile} style={{ display: 'none' }} />}
    </div>
  );
}

// ── Primitives ───────────────────────────────────────────────
function Card({ children, style = {}, onClick, pad = 16, ...rest }) {
  return (
    <div onClick={onClick} {...rest} style={{
      background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 'var(--radius)', padding: pad,
      cursor: onClick ? 'pointer' : 'default', ...style,
    }}>{children}</div>
  );
}

function Eyebrow({ children, style = {} }) {
  return <div style={{ fontFamily: 'var(--font-body)', fontSize: 11, fontWeight: 700,
    letterSpacing: 1.6, textTransform: 'uppercase', color: 'var(--muted)', ...style }}>{children}</div>;
}

function Display({ children, size = 34, style = {} }) {
  return <div style={{ fontFamily: 'var(--font-display)', fontWeight: 400, fontSize: size,
    lineHeight: 0.95, letterSpacing: 0.3, color: 'var(--text)', textTransform: 'uppercase', ...style }}>{children}</div>;
}

function Chip({ children, active, onClick, style = {} }) {
  return (
    <button onClick={onClick} style={{
      fontFamily: 'var(--font-body)', fontSize: 12.5, fontWeight: 600, letterSpacing: 0.2,
      padding: '7px 13px', borderRadius: 999, whiteSpace: 'nowrap', cursor: 'pointer',
      border: '1px solid ' + (active ? 'transparent' : 'var(--border)'),
      background: active ? 'var(--accent)' : 'transparent',
      color: active ? 'var(--accent-ink)' : 'var(--muted)',
      transition: 'all .15s', ...style,
    }}>{children}</button>
  );
}

function AccentButton({ children, onClick, style = {}, icon }) {
  return (
    <button onClick={onClick} style={{
      display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
      fontFamily: 'var(--font-display)', fontSize: 17, letterSpacing: 0.5, textTransform: 'uppercase',
      background: 'var(--accent)', color: 'var(--accent-ink)', border: 'none',
      borderRadius: 'var(--radius-sm)', padding: '15px 20px', width: '100%', cursor: 'pointer',
      boxShadow: '0 6px 20px -6px var(--accent)', transition: 'transform .1s', ...style,
    }} onMouseDown={e => e.currentTarget.style.transform = 'scale(.98)'}
       onMouseUp={e => e.currentTarget.style.transform = 'scale(1)'}
       onMouseLeave={e => e.currentTarget.style.transform = 'scale(1)'}>
      {icon}{children}
    </button>
  );
}

function IconBtn({ name, onClick, size = 20, active, style = {} }) {
  return (
    <button onClick={onClick} style={{
      width: 40, height: 40, borderRadius: 999, display: 'flex', alignItems: 'center', justifyContent: 'center',
      background: active ? 'var(--accent)' : 'var(--surface-2)', color: active ? 'var(--accent-ink)' : 'var(--text)',
      border: '1px solid var(--border)', cursor: 'pointer', flexShrink: 0, ...style,
    }}>
      <Icon name={name} size={size} />
    </button>
  );
}

// Screen header
function ScreenHeader({ eyebrow, title, right }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 18 }}>
      <div>
        {eyebrow && <Eyebrow style={{ marginBottom: 6 }}>{eyebrow}</Eyebrow>}
        <Display size={36}>{title}</Display>
      </div>
      {right}
    </div>
  );
}

// Hero image area — image-slot when imagery on, gradient panel otherwise
function HeroSlot({ id, height = 240, radius, placeholder = 'Drop a photo', children, scrim = true, mask = 'rounded' }) {
  const c = useTheme();
  const rad = radius != null ? radius : c.radius;
  return (
    <div style={{ position: 'relative', width: '100%', height, borderRadius: rad, overflow: 'hidden',
      background: c.surface2, border: '1px solid var(--border)' }}>
      {c.imagery ? (
        <AppPhoto
          id={id}
          shape={mask === 'circle' ? 'circle' : 'rounded'}
          radius={rad}
          placeholder={placeholder}
          maxDim={1400}
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}
        />
      ) : (
        <div style={{ position: 'absolute', inset: 0,
          background: `radial-gradient(120% 90% at 80% 0%, ${c.accent}22, transparent 60%), repeating-linear-gradient(135deg, ${c.surface2}, ${c.surface2} 11px, ${c.surface3} 11px, ${c.surface3} 22px)` }}>
          <div style={{ position: 'absolute', right: 16, top: 16, color: c.accent, opacity: 0.9 }}>
            <Icon name="dumbbell" size={40} />
          </div>
        </div>
      )}
      {scrim && (
        <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none',
          background: 'linear-gradient(0deg, rgba(0,0,0,0.78) 0%, rgba(0,0,0,0.18) 45%, rgba(0,0,0,0) 70%)' }} />
      )}
      <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>{children}</div>
    </div>
  );
}

Object.assign(window, {
  ThemeContext, useTheme, ACCENTS, FONT_SETS, makeColors, cssVars, makeUnit,
  loadPhoto, savePhoto, allPhotos, fileToDataUrl, AppPhoto,
  Card, Eyebrow, Display, Chip, AccentButton, IconBtn, ScreenHeader, HeroSlot,
});
